diff --git a/client/client_test.go b/client/client_test.go index c364d94f671e..04263ce45e84 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -1773,11 +1773,11 @@ func testOCILayoutSource(t *testing.T, sb integration.Sandbox) { require.NoError(t, err) // reference the OCI Layout in a build - // note that the key does not need to be the directory name, just something unique. - // since we are doing just one build with one remote here, we can give it any old ID, - // even something really imaginative, like "one" - csID := "one" - st = llb.OCILayout(csID, digest) + // note that the key does not need to be the directory name, just something + // unique. since we are doing just one build with one remote here, we can + // give it any ID + csID := "my-content-store" + st = llb.OCILayout(fmt.Sprintf("not/real@%s", digest), llb.OCIStore("", csID)) def, err = st.Marshal(context.TODO()) require.NoError(t, err) @@ -1902,12 +1902,7 @@ func testOCILayoutPlatformSource(t *testing.T, sb integration.Sandbox) { store, err := local.NewStore(dir) require.NoError(t, err) - - // reference the OCI Layout in a build - // note that the key does not need to be the directory name, just something unique. - // since we are doing just one build with one remote here, we can give it any old ID, - // even something really imaginative, like "one" - csID := "one" + csID := "my-content-store" destDir := t.TempDir() @@ -1917,7 +1912,7 @@ func testOCILayoutPlatformSource(t *testing.T, sb integration.Sandbox) { Platforms: make([]exptypes.Platform, len(platformsToTest)), } for i, platform := range platformsToTest { - st := llb.OCILayout(csID, digest) + st := llb.OCILayout(fmt.Sprintf("not/real@%s", digest), llb.OCIStore("", csID)) def, err := st.Marshal(ctx, llb.Platform(platforms.MustParse(platform))) if err != nil { diff --git a/client/llb/resolver.go b/client/llb/resolver.go index 84eaa6bd7757..b3b9cdf751c7 100644 --- a/client/llb/resolver.go +++ b/client/llb/resolver.go @@ -42,9 +42,16 @@ const ( ) type ResolveImageConfigOpt struct { - Platform *ocispecs.Platform - ResolveMode string - LogName string - ResolverType // default is ResolverTypeRegistry - SessionID string + ResolverType + + Platform *ocispecs.Platform + ResolveMode string + LogName string + + Store ResolveImageConfigOptStore +} + +type ResolveImageConfigOptStore struct { + SessionID string + StoreID string } diff --git a/client/llb/source.go b/client/llb/source.go index e0b4363483c7..27c8c1b617f2 100644 --- a/client/llb/source.go +++ b/client/llb/source.go @@ -4,7 +4,6 @@ import ( "context" _ "crypto/sha256" // for opencontainers/go-digest "encoding/json" - "fmt" "os" "strconv" "strings" @@ -455,7 +454,7 @@ func Differ(t DiffType, required bool) LocalOption { }) } -func OCILayout(store string, digest digest.Digest, opts ...OCILayoutOption) State { +func OCILayout(ref string, opts ...OCILayoutOption) State { gi := &OCILayoutInfo{} for _, o := range opts { @@ -464,17 +463,17 @@ func OCILayout(store string, digest digest.Digest, opts ...OCILayoutOption) Stat attrs := map[string]string{} if gi.sessionID != "" { attrs[pb.AttrOCILayoutSessionID] = gi.sessionID - addCap(&gi.Constraints, pb.CapSourceOCILayoutSessionID) } - - if ll := gi.layerLimit; ll != nil { - attrs[pb.AttrOCILayoutLayerLimit] = strconv.FormatInt(int64(*ll), 10) - addCap(&gi.Constraints, pb.CapSourceOCILayoutLayerLimit) + if gi.storeID != "" { + attrs[pb.AttrOCILayoutStoreID] = gi.storeID + } + if gi.layerLimit != nil { + attrs[pb.AttrOCILayoutLayerLimit] = strconv.FormatInt(int64(*gi.layerLimit), 10) } addCap(&gi.Constraints, pb.CapSourceOCILayout) - source := NewSource(fmt.Sprintf("oci-layout://%s@%s", store, digest), attrs, gi.Constraints) + source := NewSource("oci-layout://"+ref, attrs, gi.Constraints) return NewState(source.Output()) } @@ -488,9 +487,10 @@ func (fn ociLayoutOptionFunc) SetOCILayoutOption(li *OCILayoutInfo) { fn(li) } -func OCISessionID(id string) OCILayoutOption { +func OCIStore(sessionID string, storeID string) OCILayoutOption { return ociLayoutOptionFunc(func(oi *OCILayoutInfo) { - oi.sessionID = id + oi.sessionID = sessionID + oi.storeID = storeID }) } @@ -503,6 +503,7 @@ func OCILayerLimit(limit int) OCILayoutOption { type OCILayoutInfo struct { constraintsWrapper sessionID string + storeID string layerLimit *int } diff --git a/frontend/dockerfile/builder/build.go b/frontend/dockerfile/builder/build.go index d1be3cedf7bc..8c429efa46e9 100644 --- a/frontend/dockerfile/builder/build.go +++ b/frontend/dockerfile/builder/build.go @@ -873,8 +873,8 @@ func contextByNameFunc(c client.Client, sessionID string) func(context.Context, p = &pp } if p != nil { - name := name + "::" + platforms.Format(platforms.Normalize(*p)) - st, img, err := contextByName(ctx, c, sessionID, name, p, resolveMode) + pname := name + "::" + platforms.Format(platforms.Normalize(*p)) + st, img, err := contextByName(ctx, c, sessionID, name, pname, p, resolveMode) if err != nil { return nil, nil, err } @@ -882,20 +882,20 @@ func contextByNameFunc(c client.Client, sessionID string) func(context.Context, return st, img, nil } } - return contextByName(ctx, c, sessionID, name, p, resolveMode) + return contextByName(ctx, c, sessionID, name, name, p, resolveMode) } } -func contextByName(ctx context.Context, c client.Client, sessionID, name string, platform *ocispecs.Platform, resolveMode string) (*llb.State, *dockerfile2llb.Image, error) { +func contextByName(ctx context.Context, c client.Client, sessionID, name string, pname string, platform *ocispecs.Platform, resolveMode string) (*llb.State, *dockerfile2llb.Image, error) { opts := c.BuildOpts().Opts - v, ok := opts[contextPrefix+name] + v, ok := opts[contextPrefix+pname] if !ok { return nil, nil, nil } vv := strings.SplitN(v, ":", 2) if len(vv) != 2 { - return nil, nil, errors.Errorf("invalid context specifier %s for %s", v, name) + return nil, nil, errors.Errorf("invalid context specifier %s for %s", v, pname) } // allow git@ without protocol for SSH URLs for backwards compatibility if strings.HasPrefix(vv[0], "git@") { @@ -910,7 +910,7 @@ func contextByName(ctx context.Context, c client.Client, sessionID, name string, } imgOpt := []llb.ImageOption{ - llb.WithCustomName("[context " + name + "] " + ref), + llb.WithCustomName("[context " + pname + "] " + ref), } if platform != nil { imgOpt = append(imgOpt, llb.Platform(*platform)) @@ -926,9 +926,8 @@ func contextByName(ctx context.Context, c client.Client, sessionID, name string, _, data, err := c.ResolveImageConfig(ctx, named.String(), llb.ResolveImageConfigOpt{ Platform: platform, ResolveMode: resolveMode, - LogName: fmt.Sprintf("[context %s] load metadata for %s", name, ref), + LogName: fmt.Sprintf("[context %s] load metadata for %s", pname, ref), ResolverType: llb.ResolverTypeRegistry, - SessionID: sessionID, }) if err != nil { return nil, nil, err @@ -955,7 +954,7 @@ func contextByName(ctx context.Context, c client.Client, sessionID, name string, case "http", "https": st, ok := detectGitContext(v, true) if !ok { - httpst := llb.HTTP(v, llb.WithCustomName("[context "+name+"] "+v)) + httpst := llb.HTTP(v, llb.WithCustomName("[context "+pname+"] "+v)) st = &httpst } return st, nil, nil @@ -969,25 +968,31 @@ func contextByName(ctx context.Context, c client.Client, sessionID, name string, if !ok { return nil, nil, errors.Errorf("oci-layout reference %q has no name", ref.String()) } - if reference.Domain(named) != "" { - return nil, nil, errors.Errorf("oci-layout reference %q has domain", ref.String()) + dgstd, ok := named.(reference.Digested) + if !ok { + return nil, nil, errors.Errorf("oci-layout reference %q has no digest", named.String()) } - if strings.Contains(reference.Path(named), "/") { - return nil, nil, errors.Errorf("oci-layout reference %q name is multi-part", ref.String()) + + // for the dummy ref primarily used in log messages, we can use the + // original name, since the store key may not be significant + dummyRef, err := reference.ParseNormalizedNamed(name) + if err != nil { + return nil, nil, errors.Wrapf(err, "could not parse oci-layout reference %q", name) } - digested, ok := ref.(reference.Digested) - if !ok { - return nil, nil, errors.Errorf("oci-layout reference %q does not have digest", ref.String()) + dummyRef, err = reference.WithDigest(dummyRef, dgstd.Digest()) + if err != nil { + return nil, nil, errors.Wrapf(err, "could not wrap %q with digest", name) } - // We use store id as the host here, the image name will be ignored - // (since image lookup is not currently supported) - id := fmt.Sprintf("%s/image@%s", named.Name(), digested.Digest()) - _, data, err := c.ResolveImageConfig(ctx, id, llb.ResolveImageConfigOpt{ + _, data, err := c.ResolveImageConfig(ctx, dummyRef.String(), llb.ResolveImageConfigOpt{ Platform: platform, ResolveMode: resolveMode, - LogName: fmt.Sprintf("[context %s] load metadata for %s", name, ref), + LogName: fmt.Sprintf("[context %s] load metadata for %s", pname, dummyRef.String()), ResolverType: llb.ResolverTypeOCILayout, + Store: llb.ResolveImageConfigOptStore{ + SessionID: sessionID, + StoreID: named.Name(), + }, }) if err != nil { return nil, nil, err @@ -999,15 +1004,14 @@ func contextByName(ctx context.Context, c client.Client, sessionID, name string, } ociOpt := []llb.OCILayoutOption{ - llb.WithCustomName("[context " + name + "] OCI load from client"), - llb.OCISessionID(c.BuildOpts().SessionID), + llb.WithCustomName("[context " + pname + "] OCI load from client"), + llb.OCIStore(c.BuildOpts().SessionID, named.Name()), } if platform != nil { ociOpt = append(ociOpt, llb.Platform(*platform)) } st := llb.OCILayout( - named.Name(), - digested.Digest(), + dummyRef.String(), ociOpt..., ) st, err = st.WithImageConfig(data) @@ -1019,8 +1023,8 @@ func contextByName(ctx context.Context, c client.Client, sessionID, name string, st := llb.Local(vv[1], llb.SessionID(c.BuildOpts().SessionID), llb.FollowPaths([]string{dockerignoreFilename}), - llb.SharedKeyHint("context:"+name+"-"+dockerignoreFilename), - llb.WithCustomName("[context "+name+"] load "+dockerignoreFilename), + llb.SharedKeyHint("context:"+pname+"-"+dockerignoreFilename), + llb.WithCustomName("[context "+pname+"] load "+dockerignoreFilename), llb.Differ(llb.DiffNone, false), ) def, err := st.Marshal(ctx) @@ -1049,9 +1053,9 @@ func contextByName(ctx context.Context, c client.Client, sessionID, name string, } } st = llb.Local(vv[1], - llb.WithCustomName("[context "+name+"] load from client"), + llb.WithCustomName("[context "+pname+"] load from client"), llb.SessionID(c.BuildOpts().SessionID), - llb.SharedKeyHint("context:"+name), + llb.SharedKeyHint("context:"+pname), llb.ExcludePatterns(excludes), ) return &st, nil, nil @@ -1062,7 +1066,7 @@ func contextByName(ctx context.Context, c client.Client, sessionID, name string, } st, ok := inputs[vv[1]] if !ok { - return nil, nil, errors.Errorf("invalid input %s for %s", vv[1], name) + return nil, nil, errors.Errorf("invalid input %s for %s", vv[1], pname) } md, ok := opts[inputMetadataPrefix+vv[1]] if ok { @@ -1077,14 +1081,14 @@ func contextByName(ctx context.Context, c client.Client, sessionID, name string, return nil, nil, err } if err := json.Unmarshal(dtic, &img); err != nil { - return nil, nil, errors.Wrapf(err, "failed to parse image config for %s", name) + return nil, nil, errors.Wrapf(err, "failed to parse image config for %s", pname) } } return &st, img, nil } return &st, nil, nil default: - return nil, nil, errors.Errorf("unsupported context source %s for %s", vv[0], name) + return nil, nil, errors.Errorf("unsupported context source %s for %s", vv[0], pname) } } diff --git a/frontend/gateway/gateway.go b/frontend/gateway/gateway.go index b96015550a94..a9695307752f 100644 --- a/frontend/gateway/gateway.go +++ b/frontend/gateway/gateway.go @@ -541,10 +541,14 @@ func (lbf *llbBridgeForwarder) ResolveImageConfig(ctx context.Context, req *pb.R } } dgst, dt, err := lbf.llbBridge.ResolveImageConfig(ctx, req.Ref, llb.ResolveImageConfigOpt{ + ResolverType: llb.ResolverType(req.ResolverType), Platform: platform, ResolveMode: req.ResolveMode, LogName: req.LogName, - ResolverType: llb.ResolverType(req.ResolverType), + Store: llb.ResolveImageConfigOptStore{ + SessionID: req.SessionID, + StoreID: req.StoreID, + }, }) if err != nil { return nil, err diff --git a/frontend/gateway/grpcclient/client.go b/frontend/gateway/grpcclient/client.go index 70064e5cf47f..b8b2414f80a2 100644 --- a/frontend/gateway/grpcclient/client.go +++ b/frontend/gateway/grpcclient/client.go @@ -488,7 +488,15 @@ func (c *grpcClient) ResolveImageConfig(ctx context.Context, ref string, opt llb OSFeatures: platform.OSFeatures, } } - resp, err := c.client.ResolveImageConfig(ctx, &pb.ResolveImageConfigRequest{Ref: ref, Platform: p, ResolveMode: opt.ResolveMode, LogName: opt.LogName, ResolverType: int32(opt.ResolverType), SessionID: opt.SessionID}) + resp, err := c.client.ResolveImageConfig(ctx, &pb.ResolveImageConfigRequest{ + ResolverType: int32(opt.ResolverType), + Ref: ref, + Platform: p, + ResolveMode: opt.ResolveMode, + LogName: opt.LogName, + SessionID: opt.Store.SessionID, + StoreID: opt.Store.StoreID, + }) if err != nil { return "", nil, err } diff --git a/frontend/gateway/pb/gateway.pb.go b/frontend/gateway/pb/gateway.pb.go index 58701c874c62..7cecd77bf7c7 100644 --- a/frontend/gateway/pb/gateway.pb.go +++ b/frontend/gateway/pb/gateway.pb.go @@ -741,6 +741,7 @@ type ResolveImageConfigRequest struct { LogName string `protobuf:"bytes,4,opt,name=LogName,proto3" json:"LogName,omitempty"` ResolverType int32 `protobuf:"varint,5,opt,name=ResolverType,proto3" json:"ResolverType,omitempty"` SessionID string `protobuf:"bytes,6,opt,name=SessionID,proto3" json:"SessionID,omitempty"` + StoreID string `protobuf:"bytes,7,opt,name=StoreID,proto3" json:"StoreID,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -821,6 +822,13 @@ func (m *ResolveImageConfigRequest) GetSessionID() string { return "" } +func (m *ResolveImageConfigRequest) GetStoreID() string { + if m != nil { + return m.StoreID + } + return "" +} + type ResolveImageConfigResponse struct { Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=Digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"Digest"` Config []byte `protobuf:"bytes,2,opt,name=Config,proto3" json:"Config,omitempty"` @@ -2610,157 +2618,158 @@ func init() { func init() { proto.RegisterFile("gateway.proto", fileDescriptor_f1a937782ebbded5) } var fileDescriptor_f1a937782ebbded5 = []byte{ - // 2397 bytes of a gzipped FileDescriptorProto + // 2409 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x59, 0xcf, 0x6f, 0x1b, 0xc7, - 0xf5, 0xd7, 0x8a, 0x94, 0x48, 0x3e, 0xfe, 0x10, 0x3d, 0x71, 0xf2, 0x65, 0x16, 0x81, 0x23, 0xaf, - 0x13, 0x45, 0x56, 0x1c, 0xd2, 0x5f, 0xda, 0x81, 0x5c, 0xbb, 0x75, 0x62, 0xfd, 0x82, 0x14, 0x4b, + 0xf5, 0xd7, 0x8a, 0x94, 0x44, 0x3e, 0xfe, 0x10, 0x3d, 0x71, 0xf2, 0x65, 0x16, 0x81, 0x23, 0xaf, + 0x13, 0x45, 0x56, 0x1c, 0xd2, 0x5f, 0xda, 0x81, 0x5c, 0xbb, 0x75, 0x62, 0xfd, 0x82, 0x18, 0x4b, 0x36, 0x3b, 0x72, 0xe1, 0x22, 0x48, 0x81, 0xae, 0xb8, 0x43, 0x7a, 0xeb, 0xd5, 0xee, 0x76, 0x77, 0x68, 0x59, 0xc9, 0xa5, 0xbd, 0x15, 0x39, 0xf5, 0xd4, 0x5b, 0x50, 0xa0, 0x05, 0x7a, 0x6e, 0x2f, - 0xbd, 0xb5, 0xe7, 0x00, 0xbd, 0xf4, 0xd2, 0x4b, 0x0f, 0x41, 0xe1, 0x3f, 0xa2, 0x40, 0x6f, 0xc5, + 0xbd, 0xb5, 0xe7, 0x00, 0xbd, 0xf4, 0xdc, 0x43, 0x50, 0xf8, 0x1f, 0xe8, 0xad, 0x40, 0x6f, 0xc5, 0x9b, 0x99, 0x25, 0x87, 0x3f, 0xb4, 0x24, 0xeb, 0x13, 0x67, 0xde, 0xbc, 0x1f, 0x33, 0xef, 0xcd, - 0x7b, 0xef, 0x33, 0x4b, 0x28, 0x77, 0x6d, 0xce, 0xce, 0xec, 0xf3, 0x7a, 0x18, 0x05, 0x3c, 0x20, - 0x6f, 0x9f, 0x06, 0x27, 0xe7, 0xf5, 0x93, 0x9e, 0xeb, 0x39, 0xcf, 0x5d, 0x5e, 0x7f, 0xf1, 0xff, - 0xf5, 0x4e, 0x14, 0xf8, 0x9c, 0xf9, 0x8e, 0xf9, 0x51, 0xd7, 0xe5, 0xcf, 0x7a, 0x27, 0xf5, 0x76, - 0x70, 0xda, 0xe8, 0x06, 0xdd, 0xa0, 0x21, 0x24, 0x4e, 0x7a, 0x1d, 0x31, 0x13, 0x13, 0x31, 0x92, - 0x9a, 0xcc, 0xe6, 0x28, 0x7b, 0x37, 0x08, 0xba, 0x1e, 0xb3, 0x43, 0x37, 0x56, 0xc3, 0x46, 0x14, - 0xb6, 0x1b, 0x31, 0xb7, 0x79, 0x2f, 0x56, 0x32, 0x37, 0x34, 0x19, 0xdc, 0x48, 0x23, 0xd9, 0x48, - 0x23, 0x0e, 0xbc, 0x17, 0x2c, 0x6a, 0x84, 0x27, 0x8d, 0x20, 0x4c, 0xb8, 0x1b, 0x17, 0x72, 0xdb, - 0xa1, 0xdb, 0xe0, 0xe7, 0x21, 0x8b, 0x1b, 0x67, 0x41, 0xf4, 0x9c, 0x45, 0x4a, 0xe0, 0xd6, 0x85, + 0x7b, 0xef, 0x33, 0x4b, 0x28, 0x75, 0x6d, 0xce, 0xce, 0xec, 0xf3, 0x5a, 0x18, 0x05, 0x3c, 0x20, + 0x6f, 0x9f, 0x06, 0x27, 0xe7, 0xb5, 0x93, 0x9e, 0xeb, 0x39, 0xcf, 0x5d, 0x5e, 0x7b, 0xf1, 0xff, + 0xb5, 0x4e, 0x14, 0xf8, 0x9c, 0xf9, 0x8e, 0xf9, 0x51, 0xd7, 0xe5, 0xcf, 0x7a, 0x27, 0xb5, 0x76, + 0x70, 0x5a, 0xef, 0x06, 0xdd, 0xa0, 0x2e, 0x24, 0x4e, 0x7a, 0x1d, 0x31, 0x13, 0x13, 0x31, 0x92, + 0x9a, 0xcc, 0xc6, 0x28, 0x7b, 0x37, 0x08, 0xba, 0x1e, 0xb3, 0x43, 0x37, 0x56, 0xc3, 0x7a, 0x14, + 0xb6, 0xeb, 0x31, 0xb7, 0x79, 0x2f, 0x56, 0x32, 0x37, 0x34, 0x19, 0xdc, 0x48, 0x3d, 0xd9, 0x48, + 0x3d, 0x0e, 0xbc, 0x17, 0x2c, 0xaa, 0x87, 0x27, 0xf5, 0x20, 0x4c, 0xb8, 0xeb, 0x17, 0x72, 0xdb, + 0xa1, 0x5b, 0xe7, 0xe7, 0x21, 0x8b, 0xeb, 0x67, 0x41, 0xf4, 0x9c, 0x45, 0x4a, 0xe0, 0xd6, 0x85, 0x02, 0x3d, 0xee, 0x7a, 0x28, 0xd5, 0xb6, 0xc3, 0x18, 0x8d, 0xe0, 0xaf, 0x12, 0xd2, 0x8f, 0xcd, - 0x03, 0xdf, 0x8d, 0xb9, 0xeb, 0x76, 0xdd, 0x46, 0x27, 0x16, 0x32, 0xd2, 0x0a, 0x1e, 0x42, 0xb2, - 0x5b, 0x7f, 0xcb, 0xc2, 0x32, 0x65, 0x71, 0xcf, 0xe3, 0x64, 0x0d, 0xca, 0x11, 0xeb, 0xec, 0xb0, - 0x30, 0x62, 0x6d, 0x9b, 0x33, 0xa7, 0x66, 0xac, 0x1a, 0xeb, 0x85, 0xfd, 0x05, 0x3a, 0x4c, 0x26, - 0x3f, 0x82, 0x4a, 0xc4, 0x3a, 0xb1, 0xc6, 0xb8, 0xb8, 0x6a, 0xac, 0x17, 0x9b, 0x1f, 0xd6, 0x2f, - 0x0c, 0x46, 0x9d, 0xb2, 0xce, 0x91, 0x1d, 0x0e, 0x44, 0xf6, 0x17, 0xe8, 0x88, 0x12, 0xd2, 0x84, - 0x4c, 0xc4, 0x3a, 0xb5, 0x8c, 0xd0, 0x75, 0x25, 0x5d, 0xd7, 0xfe, 0x02, 0x45, 0x66, 0xb2, 0x09, - 0x59, 0xd4, 0x52, 0xcb, 0x0a, 0xa1, 0xab, 0x53, 0x37, 0xb0, 0xbf, 0x40, 0x85, 0x00, 0x79, 0x08, - 0xf9, 0x53, 0xc6, 0x6d, 0xc7, 0xe6, 0x76, 0x0d, 0x56, 0x33, 0xeb, 0xc5, 0x66, 0x23, 0x55, 0x18, - 0x1d, 0x54, 0x3f, 0x52, 0x12, 0xbb, 0x3e, 0x8f, 0xce, 0x69, 0x5f, 0x01, 0x79, 0x0a, 0x25, 0x9b, - 0x73, 0x86, 0x5e, 0x75, 0x03, 0x3f, 0xae, 0x95, 0x84, 0xc2, 0x5b, 0xd3, 0x15, 0x3e, 0xd0, 0xa4, - 0xa4, 0xd2, 0x21, 0x45, 0xe6, 0x3d, 0x28, 0x0f, 0xd9, 0x24, 0x55, 0xc8, 0x3c, 0x67, 0xe7, 0x32, - 0x30, 0x14, 0x87, 0xe4, 0x32, 0x2c, 0xbd, 0xb0, 0xbd, 0x1e, 0x13, 0x31, 0x28, 0x51, 0x39, 0xb9, - 0xbb, 0x78, 0xc7, 0x30, 0x9f, 0xc1, 0xa5, 0x31, 0xfd, 0x13, 0x14, 0xfc, 0x40, 0x57, 0x50, 0x6c, - 0x7e, 0x90, 0xb2, 0x6b, 0x5d, 0x9d, 0x66, 0x69, 0x2b, 0x0f, 0xcb, 0x91, 0x38, 0x90, 0xf5, 0x1b, - 0x03, 0xaa, 0xa3, 0xa1, 0x26, 0x07, 0x2a, 0x48, 0x86, 0x70, 0xcb, 0xc7, 0x73, 0xdc, 0x12, 0x24, - 0x28, 0xc7, 0x08, 0x15, 0xe6, 0x26, 0x14, 0xfa, 0xa4, 0x69, 0xce, 0x28, 0x68, 0x5b, 0xb4, 0x36, - 0x21, 0x43, 0x59, 0x87, 0x54, 0x60, 0xd1, 0x55, 0xf7, 0x9a, 0x2e, 0xba, 0x0e, 0x59, 0x85, 0x8c, - 0xc3, 0x3a, 0xea, 0xe8, 0x95, 0x7a, 0x78, 0x52, 0xdf, 0x61, 0x1d, 0xd7, 0x77, 0xf1, 0x88, 0x14, - 0x97, 0xac, 0xdf, 0x19, 0x98, 0x1f, 0xb8, 0x2d, 0xf2, 0xc9, 0xd0, 0x39, 0xa6, 0xdf, 0xf6, 0xb1, - 0xdd, 0x3f, 0x4d, 0xdf, 0xfd, 0xed, 0xe1, 0x48, 0x4c, 0x49, 0x01, 0xfd, 0x74, 0x3f, 0x86, 0x92, - 0x1e, 0x1b, 0xb2, 0x0f, 0x45, 0xed, 0x1e, 0xa9, 0x0d, 0xaf, 0xcd, 0x16, 0x59, 0xaa, 0x8b, 0x5a, - 0x7f, 0xc8, 0x40, 0x51, 0x5b, 0x24, 0xf7, 0x21, 0xfb, 0xdc, 0xf5, 0xa5, 0x0b, 0x2b, 0xcd, 0x8d, - 0xd9, 0x54, 0x3e, 0x74, 0x7d, 0x87, 0x0a, 0x39, 0xd2, 0xd2, 0xf2, 0x6e, 0x51, 0x6c, 0xeb, 0xf6, - 0x6c, 0x3a, 0x2e, 0x4c, 0xbe, 0x9b, 0x73, 0x94, 0x0d, 0x59, 0x34, 0x08, 0x64, 0x43, 0x9b, 0x3f, - 0x13, 0x45, 0xa3, 0x40, 0xc5, 0x98, 0xdc, 0x84, 0x37, 0x5c, 0xff, 0x49, 0xc0, 0x83, 0x56, 0xc4, - 0x1c, 0x17, 0x2f, 0xdf, 0x93, 0xf3, 0x90, 0xd5, 0x96, 0x04, 0xcb, 0xa4, 0x25, 0xd2, 0x82, 0x8a, - 0x24, 0x1f, 0xf7, 0x4e, 0x7e, 0xc6, 0xda, 0x3c, 0xae, 0x2d, 0x8b, 0xf3, 0xac, 0xa7, 0x6c, 0xe1, - 0x40, 0x17, 0xa0, 0x23, 0xf2, 0xaf, 0x95, 0xed, 0xd6, 0x9f, 0x0c, 0x28, 0x0f, 0xa9, 0x27, 0x9f, - 0x0e, 0x85, 0xea, 0xc6, 0xac, 0xdb, 0xd2, 0x82, 0xf5, 0x19, 0x2c, 0x3b, 0x6e, 0x97, 0xc5, 0x5c, - 0x84, 0xaa, 0xb0, 0xd5, 0xfc, 0xf6, 0xbb, 0x77, 0x17, 0xfe, 0xf9, 0xdd, 0xbb, 0x1b, 0x5a, 0x8b, - 0x09, 0x42, 0xe6, 0xb7, 0x03, 0x9f, 0xdb, 0xae, 0xcf, 0x22, 0xec, 0x94, 0x1f, 0x49, 0x91, 0xfa, - 0x8e, 0xf8, 0xa1, 0x4a, 0x03, 0x3a, 0xdd, 0xb7, 0x4f, 0x99, 0x88, 0x53, 0x81, 0x8a, 0xb1, 0xc5, - 0xa1, 0x4c, 0x19, 0xef, 0x45, 0x3e, 0x65, 0x3f, 0xef, 0x21, 0xd3, 0xf7, 0x92, 0x42, 0x22, 0x36, - 0x3d, 0xad, 0xa0, 0x23, 0x23, 0x55, 0x02, 0x64, 0x1d, 0x96, 0x58, 0x14, 0x05, 0x91, 0x4a, 0x1e, - 0x52, 0x97, 0x3d, 0xbb, 0x1e, 0x85, 0xed, 0xfa, 0xb1, 0xe8, 0xd9, 0x54, 0x32, 0x58, 0x55, 0xa8, - 0x24, 0x56, 0xe3, 0x30, 0xf0, 0x63, 0x66, 0xad, 0xa0, 0xeb, 0xc2, 0x1e, 0x8f, 0xd5, 0x3e, 0xac, - 0xbf, 0x1a, 0x50, 0x49, 0x28, 0x92, 0x87, 0x7c, 0x01, 0xc5, 0x41, 0x69, 0x48, 0x6a, 0xc0, 0xdd, - 0x54, 0xa7, 0xea, 0xf2, 0x5a, 0x5d, 0x51, 0x25, 0x41, 0x57, 0x67, 0x3e, 0x82, 0xea, 0x28, 0xc3, - 0x84, 0xe8, 0xbf, 0x37, 0x5c, 0x20, 0x46, 0xeb, 0x95, 0x76, 0x1b, 0xfe, 0x61, 0xc0, 0xdb, 0x94, - 0x09, 0x10, 0x72, 0x70, 0x6a, 0x77, 0xd9, 0x76, 0xe0, 0x77, 0xdc, 0x6e, 0xe2, 0xe6, 0xaa, 0x28, - 0x86, 0x89, 0x66, 0xac, 0x8b, 0xeb, 0x90, 0x6f, 0x79, 0x36, 0xef, 0x04, 0xd1, 0xa9, 0x52, 0x5e, - 0x42, 0xe5, 0x09, 0x8d, 0xf6, 0x57, 0xc9, 0x2a, 0x14, 0x95, 0xe2, 0xa3, 0xc0, 0x49, 0xc2, 0xa9, - 0x93, 0x48, 0x0d, 0x72, 0x87, 0x41, 0xf7, 0x11, 0x06, 0x5b, 0x66, 0x58, 0x32, 0x25, 0x16, 0x94, - 0x14, 0x63, 0xd4, 0xcf, 0xae, 0x25, 0x3a, 0x44, 0x23, 0xef, 0x40, 0xe1, 0x98, 0xc5, 0xb1, 0x1b, - 0xf8, 0x07, 0x3b, 0xb5, 0x65, 0x21, 0x3f, 0x20, 0x58, 0xbf, 0x30, 0xc0, 0x9c, 0x74, 0x2e, 0x15, - 0xa4, 0xcf, 0x60, 0x59, 0x5e, 0x3b, 0x79, 0xb6, 0xff, 0xed, 0xc2, 0xca, 0x5f, 0xf2, 0x16, 0x2c, - 0x4b, 0xed, 0x2a, 0xd7, 0xd4, 0xcc, 0xfa, 0xf3, 0x12, 0x94, 0x8e, 0x71, 0x03, 0x89, 0x37, 0xeb, - 0x00, 0x83, 0x20, 0xa8, 0x8b, 0x3b, 0x1a, 0x1a, 0x8d, 0x83, 0x98, 0x90, 0xdf, 0x53, 0x97, 0x44, - 0xf5, 0xa9, 0xfe, 0x9c, 0x7c, 0x0e, 0xc5, 0x64, 0xfc, 0x38, 0xe4, 0xb5, 0x8c, 0xb8, 0x65, 0x77, - 0x52, 0x6e, 0x99, 0xbe, 0x93, 0xba, 0x26, 0xaa, 0xee, 0x98, 0x46, 0x21, 0x37, 0xe0, 0x92, 0xed, - 0x79, 0xc1, 0x99, 0x4a, 0x1c, 0x91, 0x02, 0x22, 0x04, 0x79, 0x3a, 0xbe, 0x80, 0x05, 0x51, 0x23, - 0x3e, 0x88, 0x22, 0xfb, 0x1c, 0xef, 0xcc, 0xb2, 0xe0, 0x9f, 0xb4, 0x84, 0xb5, 0x69, 0xcf, 0xf5, - 0x6d, 0xaf, 0x06, 0x82, 0x47, 0x4e, 0x30, 0xe6, 0xbb, 0x2f, 0xc3, 0x20, 0xe2, 0x2c, 0x7a, 0xc0, - 0x79, 0x54, 0x2b, 0x0a, 0x67, 0x0e, 0xd1, 0x48, 0x0b, 0x4a, 0xdb, 0x76, 0xfb, 0x19, 0x3b, 0x38, - 0x45, 0x62, 0x82, 0x9f, 0xd2, 0x2a, 0x96, 0x60, 0x7f, 0x1c, 0xea, 0xc0, 0x49, 0xd7, 0x40, 0xda, - 0x50, 0x49, 0x8e, 0x2e, 0xf3, 0xb0, 0x56, 0x16, 0x3a, 0xef, 0xcd, 0xeb, 0x4a, 0x29, 0x2d, 0x4d, - 0x8c, 0xa8, 0xc4, 0x40, 0xee, 0x62, 0xca, 0xd9, 0x9c, 0xd5, 0x2a, 0xe2, 0xcc, 0xfd, 0xb9, 0x79, - 0x1f, 0xaa, 0xa3, 0xd1, 0x98, 0x07, 0xaf, 0x98, 0x3f, 0x84, 0x37, 0x26, 0x6c, 0xe1, 0xb5, 0x6a, - 0xc2, 0x1f, 0x0d, 0xb8, 0x34, 0xe6, 0x37, 0xac, 0xcb, 0x22, 0x17, 0xa5, 0x4a, 0x31, 0x26, 0x47, - 0xb0, 0x84, 0x71, 0x89, 0x55, 0x87, 0xde, 0x9c, 0x27, 0x10, 0x75, 0x21, 0x29, 0x1d, 0x26, 0xb5, - 0x98, 0x77, 0x00, 0x06, 0xc4, 0xb9, 0x50, 0xdb, 0x17, 0x50, 0x56, 0x51, 0x51, 0x09, 0x5e, 0x95, - 0xcd, 0x5e, 0x09, 0x63, 0x33, 0x1f, 0xb4, 0x8c, 0xcc, 0x9c, 0x2d, 0xc3, 0xfa, 0x0a, 0x56, 0x28, - 0xb3, 0x9d, 0x3d, 0xd7, 0x63, 0x17, 0x57, 0x46, 0xcc, 0x56, 0xd7, 0x63, 0x2d, 0x04, 0x0c, 0x49, - 0xb6, 0xaa, 0x39, 0xb9, 0x0b, 0x4b, 0xd4, 0xf6, 0xbb, 0x4c, 0x99, 0x7e, 0x2f, 0xc5, 0xb4, 0x30, - 0x82, 0xbc, 0x54, 0x8a, 0x58, 0xf7, 0xa0, 0xd0, 0xa7, 0x61, 0xad, 0x79, 0xdc, 0xe9, 0xc4, 0x4c, - 0xd6, 0xad, 0x0c, 0x55, 0x33, 0xa4, 0x1f, 0x32, 0xbf, 0xab, 0x4c, 0x67, 0xa8, 0x9a, 0x59, 0x6b, - 0x88, 0xb2, 0x93, 0x9d, 0x2b, 0xd7, 0x10, 0xc8, 0xee, 0x20, 0xaa, 0x32, 0x44, 0x82, 0x89, 0xb1, - 0xe5, 0x60, 0xab, 0xb3, 0x9d, 0x1d, 0x37, 0xba, 0xf8, 0x80, 0x35, 0xc8, 0xed, 0xb8, 0x91, 0x76, - 0xbe, 0x64, 0x4a, 0xd6, 0xb0, 0x09, 0xb6, 0xbd, 0x9e, 0x83, 0xa7, 0xe5, 0x2c, 0xf2, 0x55, 0xb5, - 0x1f, 0xa1, 0x5a, 0x9f, 0x48, 0x3f, 0x0a, 0x2b, 0x6a, 0x33, 0x37, 0x20, 0xc7, 0x7c, 0x1e, 0xb9, - 0x2c, 0xe9, 0x94, 0xa4, 0x2e, 0x1f, 0xa0, 0x75, 0xf1, 0x00, 0x15, 0x1d, 0x99, 0x26, 0x2c, 0xd6, - 0x26, 0xac, 0x20, 0x21, 0x3d, 0x10, 0x04, 0xb2, 0xda, 0x26, 0xc5, 0xd8, 0xba, 0x0b, 0xd5, 0x81, - 0xa0, 0x32, 0xbd, 0x06, 0x59, 0x84, 0x8c, 0xaa, 0x10, 0x4f, 0xb2, 0x2b, 0xd6, 0xad, 0x6b, 0xb0, - 0x92, 0x64, 0xeb, 0x85, 0x46, 0x2d, 0x02, 0xd5, 0x01, 0x93, 0x42, 0x0b, 0x65, 0x28, 0xb6, 0x5c, - 0x3f, 0x69, 0xa6, 0xd6, 0x2b, 0x03, 0x4a, 0xad, 0xc0, 0x1f, 0x34, 0xa1, 0x16, 0xac, 0x24, 0xa9, - 0xfb, 0xa0, 0x75, 0xb0, 0x6d, 0x87, 0x89, 0x0f, 0x56, 0xc7, 0xef, 0x87, 0x7a, 0xc2, 0xd7, 0x25, - 0xe3, 0x56, 0x16, 0xfb, 0x15, 0x1d, 0x15, 0x27, 0x9f, 0x42, 0xee, 0xf0, 0x70, 0x4b, 0x68, 0x5a, - 0x9c, 0x4b, 0x53, 0x22, 0x46, 0xee, 0x43, 0xee, 0xa9, 0xf8, 0xb2, 0x10, 0xab, 0x9e, 0x32, 0xe1, - 0xae, 0x4a, 0x0f, 0x49, 0x36, 0xca, 0xda, 0x41, 0xe4, 0xd0, 0x44, 0xc8, 0xfa, 0xb7, 0x01, 0xc5, - 0xa7, 0xf6, 0x00, 0xa8, 0x0d, 0x90, 0xe1, 0x6b, 0x34, 0x5a, 0x85, 0x0c, 0x2f, 0xc3, 0x92, 0xc7, - 0x5e, 0x30, 0x4f, 0xdd, 0x71, 0x39, 0x41, 0x6a, 0xfc, 0x2c, 0x88, 0x64, 0x5a, 0x97, 0xa8, 0x9c, - 0x60, 0x42, 0x38, 0x8c, 0xdb, 0xae, 0x57, 0xcb, 0xae, 0x66, 0xb0, 0x29, 0xcb, 0x19, 0x46, 0xae, - 0x17, 0x79, 0x0a, 0xae, 0xe3, 0x90, 0x58, 0x90, 0x75, 0xfd, 0x4e, 0x20, 0x1a, 0x96, 0x2a, 0x8b, - 0xc7, 0x41, 0x2f, 0x6a, 0xb3, 0x03, 0xbf, 0x13, 0x50, 0xb1, 0x46, 0xae, 0xc2, 0x72, 0x84, 0xf9, - 0x17, 0xd7, 0x72, 0xc2, 0x29, 0x05, 0xe4, 0x92, 0x59, 0xaa, 0x16, 0xac, 0x0a, 0x94, 0xe4, 0xb9, - 0x55, 0xf0, 0x7f, 0xbd, 0x08, 0x6f, 0x3c, 0x62, 0x67, 0xdb, 0xc9, 0xb9, 0x12, 0x87, 0xac, 0x42, - 0xb1, 0x4f, 0x3b, 0xd8, 0x51, 0x57, 0x48, 0x27, 0xa1, 0xb1, 0xa3, 0xa0, 0xe7, 0xf3, 0x24, 0x86, - 0xc2, 0x98, 0xa0, 0x50, 0xb5, 0x40, 0xde, 0x87, 0xdc, 0x23, 0xc6, 0xcf, 0x82, 0xe8, 0xb9, 0x38, - 0x75, 0xa5, 0x59, 0x44, 0x9e, 0x47, 0x8c, 0x23, 0xae, 0xa2, 0xc9, 0x1a, 0x82, 0xb5, 0x30, 0x01, - 0x6b, 0xd9, 0x49, 0x60, 0x2d, 0x59, 0x25, 0x9b, 0x50, 0x6c, 0x07, 0x7e, 0xcc, 0x23, 0xdb, 0x45, - 0xc3, 0x4b, 0x82, 0xf9, 0x4d, 0x64, 0x96, 0x81, 0xdd, 0x1e, 0x2c, 0x52, 0x9d, 0x93, 0x6c, 0x00, - 0xb0, 0x97, 0x3c, 0xb2, 0xf7, 0x83, 0xb8, 0xff, 0xb0, 0x01, 0x94, 0x43, 0xc2, 0x41, 0x8b, 0x6a, - 0xab, 0xd6, 0x5b, 0x70, 0x79, 0xd8, 0x23, 0xca, 0x55, 0xf7, 0xe0, 0xff, 0x28, 0xf3, 0x98, 0x1d, - 0xb3, 0xf9, 0xbd, 0x65, 0x99, 0x50, 0x1b, 0x17, 0x56, 0x8a, 0xff, 0x93, 0x81, 0xe2, 0xee, 0x4b, - 0xd6, 0x3e, 0x62, 0x71, 0x6c, 0x77, 0x05, 0x64, 0x6c, 0x45, 0x41, 0x9b, 0xc5, 0x71, 0x5f, 0xd7, - 0x80, 0x40, 0xbe, 0x0f, 0xd9, 0x03, 0xdf, 0xe5, 0xaa, 0x3f, 0xae, 0xa5, 0x22, 0x76, 0x97, 0x2b, - 0x9d, 0xfb, 0x0b, 0x54, 0x48, 0x91, 0xbb, 0x90, 0xc5, 0xea, 0x32, 0x4b, 0x85, 0x77, 0x34, 0x59, - 0x94, 0x21, 0x5b, 0xe2, 0xcb, 0x9a, 0xfb, 0x25, 0x53, 0x51, 0x5a, 0x4f, 0x6f, 0x4d, 0xee, 0x97, - 0x6c, 0xa0, 0x41, 0x49, 0x92, 0x5d, 0xc8, 0x1d, 0x73, 0x3b, 0xe2, 0xcc, 0x51, 0xd1, 0xbb, 0x9e, - 0x86, 0x60, 0x24, 0xe7, 0x40, 0x4b, 0x22, 0x8b, 0x4e, 0xd8, 0x7d, 0xe9, 0x72, 0x95, 0x0d, 0x69, - 0x4e, 0x40, 0x36, 0xed, 0x20, 0x38, 0x45, 0xe9, 0x9d, 0xc0, 0x67, 0xb5, 0xdc, 0x54, 0x69, 0x64, - 0xd3, 0xa4, 0x71, 0x8a, 0x6e, 0x38, 0x76, 0xbb, 0x08, 0x0c, 0xf3, 0x53, 0xdd, 0x20, 0x19, 0x35, - 0x37, 0x48, 0xc2, 0x56, 0x0e, 0x96, 0x04, 0x0c, 0xb2, 0x7e, 0x6b, 0x40, 0x51, 0x8b, 0xd3, 0x0c, - 0x79, 0xf7, 0x0e, 0x64, 0xf1, 0x55, 0xad, 0xe2, 0x9f, 0x17, 0x59, 0xc7, 0xb8, 0x4d, 0x05, 0x15, - 0x0b, 0xc7, 0x9e, 0x23, 0x8b, 0x62, 0x99, 0xe2, 0x10, 0x29, 0x4f, 0xf8, 0xb9, 0x08, 0x59, 0x9e, - 0xe2, 0x90, 0xdc, 0x80, 0xfc, 0x31, 0x6b, 0xf7, 0x22, 0x97, 0x9f, 0x8b, 0x20, 0x54, 0x9a, 0x55, - 0x51, 0x4e, 0x14, 0x4d, 0x24, 0x67, 0x9f, 0xc3, 0x7a, 0x88, 0x97, 0x73, 0xb0, 0x41, 0x02, 0xd9, - 0x6d, 0x7c, 0x28, 0xe1, 0xce, 0xca, 0x54, 0x8c, 0xf1, 0xad, 0xba, 0x3b, 0xed, 0xad, 0xba, 0x9b, - 0xbc, 0x55, 0x87, 0x83, 0x8a, 0xdd, 0x47, 0x73, 0xb2, 0xf5, 0x00, 0x0a, 0xfd, 0x8b, 0x47, 0x2a, - 0xb0, 0xb8, 0xe7, 0x28, 0x4b, 0x8b, 0x7b, 0x0e, 0x1e, 0x65, 0xf7, 0xf1, 0x9e, 0xb0, 0x92, 0xa7, - 0x38, 0xec, 0x83, 0x84, 0x8c, 0x06, 0x12, 0x36, 0xf1, 0x15, 0xae, 0xdd, 0x3e, 0x64, 0xa2, 0xc1, - 0x59, 0x9c, 0x6c, 0x19, 0xc7, 0xf2, 0x18, 0x5e, 0x2c, 0x74, 0x89, 0x63, 0x78, 0xb1, 0x75, 0x0d, - 0xca, 0x43, 0xf1, 0x42, 0x26, 0xf1, 0xec, 0x53, 0x58, 0x12, 0xc7, 0x1b, 0x0c, 0x56, 0x46, 0xbe, - 0x04, 0x91, 0xf7, 0x61, 0x59, 0x7e, 0x71, 0xa8, 0x2e, 0x98, 0x6f, 0x7f, 0xfd, 0xcd, 0xea, 0x9b, - 0x23, 0x0c, 0x72, 0x11, 0xd9, 0xb6, 0x7a, 0xbe, 0xe3, 0xb1, 0xaa, 0x31, 0x91, 0x4d, 0x2e, 0x9a, - 0xd9, 0x5f, 0xfd, 0xfe, 0xca, 0xc2, 0x86, 0x0d, 0x97, 0xc6, 0xbe, 0x62, 0x90, 0x6b, 0x90, 0x3d, - 0x66, 0x5e, 0x27, 0x31, 0x33, 0xc6, 0x80, 0x8b, 0xe4, 0x2a, 0x64, 0xa8, 0x7d, 0x56, 0x35, 0xcc, - 0xda, 0xd7, 0xdf, 0xac, 0x5e, 0x1e, 0xff, 0x14, 0x62, 0x9f, 0x49, 0x13, 0xcd, 0xbf, 0x00, 0x14, - 0x0e, 0x0f, 0xb7, 0xb6, 0x22, 0xd7, 0xe9, 0x32, 0xf2, 0x4b, 0x03, 0xc8, 0xf8, 0x4b, 0x94, 0xdc, - 0x4e, 0xcf, 0xf1, 0xc9, 0x0f, 0x72, 0xf3, 0xe3, 0x39, 0xa5, 0x14, 0xd2, 0xf8, 0x1c, 0x96, 0x04, - 0x3c, 0x26, 0x1f, 0xcc, 0xf8, 0xac, 0x31, 0xd7, 0xa7, 0x33, 0x2a, 0xdd, 0x6d, 0xc8, 0x27, 0x10, - 0x93, 0x6c, 0xa4, 0x6e, 0x6f, 0x08, 0x41, 0x9b, 0x1f, 0xce, 0xc4, 0xab, 0x8c, 0xfc, 0x14, 0x72, - 0x0a, 0x39, 0x92, 0xeb, 0x53, 0xe4, 0x06, 0x18, 0xd6, 0xdc, 0x98, 0x85, 0x75, 0x70, 0x8c, 0x04, - 0x21, 0xa6, 0x1e, 0x63, 0x04, 0x7f, 0xa6, 0x1e, 0x63, 0x0c, 0x72, 0xb6, 0x07, 0x0f, 0xc1, 0x54, - 0x23, 0x23, 0x78, 0x33, 0xd5, 0xc8, 0x28, 0xec, 0x24, 0x4f, 0x21, 0x8b, 0xb0, 0x93, 0xa4, 0x95, - 0x5f, 0x0d, 0x97, 0x9a, 0x69, 0x77, 0x62, 0x08, 0xaf, 0xfe, 0x04, 0xdb, 0x94, 0x78, 0xf3, 0xa7, - 0x37, 0x28, 0xed, 0x43, 0x9d, 0x79, 0x7d, 0x06, 0xce, 0x81, 0x7a, 0xf5, 0x5e, 0x5e, 0x9f, 0xe1, - 0x6b, 0xd9, 0x74, 0xf5, 0x23, 0xdf, 0xe5, 0x02, 0x28, 0xe9, 0xe8, 0x83, 0xd4, 0x53, 0x44, 0x27, - 0x00, 0x37, 0xb3, 0x31, 0x33, 0xbf, 0x32, 0xf8, 0x15, 0xbe, 0xbd, 0x86, 0x91, 0x09, 0x69, 0xa6, - 0xba, 0x63, 0x22, 0x06, 0x32, 0x6f, 0xcd, 0x25, 0xa3, 0x8c, 0xdb, 0x12, 0xf9, 0x28, 0x74, 0x43, - 0xd2, 0x1b, 0x79, 0x1f, 0x21, 0x99, 0x33, 0xf2, 0xad, 0x1b, 0x37, 0x0d, 0xbc, 0x67, 0x88, 0x78, - 0x53, 0x75, 0x6b, 0x4f, 0x81, 0xd4, 0x7b, 0xa6, 0x43, 0xe7, 0xad, 0xd2, 0xb7, 0xaf, 0xae, 0x18, - 0x7f, 0x7f, 0x75, 0xc5, 0xf8, 0xd7, 0xab, 0x2b, 0xc6, 0xc9, 0xb2, 0xf8, 0xfb, 0xf1, 0xd6, 0x7f, - 0x03, 0x00, 0x00, 0xff, 0xff, 0x5c, 0x01, 0xa5, 0x69, 0xd0, 0x1d, 0x00, 0x00, + 0x03, 0xdf, 0x8d, 0xb9, 0xeb, 0x76, 0xdd, 0x7a, 0x27, 0x16, 0x32, 0xd2, 0x0a, 0x1e, 0x42, 0xb2, + 0x5b, 0x7f, 0xcb, 0xc2, 0x32, 0x65, 0x71, 0xcf, 0xe3, 0x64, 0x1d, 0x4a, 0x11, 0xeb, 0xec, 0xb2, + 0x30, 0x62, 0x6d, 0x9b, 0x33, 0xa7, 0x6a, 0xac, 0x19, 0x1b, 0xf9, 0x83, 0x05, 0x3a, 0x4c, 0x26, + 0x3f, 0x82, 0x72, 0xc4, 0x3a, 0xb1, 0xc6, 0xb8, 0xb8, 0x66, 0x6c, 0x14, 0x1a, 0x1f, 0xd6, 0x2e, + 0x0c, 0x46, 0x8d, 0xb2, 0xce, 0x91, 0x1d, 0x0e, 0x44, 0x0e, 0x16, 0xe8, 0x88, 0x12, 0xd2, 0x80, + 0x4c, 0xc4, 0x3a, 0xd5, 0x8c, 0xd0, 0x75, 0x25, 0x5d, 0xd7, 0xc1, 0x02, 0x45, 0x66, 0xb2, 0x05, + 0x59, 0xd4, 0x52, 0xcd, 0x0a, 0xa1, 0xab, 0x53, 0x37, 0x70, 0xb0, 0x40, 0x85, 0x00, 0x79, 0x08, + 0xb9, 0x53, 0xc6, 0x6d, 0xc7, 0xe6, 0x76, 0x15, 0xd6, 0x32, 0x1b, 0x85, 0x46, 0x3d, 0x55, 0x18, + 0x1d, 0x54, 0x3b, 0x52, 0x12, 0x7b, 0x3e, 0x8f, 0xce, 0x69, 0x5f, 0x01, 0x79, 0x0a, 0x45, 0x9b, + 0x73, 0x86, 0x5e, 0x75, 0x03, 0x3f, 0xae, 0x16, 0x85, 0xc2, 0x5b, 0xd3, 0x15, 0x3e, 0xd0, 0xa4, + 0xa4, 0xd2, 0x21, 0x45, 0xe6, 0x3d, 0x28, 0x0d, 0xd9, 0x24, 0x15, 0xc8, 0x3c, 0x67, 0xe7, 0x32, + 0x30, 0x14, 0x87, 0xe4, 0x32, 0x2c, 0xbd, 0xb0, 0xbd, 0x1e, 0x13, 0x31, 0x28, 0x52, 0x39, 0xb9, + 0xbb, 0x78, 0xc7, 0x30, 0x9f, 0xc1, 0xa5, 0x31, 0xfd, 0x13, 0x14, 0xfc, 0x40, 0x57, 0x50, 0x68, + 0x7c, 0x90, 0xb2, 0x6b, 0x5d, 0x9d, 0x66, 0x69, 0x3b, 0x07, 0xcb, 0x91, 0x38, 0x90, 0xf5, 0x1b, + 0x03, 0x2a, 0xa3, 0xa1, 0x26, 0x4d, 0x15, 0x24, 0x43, 0xb8, 0xe5, 0xe3, 0x39, 0x6e, 0x09, 0x12, + 0x94, 0x63, 0x84, 0x0a, 0x73, 0x0b, 0xf2, 0x7d, 0xd2, 0x34, 0x67, 0xe4, 0xb5, 0x2d, 0x5a, 0x5b, + 0x90, 0xa1, 0xac, 0x43, 0xca, 0xb0, 0xe8, 0xaa, 0x7b, 0x4d, 0x17, 0x5d, 0x87, 0xac, 0x41, 0xc6, + 0x61, 0x1d, 0x75, 0xf4, 0x72, 0x2d, 0x3c, 0xa9, 0xed, 0xb2, 0x8e, 0xeb, 0xbb, 0x78, 0x44, 0x8a, + 0x4b, 0xd6, 0xef, 0x0c, 0xcc, 0x0f, 0xdc, 0x16, 0xf9, 0x64, 0xe8, 0x1c, 0xd3, 0x6f, 0xfb, 0xd8, + 0xee, 0x9f, 0xa6, 0xef, 0xfe, 0xf6, 0x70, 0x24, 0xa6, 0xa4, 0x80, 0x7e, 0xba, 0x1f, 0x43, 0x51, + 0x8f, 0x0d, 0x39, 0x80, 0x82, 0x76, 0x8f, 0xd4, 0x86, 0xd7, 0x67, 0x8b, 0x2c, 0xd5, 0x45, 0xad, + 0x3f, 0x64, 0xa0, 0xa0, 0x2d, 0x92, 0xfb, 0x90, 0x7d, 0xee, 0xfa, 0xd2, 0x85, 0xe5, 0xc6, 0xe6, + 0x6c, 0x2a, 0x1f, 0xba, 0xbe, 0x43, 0x85, 0x1c, 0x69, 0x69, 0x79, 0xb7, 0x28, 0xb6, 0x75, 0x7b, + 0x36, 0x1d, 0x17, 0x26, 0xdf, 0xcd, 0x39, 0xca, 0x86, 0x2c, 0x1a, 0x04, 0xb2, 0xa1, 0xcd, 0x9f, + 0x89, 0xa2, 0x91, 0xa7, 0x62, 0x4c, 0x6e, 0xc2, 0x1b, 0xae, 0xff, 0x24, 0xe0, 0x41, 0x2b, 0x62, + 0x8e, 0x8b, 0x97, 0xef, 0xc9, 0x79, 0xc8, 0xaa, 0x4b, 0x82, 0x65, 0xd2, 0x12, 0x69, 0x41, 0x59, + 0x92, 0x8f, 0x7b, 0x27, 0x3f, 0x63, 0x6d, 0x1e, 0x57, 0x97, 0xc5, 0x79, 0x36, 0x52, 0xb6, 0xd0, + 0xd4, 0x05, 0xe8, 0x88, 0xfc, 0x6b, 0x65, 0xbb, 0xf5, 0x27, 0x03, 0x4a, 0x43, 0xea, 0xc9, 0xa7, + 0x43, 0xa1, 0xba, 0x31, 0xeb, 0xb6, 0xb4, 0x60, 0x7d, 0x06, 0xcb, 0x8e, 0xdb, 0x65, 0x31, 0x17, + 0xa1, 0xca, 0x6f, 0x37, 0xbe, 0xfd, 0xee, 0xdd, 0x85, 0x7f, 0x7c, 0xf7, 0xee, 0xa6, 0xd6, 0x62, + 0x82, 0x90, 0xf9, 0xed, 0xc0, 0xe7, 0xb6, 0xeb, 0xb3, 0x08, 0x3b, 0xe5, 0x47, 0x52, 0xa4, 0xb6, + 0x2b, 0x7e, 0xa8, 0xd2, 0x80, 0x4e, 0xf7, 0xed, 0x53, 0x26, 0xe2, 0x94, 0xa7, 0x62, 0x6c, 0x71, + 0x28, 0x51, 0xc6, 0x7b, 0x91, 0x4f, 0xd9, 0xcf, 0x7b, 0xc8, 0xf4, 0xbd, 0xa4, 0x90, 0x88, 0x4d, + 0x4f, 0x2b, 0xe8, 0xc8, 0x48, 0x95, 0x00, 0xd9, 0x80, 0x25, 0x16, 0x45, 0x41, 0xa4, 0x92, 0x87, + 0xd4, 0x64, 0xcf, 0xae, 0x45, 0x61, 0xbb, 0x76, 0x2c, 0x7a, 0x36, 0x95, 0x0c, 0x56, 0x05, 0xca, + 0x89, 0xd5, 0x38, 0x0c, 0xfc, 0x98, 0x59, 0xab, 0xe8, 0xba, 0xb0, 0xc7, 0x63, 0xb5, 0x0f, 0xeb, + 0xaf, 0x06, 0x94, 0x13, 0x8a, 0xe4, 0x21, 0x5f, 0x40, 0x61, 0x50, 0x1a, 0x92, 0x1a, 0x70, 0x37, + 0xd5, 0xa9, 0xba, 0xbc, 0x56, 0x57, 0x54, 0x49, 0xd0, 0xd5, 0x99, 0x8f, 0xa0, 0x32, 0xca, 0x30, + 0x21, 0xfa, 0xef, 0x0d, 0x17, 0x88, 0xd1, 0x7a, 0xa5, 0xdd, 0x86, 0x7f, 0x19, 0xf0, 0x36, 0x65, + 0x02, 0x84, 0x34, 0x4f, 0xed, 0x2e, 0xdb, 0x09, 0xfc, 0x8e, 0xdb, 0x4d, 0xdc, 0x5c, 0x11, 0xc5, + 0x30, 0xd1, 0x8c, 0x75, 0x71, 0x03, 0x72, 0x2d, 0xcf, 0xe6, 0x9d, 0x20, 0x3a, 0x55, 0xca, 0x8b, + 0xa8, 0x3c, 0xa1, 0xd1, 0xfe, 0x2a, 0x59, 0x83, 0x82, 0x52, 0x7c, 0x14, 0x38, 0x49, 0x38, 0x75, + 0x12, 0xa9, 0xc2, 0xca, 0x61, 0xd0, 0x7d, 0x84, 0xc1, 0x96, 0x19, 0x96, 0x4c, 0x89, 0x05, 0x45, + 0xc5, 0x18, 0xf5, 0xb3, 0x6b, 0x89, 0x0e, 0xd1, 0xc8, 0x3b, 0x90, 0x3f, 0x66, 0x71, 0xec, 0x06, + 0x7e, 0x73, 0xb7, 0xba, 0x2c, 0xe4, 0x07, 0x04, 0xd4, 0x7d, 0xcc, 0x83, 0x88, 0x35, 0x77, 0xab, + 0x2b, 0x52, 0xb7, 0x9a, 0x5a, 0xbf, 0x30, 0xc0, 0x9c, 0x74, 0x62, 0x15, 0xbe, 0xcf, 0x60, 0x59, + 0x5e, 0x48, 0x79, 0xea, 0xff, 0xed, 0x2a, 0xcb, 0x5f, 0xf2, 0x16, 0x2c, 0x4b, 0xed, 0x2a, 0x0b, + 0xd5, 0xcc, 0xfa, 0xf3, 0x12, 0x14, 0x8f, 0x71, 0x03, 0x89, 0x9f, 0x6b, 0x00, 0x83, 0xf0, 0xa8, + 0x2b, 0x3d, 0x1a, 0x34, 0x8d, 0x83, 0x98, 0x90, 0xdb, 0x57, 0xd7, 0x47, 0x75, 0xb0, 0xfe, 0x9c, + 0x7c, 0x0e, 0x85, 0x64, 0xfc, 0x38, 0xe4, 0xd5, 0x8c, 0xb8, 0x7f, 0x77, 0x52, 0xee, 0x9f, 0xbe, + 0x93, 0x9a, 0x26, 0xaa, 0x6e, 0x9f, 0x46, 0x21, 0x37, 0xe0, 0x92, 0xed, 0x79, 0xc1, 0x99, 0x4a, + 0x29, 0x91, 0x1c, 0x22, 0x38, 0x39, 0x3a, 0xbe, 0x80, 0xa5, 0x52, 0x23, 0x3e, 0x88, 0x22, 0xfb, + 0x1c, 0x6f, 0xd3, 0xb2, 0xe0, 0x9f, 0xb4, 0x84, 0x55, 0x6b, 0xdf, 0xf5, 0x6d, 0xaf, 0x0a, 0x82, + 0x47, 0x4e, 0xf0, 0x36, 0xec, 0xbd, 0x0c, 0x83, 0x88, 0xb3, 0xe8, 0x01, 0xe7, 0x51, 0xb5, 0x20, + 0x9c, 0x39, 0x44, 0x23, 0x2d, 0x28, 0xee, 0xd8, 0xed, 0x67, 0xac, 0x79, 0x8a, 0xc4, 0x04, 0x59, + 0xa5, 0xd5, 0x32, 0xc1, 0xfe, 0x38, 0xd4, 0x21, 0x95, 0xae, 0x81, 0xb4, 0xa1, 0x9c, 0x1c, 0x5d, + 0x66, 0x68, 0xb5, 0x24, 0x74, 0xde, 0x9b, 0xd7, 0x95, 0x52, 0x5a, 0x9a, 0x18, 0x51, 0x89, 0x81, + 0xdc, 0xc3, 0x64, 0xb4, 0x39, 0xab, 0x96, 0xc5, 0x99, 0xfb, 0x73, 0xf3, 0x3e, 0x54, 0x46, 0xa3, + 0x31, 0x0f, 0x92, 0x31, 0x7f, 0x08, 0x6f, 0x4c, 0xd8, 0xc2, 0x6b, 0x55, 0x8b, 0x3f, 0x1a, 0x70, + 0x69, 0xcc, 0x6f, 0x58, 0xb1, 0x45, 0x96, 0x4a, 0x95, 0x62, 0x4c, 0x8e, 0x60, 0x09, 0xe3, 0x12, + 0xab, 0xde, 0xbd, 0x35, 0x4f, 0x20, 0x6a, 0x42, 0x52, 0x3a, 0x4c, 0x6a, 0x31, 0xef, 0x00, 0x0c, + 0x88, 0x73, 0xe1, 0xb9, 0x2f, 0xa0, 0xa4, 0xa2, 0xa2, 0x12, 0xbc, 0x22, 0x61, 0x80, 0x12, 0xc6, + 0x36, 0x3f, 0x68, 0x26, 0x99, 0x39, 0x9b, 0x89, 0xf5, 0x15, 0xac, 0x52, 0x66, 0x3b, 0xfb, 0xae, + 0xc7, 0x2e, 0xae, 0x99, 0x98, 0xad, 0xae, 0xc7, 0x5a, 0x08, 0x25, 0x92, 0x6c, 0x55, 0x73, 0x72, + 0x17, 0x96, 0xa8, 0xed, 0x77, 0x99, 0x32, 0xfd, 0x5e, 0x8a, 0x69, 0x61, 0x04, 0x79, 0xa9, 0x14, + 0xb1, 0xee, 0x41, 0xbe, 0x4f, 0xc3, 0x5a, 0xf3, 0xb8, 0xd3, 0x89, 0x99, 0xac, 0x5b, 0x19, 0xaa, + 0x66, 0x48, 0x3f, 0x64, 0x7e, 0x57, 0x99, 0xce, 0x50, 0x35, 0xb3, 0xd6, 0x11, 0x7f, 0x27, 0x3b, + 0x57, 0xae, 0x21, 0x90, 0xdd, 0x45, 0xbc, 0x65, 0x88, 0x04, 0x13, 0x63, 0xcb, 0xc1, 0x26, 0x68, + 0x3b, 0xbb, 0x6e, 0x74, 0xf1, 0x01, 0xab, 0xb0, 0xb2, 0xeb, 0x46, 0xda, 0xf9, 0x92, 0x29, 0x59, + 0xc7, 0xf6, 0xd8, 0xf6, 0x7a, 0x0e, 0x9e, 0x96, 0xb3, 0xc8, 0x57, 0x7d, 0x60, 0x84, 0x6a, 0x7d, + 0x22, 0xfd, 0x28, 0xac, 0xa8, 0xcd, 0xdc, 0x80, 0x15, 0xe6, 0xf3, 0xc8, 0x65, 0x49, 0x0f, 0x25, + 0x35, 0xf9, 0x34, 0xad, 0x89, 0xa7, 0xa9, 0xe8, 0xd5, 0x34, 0x61, 0xb1, 0xb6, 0x60, 0x15, 0x09, + 0xe9, 0x81, 0x20, 0x90, 0xd5, 0x36, 0x29, 0xc6, 0xd6, 0x5d, 0xa8, 0x0c, 0x04, 0x95, 0xe9, 0x75, + 0xc8, 0x22, 0x98, 0x54, 0x85, 0x78, 0x92, 0x5d, 0xb1, 0x6e, 0x5d, 0x83, 0xd5, 0x24, 0x5b, 0x2f, + 0x34, 0x6a, 0x11, 0xa8, 0x0c, 0x98, 0x14, 0x8e, 0x28, 0x41, 0xa1, 0xe5, 0xfa, 0x49, 0x9b, 0xb5, + 0x5e, 0x19, 0x50, 0x6c, 0x05, 0xfe, 0xa0, 0x09, 0xb5, 0x60, 0x35, 0x49, 0xdd, 0x07, 0xad, 0xe6, + 0x8e, 0x1d, 0x26, 0x3e, 0x58, 0x1b, 0xbf, 0x1f, 0xea, 0x71, 0x5f, 0x93, 0x8c, 0xdb, 0x59, 0xec, + 0x57, 0x74, 0x54, 0x9c, 0x7c, 0x0a, 0x2b, 0x87, 0x87, 0xdb, 0x42, 0xd3, 0xe2, 0x5c, 0x9a, 0x12, + 0x31, 0x72, 0x1f, 0x56, 0x9e, 0x8a, 0x6f, 0x0e, 0xb1, 0xea, 0x29, 0x13, 0xee, 0xaa, 0xf4, 0x90, + 0x64, 0xa3, 0xac, 0x1d, 0x44, 0x0e, 0x4d, 0x84, 0xac, 0x7f, 0x1b, 0x50, 0x78, 0x6a, 0x0f, 0x20, + 0xdc, 0x00, 0x33, 0xbe, 0x46, 0xa3, 0x55, 0x98, 0xf1, 0x32, 0x2c, 0x79, 0xec, 0x05, 0xf3, 0xd4, + 0x1d, 0x97, 0x13, 0xa4, 0xc6, 0xcf, 0x82, 0x48, 0xa6, 0x75, 0x91, 0xca, 0x09, 0x26, 0x84, 0xc3, + 0xb8, 0xed, 0x7a, 0xd5, 0xec, 0x5a, 0x06, 0x9b, 0xb2, 0x9c, 0x61, 0xe4, 0x7a, 0x91, 0xa7, 0x80, + 0x3c, 0x0e, 0x89, 0x05, 0x59, 0xd7, 0xef, 0x04, 0xa2, 0x61, 0xa9, 0xb2, 0x78, 0x1c, 0xf4, 0xa2, + 0x36, 0x6b, 0xfa, 0x9d, 0x80, 0x8a, 0x35, 0x72, 0x15, 0x96, 0x23, 0xcc, 0xbf, 0xb8, 0xba, 0x22, + 0x9c, 0x92, 0x47, 0x2e, 0x99, 0xa5, 0x6a, 0xc1, 0x2a, 0x43, 0x51, 0x9e, 0x5b, 0x05, 0xff, 0xd7, + 0x8b, 0xf0, 0xc6, 0x23, 0x76, 0xb6, 0x93, 0x9c, 0x2b, 0x71, 0xc8, 0x1a, 0x14, 0xfa, 0xb4, 0xe6, + 0xae, 0xba, 0x42, 0x3a, 0x09, 0x8d, 0x1d, 0x05, 0x3d, 0x9f, 0x27, 0x31, 0x14, 0xc6, 0x04, 0x85, + 0xaa, 0x05, 0xf2, 0x3e, 0xac, 0x3c, 0x62, 0xfc, 0x2c, 0x88, 0x9e, 0x8b, 0x53, 0x97, 0x1b, 0x05, + 0xe4, 0x79, 0xc4, 0x38, 0x22, 0x2e, 0x9a, 0xac, 0x21, 0x8c, 0x0b, 0x13, 0x18, 0x97, 0x9d, 0x04, + 0xe3, 0x92, 0x55, 0xb2, 0x05, 0x85, 0x76, 0xe0, 0xc7, 0x3c, 0xb2, 0x5d, 0x34, 0xbc, 0x24, 0x98, + 0xdf, 0x44, 0x66, 0x19, 0xd8, 0x9d, 0xc1, 0x22, 0xd5, 0x39, 0xc9, 0x26, 0x00, 0x7b, 0xc9, 0x23, + 0xfb, 0x20, 0x88, 0xfb, 0x4f, 0x1e, 0x40, 0x39, 0x24, 0x34, 0x5b, 0x54, 0x5b, 0xb5, 0xde, 0x82, + 0xcb, 0xc3, 0x1e, 0x51, 0xae, 0xba, 0x07, 0xff, 0x47, 0x99, 0xc7, 0xec, 0x98, 0xcd, 0xef, 0x2d, + 0xcb, 0x84, 0xea, 0xb8, 0xb0, 0x52, 0xfc, 0x9f, 0x0c, 0x14, 0xf6, 0x5e, 0xb2, 0xf6, 0x11, 0x8b, + 0x63, 0xbb, 0x2b, 0xc0, 0x64, 0x2b, 0x0a, 0xda, 0x2c, 0x8e, 0xfb, 0xba, 0x06, 0x04, 0xf2, 0x7d, + 0xc8, 0x36, 0x7d, 0x97, 0xab, 0xfe, 0xb8, 0x9e, 0x8a, 0xe5, 0x5d, 0xae, 0x74, 0x1e, 0x2c, 0x50, + 0x21, 0x45, 0xee, 0x42, 0x16, 0xab, 0xcb, 0x2c, 0x15, 0xde, 0xd1, 0x64, 0x51, 0x86, 0x6c, 0x8b, + 0x6f, 0x6e, 0xee, 0x97, 0x4c, 0x45, 0x69, 0x23, 0xbd, 0x35, 0xb9, 0x5f, 0xb2, 0x81, 0x06, 0x25, + 0x49, 0xf6, 0x10, 0x0a, 0xdb, 0x11, 0x67, 0x8e, 0x8a, 0xde, 0xf5, 0x34, 0x04, 0x23, 0x39, 0x07, + 0x5a, 0x12, 0x59, 0x74, 0xc2, 0xde, 0x4b, 0x97, 0xab, 0x6c, 0x48, 0x73, 0x02, 0xb2, 0x69, 0x07, + 0xc1, 0x29, 0x4a, 0xef, 0x06, 0x3e, 0x13, 0x60, 0x3c, 0x5d, 0x1a, 0xd9, 0x34, 0x69, 0x9c, 0xa2, + 0x1b, 0x8e, 0xdd, 0x2e, 0x02, 0xc3, 0xdc, 0x54, 0x37, 0x48, 0x46, 0xcd, 0x0d, 0x92, 0xb0, 0xbd, + 0x02, 0x4b, 0x02, 0x06, 0x59, 0xbf, 0x35, 0xa0, 0xa0, 0xc5, 0x69, 0x86, 0xbc, 0x7b, 0x07, 0xb2, + 0xf8, 0xde, 0x56, 0xf1, 0xcf, 0x89, 0xac, 0x63, 0xdc, 0xa6, 0x82, 0x8a, 0x85, 0x63, 0xdf, 0x91, + 0x45, 0xb1, 0x44, 0x71, 0x88, 0x94, 0x27, 0xfc, 0x5c, 0x84, 0x2c, 0x47, 0x71, 0x48, 0x6e, 0x40, + 0xee, 0x98, 0xb5, 0x7b, 0x91, 0xcb, 0xcf, 0x45, 0x10, 0xca, 0x8d, 0x8a, 0x28, 0x27, 0x8a, 0x26, + 0x92, 0xb3, 0xcf, 0x61, 0x3d, 0xc4, 0xcb, 0x39, 0xd8, 0x20, 0x81, 0xec, 0x0e, 0x3e, 0xa1, 0x70, + 0x67, 0x25, 0x2a, 0xc6, 0xf8, 0x8a, 0xdd, 0x9b, 0xf6, 0x8a, 0xdd, 0x4b, 0x5e, 0xb1, 0xc3, 0x41, + 0xc5, 0xee, 0xa3, 0x39, 0xd9, 0x7a, 0x00, 0xf9, 0xfe, 0xc5, 0x23, 0x65, 0x58, 0xdc, 0x77, 0x94, + 0xa5, 0xc5, 0x7d, 0x07, 0x8f, 0xb2, 0xf7, 0x78, 0x5f, 0x58, 0xc9, 0x51, 0x1c, 0xf6, 0x41, 0x42, + 0x46, 0x03, 0x09, 0x5b, 0xf8, 0x3e, 0xd7, 0x6e, 0x1f, 0x32, 0xd1, 0xe0, 0x2c, 0x4e, 0xb6, 0x8c, + 0x63, 0x79, 0x0c, 0x2f, 0x16, 0xba, 0xc4, 0x31, 0xbc, 0xd8, 0xba, 0x06, 0xa5, 0xa1, 0x78, 0x21, + 0x93, 0x78, 0x10, 0x2a, 0x2c, 0x89, 0xe3, 0x4d, 0x06, 0xab, 0x23, 0xdf, 0x88, 0xc8, 0xfb, 0xb0, + 0x2c, 0xbf, 0x45, 0x54, 0x16, 0xcc, 0xb7, 0xbf, 0xfe, 0x66, 0xed, 0xcd, 0x11, 0x06, 0xb9, 0x88, + 0x6c, 0xdb, 0x3d, 0xdf, 0xf1, 0x58, 0xc5, 0x98, 0xc8, 0x26, 0x17, 0xcd, 0xec, 0xaf, 0x7e, 0x7f, + 0x65, 0x61, 0xd3, 0x86, 0x4b, 0x63, 0xdf, 0x37, 0xc8, 0x35, 0xc8, 0x1e, 0x33, 0xaf, 0x93, 0x98, + 0x19, 0x63, 0xc0, 0x45, 0x72, 0x15, 0x32, 0xd4, 0x3e, 0xab, 0x18, 0x66, 0xf5, 0xeb, 0x6f, 0xd6, + 0x2e, 0x8f, 0x7f, 0x24, 0xb1, 0xcf, 0xa4, 0x89, 0xc6, 0x5f, 0x00, 0xf2, 0x87, 0x87, 0xdb, 0xdb, + 0x91, 0xeb, 0x74, 0x19, 0xf9, 0xa5, 0x01, 0x64, 0xfc, 0x25, 0x4a, 0x6e, 0xa7, 0xe7, 0xf8, 0xe4, + 0xa7, 0xba, 0xf9, 0xf1, 0x9c, 0x52, 0x0a, 0x69, 0x7c, 0x0e, 0x4b, 0x02, 0x1e, 0x93, 0x0f, 0x66, + 0x7c, 0xd6, 0x98, 0x1b, 0xd3, 0x19, 0x95, 0xee, 0x36, 0xe4, 0x12, 0x88, 0x49, 0x36, 0x53, 0xb7, + 0x37, 0x84, 0xa0, 0xcd, 0x0f, 0x67, 0xe2, 0x55, 0x46, 0x7e, 0x0a, 0x2b, 0x0a, 0x39, 0x92, 0xeb, + 0x53, 0xe4, 0x06, 0x18, 0xd6, 0xdc, 0x9c, 0x85, 0x75, 0x70, 0x8c, 0x04, 0x21, 0xa6, 0x1e, 0x63, + 0x04, 0x7f, 0xa6, 0x1e, 0x63, 0x0c, 0x72, 0xb6, 0x07, 0x0f, 0xc1, 0x54, 0x23, 0x23, 0x78, 0x33, + 0xd5, 0xc8, 0x28, 0xec, 0x24, 0x4f, 0x21, 0x8b, 0xb0, 0x93, 0xa4, 0x95, 0x5f, 0x0d, 0x97, 0x9a, + 0x69, 0x77, 0x62, 0x08, 0xaf, 0xfe, 0x04, 0xdb, 0x94, 0x78, 0xf3, 0xa7, 0x37, 0x28, 0xed, 0x13, + 0x9e, 0x79, 0x7d, 0x06, 0xce, 0x81, 0x7a, 0xf5, 0x5e, 0xde, 0x98, 0xe1, 0x3b, 0xda, 0x74, 0xf5, + 0x23, 0x5f, 0xec, 0x02, 0x28, 0xea, 0xe8, 0x83, 0xd4, 0x52, 0x44, 0x27, 0x00, 0x37, 0xb3, 0x3e, + 0x33, 0xbf, 0x32, 0xf8, 0x15, 0xbe, 0xbd, 0x86, 0x91, 0x09, 0x69, 0xa4, 0xba, 0x63, 0x22, 0x06, + 0x32, 0x6f, 0xcd, 0x25, 0xa3, 0x8c, 0xdb, 0x12, 0xf9, 0x28, 0x74, 0x43, 0xd2, 0x1b, 0x79, 0x1f, + 0x21, 0x99, 0x33, 0xf2, 0x6d, 0x18, 0x37, 0x0d, 0xbc, 0x67, 0x88, 0x78, 0x53, 0x75, 0x6b, 0x4f, + 0x81, 0xd4, 0x7b, 0xa6, 0x43, 0xe7, 0xed, 0xe2, 0xb7, 0xaf, 0xae, 0x18, 0x7f, 0x7f, 0x75, 0xc5, + 0xf8, 0xe7, 0xab, 0x2b, 0xc6, 0xc9, 0xb2, 0xf8, 0x63, 0xf2, 0xd6, 0x7f, 0x03, 0x00, 0x00, 0xff, + 0xff, 0x7d, 0x4e, 0x08, 0x7e, 0xea, 0x1d, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -3993,6 +4002,13 @@ func (m *ResolveImageConfigRequest) MarshalToSizedBuffer(dAtA []byte) (int, erro i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.StoreID) > 0 { + i -= len(m.StoreID) + copy(dAtA[i:], m.StoreID) + i = encodeVarintGateway(dAtA, i, uint64(len(m.StoreID))) + i-- + dAtA[i] = 0x3a + } if len(m.SessionID) > 0 { i -= len(m.SessionID) copy(dAtA[i:], m.SessionID) @@ -5912,6 +5928,10 @@ func (m *ResolveImageConfigRequest) Size() (n int) { if l > 0 { n += 1 + l + sovGateway(uint64(l)) } + l = len(m.StoreID) + if l > 0 { + n += 1 + l + sovGateway(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -8716,6 +8736,38 @@ func (m *ResolveImageConfigRequest) Unmarshal(dAtA []byte) error { } m.SessionID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StoreID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGateway + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGateway + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGateway + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StoreID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGateway(dAtA[iNdEx:]) diff --git a/frontend/gateway/pb/gateway.proto b/frontend/gateway/pb/gateway.proto index 0a24d31f33c1..6fd3a9ae9635 100644 --- a/frontend/gateway/pb/gateway.proto +++ b/frontend/gateway/pb/gateway.proto @@ -122,6 +122,7 @@ message ResolveImageConfigRequest { string LogName = 4; int32 ResolverType = 5; string SessionID = 6; + string StoreID = 7; } message ResolveImageConfigResponse { diff --git a/solver/llbsolver/provenance.go b/solver/llbsolver/provenance.go index f3fc171aa45d..341e2ab839a5 100644 --- a/solver/llbsolver/provenance.go +++ b/solver/llbsolver/provenance.go @@ -324,7 +324,7 @@ func captureProvenance(ctx context.Context, res solver.CachedResultWithProvenanc return errors.Wrapf(err, "failed to parse OCI digest %s", pin) } c.AddLocalImage(provenance.ImageSource{ - Ref: s.Name, + Ref: s.Reference.String(), Platform: s.Platform, Digest: dgst, }) diff --git a/solver/pb/attr.go b/solver/pb/attr.go index 5b138d76f14b..85e7cce60ee8 100644 --- a/solver/pb/attr.go +++ b/solver/pb/attr.go @@ -29,6 +29,7 @@ const AttrImageRecordType = "image.recordtype" const AttrImageLayerLimit = "image.layerlimit" const AttrOCILayoutSessionID = "oci.session" +const AttrOCILayoutStoreID = "oci.store" const AttrOCILayoutLayerLimit = "oci.layerlimit" const AttrLocalDiffer = "local.differ" diff --git a/solver/pb/caps.go b/solver/pb/caps.go index 39918a4690c4..8e177f1d0fb9 100644 --- a/solver/pb/caps.go +++ b/solver/pb/caps.go @@ -35,9 +35,7 @@ const ( CapSourceHTTPPerm apicaps.CapID = "source.http.perm" CapSourceHTTPUIDGID apicaps.CapID = "soruce.http.uidgid" - CapSourceOCILayout apicaps.CapID = "source.ocilayout" - CapSourceOCILayoutSessionID apicaps.CapID = "source.ocilayout.sessionid" - CapSourceOCILayoutLayerLimit apicaps.CapID = "source.ocilayout.layerlimit" + CapSourceOCILayout apicaps.CapID = "source.ocilayout" CapBuildOpLLBFileName apicaps.CapID = "source.buildop.llbfilename" @@ -221,18 +219,6 @@ func init() { Status: apicaps.CapStatusExperimental, }) - Caps.Init(apicaps.Cap{ - ID: CapSourceOCILayoutSessionID, - Enabled: true, - Status: apicaps.CapStatusExperimental, - }) - - Caps.Init(apicaps.Cap{ - ID: CapSourceOCILayoutLayerLimit, - Enabled: true, - Status: apicaps.CapStatusExperimental, - }) - Caps.Init(apicaps.Cap{ ID: CapSourceHTTPUIDGID, Enabled: true, diff --git a/source/containerimage/ocilayout.go b/source/containerimage/ocilayout.go index 521a2e7b2dde..2358b5339b7a 100644 --- a/source/containerimage/ocilayout.go +++ b/source/containerimage/ocilayout.go @@ -8,6 +8,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/reference" "github.com/containerd/containerd/remotes" + "github.com/moby/buildkit/client/llb" "github.com/moby/buildkit/session" sessioncontent "github.com/moby/buildkit/session/content" "github.com/moby/buildkit/util/imageutil" @@ -20,22 +21,20 @@ const ( ) // getOCILayoutResolver gets a resolver to an OCI layout for a specified store from the client using the given session. -func getOCILayoutResolver(storeID string, sm *session.Manager, sessionID string, g session.Group) *ociLayoutResolver { +func getOCILayoutResolver(store llb.ResolveImageConfigOptStore, sm *session.Manager, g session.Group) *ociLayoutResolver { r := &ociLayoutResolver{ - storeID: storeID, - sm: sm, - sessionID: sessionID, - g: g, + store: store, + sm: sm, + g: g, } return r } type ociLayoutResolver struct { remotes.Resolver - storeID string - sm *session.Manager - sessionID string - g session.Group + store llb.ResolveImageConfigOptStore + sm *session.Manager + g session.Group } // Fetcher returns a new fetcher for the provided reference. @@ -47,7 +46,7 @@ func (r *ociLayoutResolver) Fetcher(ctx context.Context, ref string) (remotes.Fe func (r *ociLayoutResolver) Fetch(ctx context.Context, desc ocispecs.Descriptor) (io.ReadCloser, error) { var rc io.ReadCloser err := r.withCaller(ctx, func(ctx context.Context, caller session.Caller) error { - store := sessioncontent.NewCallerStore(caller, "oci:"+r.storeID) + store := sessioncontent.NewCallerStore(caller, "oci:"+r.store.StoreID) readerAt, err := store.ReaderAt(ctx, desc) if err != nil { return err @@ -103,7 +102,7 @@ func (r *ociLayoutResolver) Resolve(ctx context.Context, refString string) (stri func (r *ociLayoutResolver) info(ctx context.Context, ref reference.Spec) (content.Info, error) { var info *content.Info err := r.withCaller(ctx, func(ctx context.Context, caller session.Caller) error { - store := sessioncontent.NewCallerStore(caller, "oci:"+r.storeID) + store := sessioncontent.NewCallerStore(caller, "oci:"+r.store.StoreID) _, dgst := reference.SplitObject(ref.Object) if dgst == "" { @@ -123,11 +122,11 @@ func (r *ociLayoutResolver) info(ctx context.Context, ref reference.Spec) (conte } func (r *ociLayoutResolver) withCaller(ctx context.Context, f func(context.Context, session.Caller) error) error { - if r.sessionID != "" { + if r.store.SessionID != "" { timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() - caller, err := r.sm.Get(timeoutCtx, r.sessionID, false) + caller, err := r.sm.Get(timeoutCtx, r.store.SessionID, false) if err != nil { return err } diff --git a/source/containerimage/pull.go b/source/containerimage/pull.go index 0b03d17c16fb..509d2a994660 100644 --- a/source/containerimage/pull.go +++ b/source/containerimage/pull.go @@ -107,12 +107,7 @@ func (is *Source) ResolveImageConfig(ctx context.Context, ref string, opt llb.Re rslvr = resolver.DefaultPool.GetResolver(is.RegistryHosts, ref, "pull", sm, g).WithImageStore(is.ImageStore, rm) case ResolverTypeOCILayout: rm = source.ResolveModeForcePull - - parsed, err := reference.Parse(ref) - if err != nil { - return "", nil, err - } - rslvr = getOCILayoutResolver(parsed.Hostname(), sm, "", g) + rslvr = getOCILayoutResolver(opt.Store, sm, g) } key += rm.String() res, err := is.g.Do(ctx, key, func(ctx context.Context) (interface{}, error) { @@ -137,8 +132,7 @@ func (is *Source) Resolve(ctx context.Context, id source.Identifier, sm *session mode source.ResolveMode recordType client.UsageRecordType ref reference.Spec - sessionID string - storeID string + store llb.ResolveImageConfigOptStore layerLimit *int ) switch is.ResolverType { @@ -165,9 +159,11 @@ func (is *Source) Resolve(ctx context.Context, id source.Identifier, sm *session platform = *ociIdentifier.Platform } mode = source.ResolveModeForcePull // with OCI layout, we always just "pull" - sessionID = ociIdentifier.SessionID - ref = reference.Spec{Locator: "oci-layout/dummy", Object: "@" + ociIdentifier.Digest.String()} - storeID = ociIdentifier.Name + store = llb.ResolveImageConfigOptStore{ + SessionID: ociIdentifier.SessionID, + StoreID: ociIdentifier.StoreID, + } + ref = ociIdentifier.Reference layerLimit = ociIdentifier.LayerLimit default: return nil, errors.Errorf("unknown resolver type: %v", is.ResolverType) @@ -188,9 +184,8 @@ func (is *Source) Resolve(ctx context.Context, id source.Identifier, sm *session RecordType: recordType, Ref: ref.String(), SessionManager: sm, - SessionID: sessionID, vtx: vtx, - storeID: storeID, + store: store, layerLimit: layerLimit, } return p, nil @@ -205,11 +200,10 @@ type puller struct { RecordType client.UsageRecordType Ref string SessionManager *session.Manager - SessionID string layerLimit *int vtx solver.Vertex ResolverType - storeID string + store llb.ResolveImageConfigOptStore g flightcontrol.Group cacheKeyErr error @@ -250,7 +244,7 @@ func (p *puller) CacheKey(ctx context.Context, g session.Group, index int) (cach p.Puller.Resolver = resolver getResolver = func(g session.Group) remotes.Resolver { return resolver.WithSession(g) } case ResolverTypeOCILayout: - resolver := getOCILayoutResolver(p.storeID, p.SessionManager, p.SessionID, g) + resolver := getOCILayoutResolver(p.store, p.SessionManager, g) p.Puller.Resolver = resolver // OCILayout has no need for session getResolver = func(g session.Group) remotes.Resolver { return resolver } @@ -366,7 +360,7 @@ func (p *puller) Snapshot(ctx context.Context, g session.Group) (ir cache.Immuta p.Puller.Resolver = resolver getResolver = func(g session.Group) remotes.Resolver { return resolver.WithSession(g) } case ResolverTypeOCILayout: - resolver := getOCILayoutResolver(p.storeID, p.SessionManager, p.SessionID, g) + resolver := getOCILayoutResolver(p.store, p.SessionManager, g) p.Puller.Resolver = resolver // OCILayout has no need for session getResolver = func(g session.Group) remotes.Resolver { return resolver } diff --git a/source/identifier.go b/source/identifier.go index be7bd21f8bd1..aad9f226ff6e 100644 --- a/source/identifier.go +++ b/source/identifier.go @@ -207,10 +207,8 @@ func FromLLB(op *pb.Op_Source, platform *pb.Platform) (Identifier, error) { switch k { case pb.AttrOCILayoutSessionID: id.SessionID = v - if p := strings.SplitN(v, ":", 2); len(p) == 2 { - id.Name = p[0] + "-" + id.Name - id.SessionID = p[1] - } + case pb.AttrOCILayoutStoreID: + id.StoreID = v case pb.AttrOCILayoutLayerLimit: l, err := strconv.Atoi(v) if err != nil { @@ -291,23 +289,23 @@ func (*HTTPIdentifier) ID() string { } type OCIIdentifier struct { - Name string - Digest digest.Digest + Reference reference.Spec Platform *ocispecs.Platform SessionID string + StoreID string LayerLimit *int } func NewOCIIdentifier(str string) (*OCIIdentifier, error) { - store, digSrc, found := strings.Cut(str, "@") - if !found { - return nil, errors.Errorf("invalid OCI identifier %s", str) - } - dig, err := digest.Parse(digSrc) + ref, err := reference.Parse(str) if err != nil { - return nil, errors.Wrapf(err, "invalid digest in OCI identifier %s", str) + return nil, errors.WithStack(err) + } + + if ref.Object == "" { + return nil, errors.WithStack(reference.ErrObjectRequired) } - return &OCIIdentifier{Name: store, Digest: dig}, nil + return &OCIIdentifier{Reference: ref}, nil } func (*OCIIdentifier) ID() string {