diff --git a/client/client_test.go b/client/client_test.go index 82104e3ab..b06714891 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -47,7 +47,9 @@ import ( "github.com/moby/buildkit/solver/errdefs" "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/solver/result" + "github.com/moby/buildkit/sourcepolicy" sourcepolicypb "github.com/moby/buildkit/sourcepolicy/pb" + spb "github.com/moby/buildkit/sourcepolicy/pb" "github.com/moby/buildkit/util/attestation" binfotypes "github.com/moby/buildkit/util/buildinfo/types" "github.com/moby/buildkit/util/contentutil" @@ -8581,4 +8583,50 @@ func testSourcePolicy(t *testing.T, sb integration.Sandbox) { } }) } + + t.Run("Frontend policies", func(t *testing.T) { + denied := "https://raw.githubusercontent.com/moby/buildkit/v0.10.1/README.md" + frontend := func(ctx context.Context, c gateway.Client) (*gateway.Result, error) { + st := llb.Image("busybox:1.34.1-uclibc").File( + llb.Copy(llb.HTTP(denied), + "README.md", "README.md")) + def, err := st.Marshal(sb.Context()) + if err != nil { + return nil, err + } + return c.Solve(ctx, gateway.SolveRequest{ + Definition: def.ToPB(), + SourcePolicies: []*spb.Policy{{ + Rules: []*spb.Rule{ + { + Action: spb.PolicyAction_DENY, + Source: &spb.Source{ + Type: "http", + Identifier: denied, + }, + }, + }, + }}, + }) + } + + _, err = c.Build(sb.Context(), SolveOpt{}, "", frontend, nil) + require.ErrorContains(t, err, sourcepolicy.ErrSourceDenied.Error()) + + // Override frontend policy + _, err = c.Build(sb.Context(), SolveOpt{ + SourcePolicy: &sourcepolicypb.Policy{ + Rules: []*sourcepolicypb.Rule{ + { + Action: sourcepolicypb.PolicyAction_ALLOW, + Source: &sourcepolicypb.Source{ + Type: "http", + Identifier: denied, + }, + }, + }, + }, + }, "", frontend, nil) + require.NoError(t, err) + }) } diff --git a/frontend/gateway/client/client.go b/frontend/gateway/client/client.go index ae6d297fd..7b6b9de13 100644 --- a/frontend/gateway/client/client.go +++ b/frontend/gateway/client/client.go @@ -8,6 +8,7 @@ import ( "github.com/moby/buildkit/client/llb" "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/solver/result" + spb "github.com/moby/buildkit/sourcepolicy/pb" "github.com/moby/buildkit/util/apicaps" digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" @@ -128,6 +129,7 @@ type SolveRequest struct { FrontendOpt map[string]string FrontendInputs map[string]*pb.Definition CacheImports []CacheOptionsEntry + SourcePolicies []*spb.Policy } type CacheOptionsEntry struct { diff --git a/frontend/gateway/forwarder/forward.go b/frontend/gateway/forwarder/forward.go index a1fa5bd5c..9ff531795 100644 --- a/frontend/gateway/forwarder/forward.go +++ b/frontend/gateway/forwarder/forward.go @@ -62,6 +62,7 @@ func (c *bridgeClient) Solve(ctx context.Context, req client.SolveRequest) (*cli FrontendOpt: req.FrontendOpt, FrontendInputs: req.FrontendInputs, CacheImports: req.CacheImports, + SourcePolicies: req.SourcePolicies, }, c.sid) if err != nil { return nil, c.wrapSolveError(err) diff --git a/frontend/gateway/gateway.go b/frontend/gateway/gateway.go index a96953077..79825d0b6 100644 --- a/frontend/gateway/gateway.go +++ b/frontend/gateway/gateway.go @@ -629,6 +629,7 @@ func (lbf *llbBridgeForwarder) Solve(ctx context.Context, req *pb.SolveRequest) FrontendOpt: req.FrontendOpt, FrontendInputs: req.FrontendInputs, CacheImports: cacheImports, + SourcePolicies: req.SourcePolicies, }, lbf.sid) if err != nil { return nil, lbf.wrapSolveError(err) diff --git a/frontend/gateway/grpcclient/client.go b/frontend/gateway/grpcclient/client.go index b8b2414f8..1b000a816 100644 --- a/frontend/gateway/grpcclient/client.go +++ b/frontend/gateway/grpcclient/client.go @@ -382,6 +382,7 @@ func (c *grpcClient) Solve(ctx context.Context, creq client.SolveRequest) (res * AllowResultReturn: true, AllowResultArrayRef: true, CacheImports: cacheImports, + SourcePolicies: creq.SourcePolicies, } // backwards compatibility with inline return diff --git a/frontend/gateway/pb/gateway.pb.go b/frontend/gateway/pb/gateway.pb.go index 7cecd77bf..da36afdd1 100644 --- a/frontend/gateway/pb/gateway.pb.go +++ b/frontend/gateway/pb/gateway.pb.go @@ -11,7 +11,8 @@ import ( proto "github.com/gogo/protobuf/proto" types1 "github.com/moby/buildkit/api/types" pb "github.com/moby/buildkit/solver/pb" - pb1 "github.com/moby/buildkit/util/apicaps/pb" + pb1 "github.com/moby/buildkit/sourcepolicy/pb" + pb2 "github.com/moby/buildkit/util/apicaps/pb" github_com_opencontainers_go_digest "github.com/opencontainers/go-digest" types "github.com/tonistiigi/fsutil/types" grpc "google.golang.org/grpc" @@ -893,6 +894,7 @@ type SolveRequest struct { // apicaps:CapFrontendInputs FrontendInputs map[string]*pb.Definition `protobuf:"bytes,13,rep,name=FrontendInputs,proto3" json:"FrontendInputs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` Evaluate bool `protobuf:"varint,14,opt,name=Evaluate,proto3" json:"Evaluate,omitempty"` + SourcePolicies []*pb1.Policy `protobuf:"bytes,15,rep,name=SourcePolicies,proto3" json:"SourcePolicies,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1001,6 +1003,13 @@ func (m *SolveRequest) GetEvaluate() bool { return false } +func (m *SolveRequest) GetSourcePolicies() []*pb1.Policy { + if m != nil { + return m.SourcePolicies + } + return nil +} + // CacheOptionsEntry corresponds to the control.CacheOptionsEntry type CacheOptionsEntry struct { Type string `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"` @@ -1617,8 +1626,8 @@ func (m *PingRequest) XXX_DiscardUnknown() { var xxx_messageInfo_PingRequest proto.InternalMessageInfo type PongResponse struct { - FrontendAPICaps []pb1.APICap `protobuf:"bytes,1,rep,name=FrontendAPICaps,proto3" json:"FrontendAPICaps"` - LLBCaps []pb1.APICap `protobuf:"bytes,2,rep,name=LLBCaps,proto3" json:"LLBCaps"` + FrontendAPICaps []pb2.APICap `protobuf:"bytes,1,rep,name=FrontendAPICaps,proto3" json:"FrontendAPICaps"` + LLBCaps []pb2.APICap `protobuf:"bytes,2,rep,name=LLBCaps,proto3" json:"LLBCaps"` Workers []*types1.WorkerRecord `protobuf:"bytes,3,rep,name=Workers,proto3" json:"Workers,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -1658,14 +1667,14 @@ func (m *PongResponse) XXX_DiscardUnknown() { var xxx_messageInfo_PongResponse proto.InternalMessageInfo -func (m *PongResponse) GetFrontendAPICaps() []pb1.APICap { +func (m *PongResponse) GetFrontendAPICaps() []pb2.APICap { if m != nil { return m.FrontendAPICaps } return nil } -func (m *PongResponse) GetLLBCaps() []pb1.APICap { +func (m *PongResponse) GetLLBCaps() []pb2.APICap { if m != nil { return m.LLBCaps } @@ -2618,158 +2627,161 @@ func init() { func init() { proto.RegisterFile("gateway.proto", fileDescriptor_f1a937782ebbded5) } var fileDescriptor_f1a937782ebbded5 = []byte{ - // 2409 bytes of a gzipped FileDescriptorProto + // 2452 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, 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, 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, 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, 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, + 0xf5, 0xd7, 0x8a, 0x14, 0x25, 0x3d, 0x52, 0x14, 0x3d, 0x76, 0xf2, 0xa5, 0x17, 0x81, 0x23, 0xaf, + 0x63, 0x45, 0x56, 0x9c, 0xa5, 0xbf, 0xb2, 0x0d, 0xb9, 0x76, 0xeb, 0xc4, 0xfa, 0x05, 0x29, 0x96, + 0x6c, 0x76, 0xe4, 0xc2, 0x45, 0x90, 0x02, 0x5d, 0x71, 0x87, 0xf4, 0xd6, 0xab, 0xdd, 0xed, 0xee, + 0xd0, 0x32, 0x93, 0x4b, 0x7b, 0x28, 0x50, 0xe4, 0xd4, 0x53, 0x6f, 0x41, 0x81, 0x16, 0xe8, 0xb9, + 0xfd, 0x03, 0xda, 0x73, 0x80, 0x5e, 0x7a, 0xee, 0x21, 0x28, 0xfc, 0x0f, 0xf4, 0x56, 0xa0, 0xb7, + 0xe2, 0xcd, 0xcc, 0x92, 0xc3, 0x1f, 0x5a, 0x92, 0xf5, 0x89, 0x33, 0x6f, 0xde, 0x8f, 0x79, 0xef, + 0xcd, 0x7b, 0xf3, 0x99, 0x25, 0x2c, 0xb5, 0x1c, 0xce, 0xce, 0x9c, 0x8e, 0x1d, 0xc5, 0x21, 0x0f, + 0xc9, 0xe5, 0xd3, 0xf0, 0xa4, 0x63, 0x9f, 0xb4, 0x3d, 0xdf, 0x7d, 0xe9, 0x71, 0xfb, 0xd5, 0xff, + 0xdb, 0xcd, 0x38, 0x0c, 0x38, 0x0b, 0x5c, 0xf3, 0xe3, 0x96, 0xc7, 0x5f, 0xb4, 0x4f, 0xec, 0x46, + 0x78, 0x5a, 0x6b, 0x85, 0xad, 0xb0, 0x26, 0x24, 0x4e, 0xda, 0x4d, 0x31, 0x13, 0x13, 0x31, 0x92, + 0x9a, 0xcc, 0x8d, 0x41, 0xf6, 0x56, 0x18, 0xb6, 0x7c, 0xe6, 0x44, 0x5e, 0xa2, 0x86, 0xb5, 0x38, + 0x6a, 0xd4, 0x12, 0xee, 0xf0, 0x76, 0xa2, 0x64, 0x6e, 0x6a, 0x32, 0xb8, 0x91, 0x5a, 0xba, 0x91, + 0x5a, 0x12, 0xfa, 0xaf, 0x58, 0x5c, 0x8b, 0x4e, 0x6a, 0x61, 0x94, 0x72, 0xd7, 0xce, 0xe5, 0x76, + 0x22, 0xaf, 0xc6, 0x3b, 0x11, 0x4b, 0x6a, 0x67, 0x61, 0xfc, 0x92, 0xc5, 0x4a, 0xe0, 0xf6, 0xb9, + 0x02, 0x6d, 0xee, 0xf9, 0x28, 0xd5, 0x70, 0xa2, 0x04, 0x8d, 0xe0, 0xaf, 0x12, 0xd2, 0xdd, 0xe6, + 0x61, 0xe0, 0x25, 0xdc, 0xf3, 0x5a, 0x5e, 0xad, 0x99, 0x08, 0x19, 0x69, 0x05, 0x9d, 0x50, 0xec, + 0x77, 0x33, 0x5c, 0x68, 0xc7, 0x0d, 0x16, 0x85, 0xbe, 0xd7, 0xe8, 0xa0, 0x0d, 0x39, 0x92, 0x62, + 0xd6, 0xdf, 0xf2, 0x50, 0xa0, 0x2c, 0x69, 0xfb, 0x9c, 0xac, 0xc2, 0x52, 0xcc, 0x9a, 0x3b, 0x2c, + 0x8a, 0x59, 0xc3, 0xe1, 0xcc, 0xad, 0x1a, 0x2b, 0xc6, 0xda, 0xe2, 0xfe, 0x0c, 0xed, 0x27, 0x93, + 0x1f, 0x41, 0x39, 0x66, 0xcd, 0x44, 0x63, 0x9c, 0x5d, 0x31, 0xd6, 0x8a, 0x1b, 0x1f, 0xd9, 0xe7, + 0xe6, 0xd0, 0xa6, 0xac, 0x79, 0xe4, 0x44, 0x3d, 0x91, 0xfd, 0x19, 0x3a, 0xa0, 0x84, 0x6c, 0x40, + 0x2e, 0x66, 0xcd, 0x6a, 0x4e, 0xe8, 0xba, 0x92, 0xad, 0x6b, 0x7f, 0x86, 0x22, 0x33, 0xd9, 0x84, + 0x3c, 0x6a, 0xa9, 0xe6, 0x85, 0xd0, 0xd5, 0xb1, 0x1b, 0xd8, 0x9f, 0xa1, 0x42, 0x80, 0x3c, 0x86, + 0x85, 0x53, 0xc6, 0x1d, 0xd7, 0xe1, 0x4e, 0x15, 0x56, 0x72, 0x6b, 0xc5, 0x8d, 0x5a, 0xa6, 0x30, + 0x06, 0xc8, 0x3e, 0x52, 0x12, 0xbb, 0x01, 0x8f, 0x3b, 0xb4, 0xab, 0x80, 0x3c, 0x87, 0x92, 0xc3, + 0x39, 0xc3, 0x64, 0x78, 0x61, 0x90, 0x54, 0x4b, 0x42, 0xe1, 0xed, 0xf1, 0x0a, 0x1f, 0x69, 0x52, + 0x52, 0x69, 0x9f, 0x22, 0xf3, 0x01, 0x2c, 0xf5, 0xd9, 0x24, 0x15, 0xc8, 0xbd, 0x64, 0x1d, 0x99, + 0x18, 0x8a, 0x43, 0x72, 0x09, 0xe6, 0x5e, 0x39, 0x7e, 0x9b, 0x89, 0x1c, 0x94, 0xa8, 0x9c, 0xdc, + 0x9f, 0xbd, 0x67, 0x98, 0x2f, 0xe0, 0xc2, 0x90, 0xfe, 0x11, 0x0a, 0x7e, 0xa0, 0x2b, 0x28, 0x6e, + 0x7c, 0x98, 0xb1, 0x6b, 0x5d, 0x9d, 0x66, 0x69, 0x6b, 0x01, 0x0a, 0xb1, 0x70, 0xc8, 0xfa, 0xad, + 0x01, 0x95, 0xc1, 0x54, 0x93, 0x03, 0x95, 0x24, 0x43, 0x84, 0xe5, 0xee, 0x14, 0xa7, 0x04, 0x09, + 0x2a, 0x30, 0x42, 0x85, 0xb9, 0x09, 0x8b, 0x5d, 0xd2, 0xb8, 0x60, 0x2c, 0x6a, 0x5b, 0xb4, 0x36, + 0x21, 0x47, 0x59, 0x93, 0x94, 0x61, 0xd6, 0x53, 0xe7, 0x9a, 0xce, 0x7a, 0x2e, 0x59, 0x81, 0x9c, + 0xcb, 0x9a, 0xca, 0xf5, 0xb2, 0x1d, 0x9d, 0xd8, 0x3b, 0xac, 0xe9, 0x05, 0x1e, 0xba, 0x48, 0x71, + 0xc9, 0xfa, 0xbd, 0x81, 0xf5, 0x81, 0xdb, 0x22, 0x9f, 0xf4, 0xf9, 0x31, 0xfe, 0xb4, 0x0f, 0xed, + 0xfe, 0x79, 0xf6, 0xee, 0xef, 0xf4, 0x67, 0x62, 0x4c, 0x09, 0xe8, 0xde, 0xfd, 0x18, 0x4a, 0x7a, + 0x6e, 0xc8, 0x3e, 0x14, 0xb5, 0x73, 0xa4, 0x36, 0xbc, 0x3a, 0x59, 0x66, 0xa9, 0x2e, 0x6a, 0xfd, + 0x31, 0x07, 0x45, 0x6d, 0x91, 0x3c, 0x84, 0xfc, 0x4b, 0x2f, 0x90, 0x21, 0x2c, 0x6f, 0xac, 0x4f, + 0xa6, 0xf2, 0xb1, 0x17, 0xb8, 0x54, 0xc8, 0x91, 0xba, 0x56, 0x77, 0xb3, 0x62, 0x5b, 0x77, 0x26, + 0xd3, 0x71, 0x6e, 0xf1, 0xdd, 0x9a, 0xa2, 0x6d, 0xc8, 0xa6, 0x41, 0x20, 0x1f, 0x39, 0xfc, 0x85, + 0x68, 0x1a, 0x8b, 0x54, 0x8c, 0xc9, 0x2d, 0xb8, 0xe8, 0x05, 0xcf, 0x42, 0x1e, 0xd6, 0x63, 0xe6, + 0x7a, 0x78, 0xf8, 0x9e, 0x75, 0x22, 0x56, 0x9d, 0x13, 0x2c, 0xa3, 0x96, 0x48, 0x1d, 0xca, 0x92, + 0x7c, 0xdc, 0x3e, 0xf9, 0x19, 0x6b, 0xf0, 0xa4, 0x5a, 0x10, 0xfe, 0xac, 0x65, 0x6c, 0xe1, 0x40, + 0x17, 0xa0, 0x03, 0xf2, 0x6f, 0x55, 0xed, 0xd6, 0x9f, 0x0d, 0x58, 0xea, 0x53, 0x4f, 0x3e, 0xed, + 0x4b, 0xd5, 0xcd, 0x49, 0xb7, 0xa5, 0x25, 0xeb, 0x33, 0x28, 0xb8, 0x5e, 0x8b, 0x25, 0x5c, 0xa4, + 0x6a, 0x71, 0x6b, 0xe3, 0xdb, 0xef, 0xde, 0x9f, 0xf9, 0xc7, 0x77, 0xef, 0xaf, 0x6b, 0x57, 0x4d, + 0x18, 0xb1, 0xa0, 0x11, 0x06, 0xdc, 0xf1, 0x02, 0x16, 0xe3, 0x05, 0xfb, 0xb1, 0x14, 0xb1, 0x77, + 0xc4, 0x0f, 0x55, 0x1a, 0x30, 0xe8, 0x81, 0x73, 0xca, 0x44, 0x9e, 0x16, 0xa9, 0x18, 0x5b, 0x1c, + 0x96, 0x28, 0xe3, 0xed, 0x38, 0xa0, 0xec, 0xe7, 0x6d, 0x64, 0xfa, 0x5e, 0xda, 0x48, 0xc4, 0xa6, + 0xc7, 0x35, 0x74, 0x64, 0xa4, 0x4a, 0x80, 0xac, 0xc1, 0x1c, 0x8b, 0xe3, 0x30, 0x56, 0xc5, 0x43, + 0x6c, 0x79, 0xd5, 0xdb, 0x71, 0xd4, 0xb0, 0x8f, 0xc5, 0x55, 0x4f, 0x25, 0x83, 0x55, 0x81, 0x72, + 0x6a, 0x35, 0x89, 0xc2, 0x20, 0x61, 0xd6, 0x32, 0x86, 0x2e, 0x6a, 0xf3, 0x44, 0xed, 0xc3, 0xfa, + 0xab, 0x01, 0xe5, 0x94, 0x22, 0x79, 0xc8, 0x17, 0x50, 0xec, 0xb5, 0x86, 0xb4, 0x07, 0xdc, 0xcf, + 0x0c, 0xaa, 0x2e, 0xaf, 0xf5, 0x15, 0xd5, 0x12, 0x74, 0x75, 0xe6, 0x13, 0xa8, 0x0c, 0x32, 0x8c, + 0xc8, 0xfe, 0x07, 0xfd, 0x0d, 0x62, 0xb0, 0x5f, 0x69, 0xa7, 0xe1, 0x5f, 0x06, 0x5c, 0xa6, 0x4c, + 0x60, 0x97, 0x83, 0x53, 0xa7, 0xc5, 0xb6, 0xc3, 0xa0, 0xe9, 0xb5, 0xd2, 0x30, 0x57, 0x44, 0x33, + 0x4c, 0x35, 0x63, 0x5f, 0x5c, 0x83, 0x85, 0xba, 0xef, 0xf0, 0x66, 0x18, 0x9f, 0x2a, 0xe5, 0x25, + 0x54, 0x9e, 0xd2, 0x68, 0x77, 0x95, 0xac, 0x40, 0x51, 0x29, 0x3e, 0x0a, 0xdd, 0x34, 0x9d, 0x3a, + 0x89, 0x54, 0x61, 0xfe, 0x30, 0x6c, 0x3d, 0xc1, 0x64, 0xcb, 0x0a, 0x4b, 0xa7, 0xc4, 0x82, 0x92, + 0x62, 0x8c, 0xbb, 0xd5, 0x35, 0x47, 0xfb, 0x68, 0xe4, 0x3d, 0x58, 0x3c, 0x66, 0x49, 0xe2, 0x85, + 0xc1, 0xc1, 0x4e, 0xb5, 0x20, 0xe4, 0x7b, 0x04, 0xd4, 0x7d, 0xcc, 0xc3, 0x98, 0x1d, 0xec, 0x54, + 0xe7, 0xa5, 0x6e, 0x35, 0xb5, 0x7e, 0x61, 0x80, 0x39, 0xca, 0x63, 0x95, 0xbe, 0xcf, 0xa0, 0x20, + 0x0f, 0xa4, 0xf4, 0xfa, 0x7f, 0x3b, 0xca, 0xf2, 0x97, 0xbc, 0x0b, 0x05, 0xa9, 0x5d, 0x55, 0xa1, + 0x9a, 0x59, 0xbf, 0x2a, 0x40, 0xe9, 0x18, 0x37, 0x90, 0xc6, 0xd9, 0x06, 0xe8, 0xa5, 0x47, 0x1d, + 0xe9, 0xc1, 0xa4, 0x69, 0x1c, 0xc4, 0x84, 0x85, 0x3d, 0x75, 0x7c, 0xd4, 0x0d, 0xd6, 0x9d, 0x93, + 0xcf, 0xa1, 0x98, 0x8e, 0x9f, 0x46, 0xbc, 0x9a, 0x13, 0xe7, 0xef, 0x5e, 0xc6, 0xf9, 0xd3, 0x77, + 0x62, 0x6b, 0xa2, 0xea, 0xf4, 0x69, 0x14, 0x72, 0x13, 0x2e, 0x38, 0xbe, 0x1f, 0x9e, 0xa9, 0x92, + 0x12, 0xc5, 0x21, 0x92, 0xb3, 0x40, 0x87, 0x17, 0xb0, 0x55, 0x6a, 0xc4, 0x47, 0x71, 0xec, 0x74, + 0xf0, 0x34, 0x15, 0x04, 0xff, 0xa8, 0x25, 0xec, 0x5a, 0x7b, 0x5e, 0xe0, 0xf8, 0x55, 0x10, 0x3c, + 0x72, 0x82, 0xa7, 0x61, 0xf7, 0x75, 0x14, 0xc6, 0x9c, 0xc5, 0x8f, 0x38, 0x8f, 0xab, 0x45, 0x11, + 0xcc, 0x3e, 0x1a, 0xa9, 0x43, 0x69, 0xdb, 0x69, 0xbc, 0x60, 0x07, 0xa7, 0x48, 0x4c, 0x91, 0x55, + 0x56, 0x2f, 0x13, 0xec, 0x4f, 0x23, 0x1d, 0x52, 0xe9, 0x1a, 0x48, 0x03, 0xca, 0xa9, 0xeb, 0xb2, + 0x42, 0xab, 0x4b, 0x42, 0xe7, 0x83, 0x69, 0x43, 0x29, 0xa5, 0xa5, 0x89, 0x01, 0x95, 0x98, 0xc8, + 0x5d, 0x2c, 0x46, 0x87, 0xb3, 0x6a, 0x59, 0xf8, 0xdc, 0x9d, 0x93, 0x23, 0x28, 0x1f, 0x0b, 0x40, + 0x5e, 0x47, 0x18, 0xee, 0xb1, 0xa4, 0xba, 0x2c, 0x36, 0x70, 0x7d, 0x78, 0x03, 0x3a, 0x70, 0xb7, + 0x05, 0x7b, 0x87, 0x0e, 0x08, 0x9b, 0x0f, 0xa1, 0x32, 0x98, 0xdc, 0x69, 0x80, 0x91, 0xf9, 0x43, + 0xb8, 0x38, 0xc2, 0xa3, 0xb7, 0x6a, 0x3e, 0x7f, 0x32, 0xe0, 0xc2, 0x50, 0x1a, 0xf0, 0x02, 0x10, + 0x45, 0x2f, 0x55, 0x8a, 0x31, 0x39, 0x82, 0x39, 0x4c, 0x73, 0xa2, 0xa0, 0xc0, 0xe6, 0x34, 0x79, + 0xb5, 0x85, 0xa4, 0x8c, 0xbf, 0xd4, 0x62, 0xde, 0x03, 0xe8, 0x11, 0xa7, 0x82, 0x87, 0x5f, 0xc0, + 0x92, 0x4a, 0xb2, 0xea, 0x17, 0x15, 0x89, 0x2a, 0x94, 0x30, 0xa2, 0x86, 0xde, 0xdd, 0x94, 0x9b, + 0xf2, 0x6e, 0xb2, 0xbe, 0x82, 0x65, 0xca, 0x1c, 0x77, 0xcf, 0xf3, 0xd9, 0xf9, 0x2d, 0x18, 0x8b, + 0xdf, 0xf3, 0x59, 0x1d, 0x91, 0x49, 0x5a, 0xfc, 0x6a, 0x4e, 0xee, 0xc3, 0x1c, 0x75, 0x82, 0x16, + 0x53, 0xa6, 0x3f, 0xc8, 0x30, 0x2d, 0x8c, 0x20, 0x2f, 0x95, 0x22, 0xd6, 0x03, 0x58, 0xec, 0xd2, + 0xb0, 0x75, 0x3d, 0x6d, 0x36, 0x13, 0x26, 0xdb, 0x60, 0x8e, 0xaa, 0x19, 0xd2, 0x0f, 0x59, 0xd0, + 0x52, 0xa6, 0x73, 0x54, 0xcd, 0xac, 0x55, 0x84, 0xf3, 0xe9, 0xce, 0x55, 0x68, 0x08, 0xe4, 0x77, + 0x10, 0xbe, 0x19, 0xa2, 0x5e, 0xc5, 0xd8, 0x72, 0xf1, 0x4e, 0x75, 0xdc, 0x1d, 0x2f, 0x3e, 0xdf, + 0xc1, 0x2a, 0xcc, 0xef, 0x78, 0xb1, 0xe6, 0x5f, 0x3a, 0x25, 0xab, 0x78, 0xdb, 0x36, 0xfc, 0xb6, + 0x8b, 0xde, 0x72, 0x16, 0x07, 0xea, 0x5a, 0x19, 0xa0, 0x5a, 0x9f, 0xc8, 0x38, 0x0a, 0x2b, 0x6a, + 0x33, 0x37, 0x61, 0x9e, 0x05, 0x3c, 0xc6, 0x32, 0x92, 0x57, 0x32, 0xb1, 0xe5, 0x03, 0xd9, 0x16, + 0x0f, 0x64, 0x71, 0xf5, 0xd3, 0x94, 0xc5, 0xda, 0x84, 0x65, 0x24, 0x64, 0x27, 0x82, 0x40, 0x5e, + 0xdb, 0xa4, 0x18, 0x5b, 0xf7, 0xa1, 0xd2, 0x13, 0x54, 0xa6, 0x57, 0x21, 0x8f, 0xd8, 0x54, 0xf5, + 0xf5, 0x51, 0x76, 0xc5, 0xba, 0x75, 0x0d, 0x96, 0xd3, 0xe2, 0x3f, 0xd7, 0xa8, 0x45, 0xa0, 0xd2, + 0x63, 0x52, 0xb0, 0x64, 0x09, 0x8a, 0x75, 0x2f, 0x48, 0x6f, 0x6d, 0xeb, 0x8d, 0x01, 0xa5, 0x7a, + 0x18, 0xf4, 0xee, 0xb4, 0x3a, 0x2c, 0xa7, 0xa5, 0xfb, 0xa8, 0x7e, 0xb0, 0xed, 0x44, 0x69, 0x0c, + 0x56, 0x86, 0xcf, 0x87, 0xfa, 0xc4, 0x60, 0x4b, 0xc6, 0xad, 0x3c, 0x5e, 0x7f, 0x74, 0x50, 0x9c, + 0x7c, 0x0a, 0xf3, 0x87, 0x87, 0x5b, 0x42, 0xd3, 0xec, 0x54, 0x9a, 0x52, 0x31, 0xf2, 0x10, 0xe6, + 0x9f, 0x8b, 0x2f, 0x1f, 0x89, 0xba, 0xa2, 0x46, 0x9c, 0x55, 0x19, 0x21, 0xc9, 0x46, 0x59, 0x23, + 0x8c, 0x5d, 0x9a, 0x0a, 0x59, 0xff, 0x36, 0xa0, 0xf8, 0xdc, 0xe9, 0x21, 0xc2, 0x1e, 0x04, 0x7d, + 0x8b, 0x7b, 0x5b, 0x41, 0xd0, 0x4b, 0x30, 0xe7, 0xb3, 0x57, 0xcc, 0x57, 0x67, 0x5c, 0x4e, 0x90, + 0x9a, 0xbc, 0x08, 0x63, 0x59, 0xd6, 0x25, 0x2a, 0x27, 0x58, 0x10, 0x2e, 0xe3, 0x8e, 0xe7, 0x57, + 0xf3, 0x2b, 0x39, 0xbc, 0xe3, 0xe5, 0x0c, 0x33, 0xd7, 0x8e, 0x7d, 0xf5, 0x2e, 0xc0, 0x21, 0xb1, + 0x20, 0xef, 0x05, 0xcd, 0x50, 0xdc, 0x7f, 0xaa, 0x2d, 0xca, 0x16, 0x7d, 0x10, 0x34, 0x43, 0x2a, + 0xd6, 0xc8, 0x55, 0x28, 0xc4, 0x58, 0x7f, 0x49, 0x75, 0x5e, 0x04, 0x65, 0x11, 0xb9, 0x64, 0x95, + 0xaa, 0x05, 0xab, 0x0c, 0x25, 0xe9, 0xb7, 0x4a, 0xfe, 0x6f, 0x66, 0xe1, 0xe2, 0x13, 0x76, 0xb6, + 0x9d, 0xfa, 0x95, 0x06, 0x64, 0x05, 0x8a, 0x5d, 0xda, 0xc1, 0x8e, 0x3a, 0x42, 0x3a, 0x09, 0x8d, + 0x1d, 0x85, 0xed, 0x80, 0xa7, 0x39, 0x14, 0xc6, 0x04, 0x85, 0xaa, 0x05, 0x72, 0x1d, 0xe6, 0x9f, + 0x30, 0x7e, 0x16, 0xc6, 0x2f, 0x85, 0xd7, 0xe5, 0x8d, 0x22, 0xf2, 0x3c, 0x61, 0x1c, 0x01, 0x1c, + 0x4d, 0xd7, 0x10, 0x15, 0x46, 0x29, 0x2a, 0xcc, 0x8f, 0x42, 0x85, 0xe9, 0x2a, 0xd9, 0x84, 0x62, + 0x23, 0x0c, 0x12, 0x1e, 0x3b, 0x1e, 0x1a, 0x9e, 0x13, 0xcc, 0xef, 0x20, 0xb3, 0x4c, 0xec, 0x76, + 0x6f, 0x91, 0xea, 0x9c, 0x64, 0x1d, 0x80, 0xbd, 0xe6, 0xb1, 0xb3, 0x1f, 0x26, 0xdd, 0x17, 0x14, + 0xa0, 0x1c, 0x12, 0x0e, 0xea, 0x54, 0x5b, 0xb5, 0xde, 0x85, 0x4b, 0xfd, 0x11, 0x51, 0xa1, 0x7a, + 0x00, 0xff, 0x47, 0x99, 0xcf, 0x9c, 0x84, 0x4d, 0x1f, 0x2d, 0xcb, 0x84, 0xea, 0xb0, 0xb0, 0x52, + 0xfc, 0x9f, 0x1c, 0x14, 0x77, 0x5f, 0xb3, 0xc6, 0x11, 0x4b, 0x12, 0xa7, 0x25, 0xb0, 0x69, 0x3d, + 0x0e, 0x1b, 0x2c, 0x49, 0xba, 0xba, 0x7a, 0x04, 0xf2, 0x7d, 0xc8, 0x1f, 0x04, 0x1e, 0x57, 0xf7, + 0xe3, 0x6a, 0xe6, 0xd3, 0xc0, 0xe3, 0x4a, 0xe7, 0xfe, 0x0c, 0x15, 0x52, 0xe4, 0x3e, 0xe4, 0xb1, + 0xbb, 0x4c, 0xd2, 0xe1, 0x5d, 0x4d, 0x16, 0x65, 0xc8, 0x96, 0xf8, 0x84, 0xe7, 0x7d, 0xc9, 0x54, + 0x96, 0xd6, 0xb2, 0xaf, 0x26, 0xef, 0x4b, 0xd6, 0xd3, 0xa0, 0x24, 0xc9, 0x2e, 0x22, 0x6b, 0x27, + 0xe6, 0xcc, 0x55, 0xd9, 0xbb, 0x91, 0x05, 0x88, 0x24, 0x67, 0x4f, 0x4b, 0x2a, 0x8b, 0x41, 0xd8, + 0x7d, 0xed, 0x71, 0x55, 0x0d, 0x59, 0x41, 0x40, 0x36, 0xcd, 0x11, 0x9c, 0xa2, 0xf4, 0x4e, 0x18, + 0x30, 0x81, 0xed, 0xb3, 0xa5, 0x91, 0x4d, 0x93, 0xc6, 0x29, 0x86, 0xe1, 0xd8, 0x6b, 0x21, 0xce, + 0x5c, 0x18, 0x1b, 0x06, 0xc9, 0xa8, 0x85, 0x41, 0x12, 0xb6, 0xe6, 0x61, 0x4e, 0xc0, 0x20, 0xeb, + 0x77, 0x06, 0x14, 0xb5, 0x3c, 0x4d, 0x50, 0x77, 0xef, 0x41, 0x1e, 0x9f, 0xef, 0x2a, 0xff, 0x0b, + 0xa2, 0xea, 0x18, 0x77, 0xa8, 0xa0, 0x62, 0xe3, 0xd8, 0x73, 0x65, 0x53, 0x5c, 0xa2, 0x38, 0x44, + 0xca, 0x33, 0xde, 0x11, 0x29, 0x5b, 0xa0, 0x38, 0x24, 0x37, 0x61, 0xe1, 0x98, 0x35, 0xda, 0xb1, + 0xc7, 0x3b, 0x22, 0x09, 0xe5, 0x8d, 0x8a, 0x68, 0x27, 0x8a, 0x26, 0x8a, 0xb3, 0xcb, 0x61, 0x3d, + 0xc6, 0xc3, 0xd9, 0xdb, 0x20, 0x81, 0xfc, 0x36, 0xbe, 0xc8, 0x70, 0x67, 0x4b, 0x54, 0x8c, 0xf1, + 0x51, 0xbc, 0x3b, 0xee, 0x51, 0xbc, 0x9b, 0x3e, 0x8a, 0xfb, 0x93, 0x8a, 0xb7, 0x8f, 0x16, 0x64, + 0xeb, 0x11, 0x2c, 0x76, 0x0f, 0x1e, 0x29, 0xc3, 0xec, 0x9e, 0xab, 0x2c, 0xcd, 0xee, 0xb9, 0xe8, + 0xca, 0xee, 0xd3, 0x3d, 0x61, 0x65, 0x81, 0xe2, 0xb0, 0x0b, 0x12, 0x72, 0x1a, 0x48, 0xd8, 0xc4, + 0xe7, 0xbe, 0x76, 0xfa, 0x90, 0x89, 0x86, 0x67, 0x49, 0xba, 0x65, 0x1c, 0x4b, 0x37, 0xfc, 0x44, + 0xe8, 0x12, 0x6e, 0xf8, 0x89, 0x75, 0x0d, 0x96, 0xfa, 0xf2, 0x85, 0x4c, 0xe2, 0x7d, 0xa9, 0xb0, + 0x24, 0x8e, 0xd7, 0x19, 0x2c, 0x0f, 0x7c, 0x72, 0x22, 0xd7, 0xa1, 0x20, 0x3f, 0x6d, 0x54, 0x66, + 0xcc, 0xcb, 0x5f, 0x7f, 0xb3, 0xf2, 0xce, 0x00, 0x83, 0x5c, 0x44, 0xb6, 0xad, 0x76, 0xe0, 0xfa, + 0xac, 0x62, 0x8c, 0x64, 0x93, 0x8b, 0x66, 0xfe, 0xd7, 0x7f, 0xb8, 0x32, 0xb3, 0xee, 0xc0, 0x85, + 0xa1, 0xcf, 0x25, 0xe4, 0x1a, 0xe4, 0x8f, 0x99, 0xdf, 0x4c, 0xcd, 0x0c, 0x31, 0xe0, 0x22, 0xb9, + 0x0a, 0x39, 0xea, 0x9c, 0x55, 0x0c, 0xb3, 0xfa, 0xf5, 0x37, 0x2b, 0x97, 0x86, 0xbf, 0xb9, 0x38, + 0x67, 0xd2, 0xc4, 0xc6, 0x5f, 0x00, 0x16, 0x0f, 0x0f, 0xb7, 0xb6, 0x62, 0xcf, 0x6d, 0x31, 0xf2, + 0x4b, 0x03, 0xc8, 0xf0, 0xc3, 0x96, 0xdc, 0xc9, 0xae, 0xf1, 0xd1, 0x2f, 0x7f, 0xf3, 0xee, 0x94, + 0x52, 0x0a, 0x69, 0x7c, 0x0e, 0x73, 0x02, 0x1e, 0x93, 0x0f, 0x27, 0x7c, 0x25, 0x99, 0x6b, 0xe3, + 0x19, 0x95, 0xee, 0x06, 0x2c, 0xa4, 0x10, 0x93, 0xac, 0x67, 0x6e, 0xaf, 0x0f, 0x41, 0x9b, 0x1f, + 0x4d, 0xc4, 0xab, 0x8c, 0xfc, 0x14, 0xe6, 0x15, 0x72, 0x24, 0x37, 0xc6, 0xc8, 0xf5, 0x30, 0xac, + 0xb9, 0x3e, 0x09, 0x6b, 0xcf, 0x8d, 0x14, 0x21, 0x66, 0xba, 0x31, 0x80, 0x3f, 0x33, 0xdd, 0x18, + 0x82, 0x9c, 0x8d, 0xde, 0xbb, 0x32, 0xd3, 0xc8, 0x00, 0xde, 0xcc, 0x34, 0x32, 0x08, 0x3b, 0xc9, + 0x73, 0xc8, 0x23, 0xec, 0x24, 0x59, 0xed, 0x57, 0xc3, 0xa5, 0x66, 0xd6, 0x99, 0xe8, 0xc3, 0xab, + 0x3f, 0xc1, 0x6b, 0x4a, 0x7c, 0x42, 0xc8, 0xbe, 0xa0, 0xb4, 0x2f, 0x82, 0xe6, 0x8d, 0x09, 0x38, + 0x7b, 0xea, 0xd5, 0xf3, 0x7b, 0x6d, 0x82, 0xcf, 0x72, 0xe3, 0xd5, 0x0f, 0x7c, 0x00, 0x0c, 0xa1, + 0xa4, 0xa3, 0x0f, 0x62, 0x67, 0x88, 0x8e, 0x00, 0x6e, 0x66, 0x6d, 0x62, 0x7e, 0x65, 0xf0, 0x2b, + 0x7c, 0x7b, 0xf5, 0x23, 0x13, 0xb2, 0x91, 0x19, 0x8e, 0x91, 0x18, 0xc8, 0xbc, 0x3d, 0x95, 0x8c, + 0x32, 0xee, 0x48, 0xe4, 0xa3, 0xd0, 0x0d, 0xc9, 0xbe, 0xc8, 0xbb, 0x08, 0xc9, 0x9c, 0x90, 0x6f, + 0xcd, 0xb8, 0x65, 0xe0, 0x39, 0x43, 0xc4, 0x9b, 0xa9, 0x5b, 0x7b, 0x0a, 0x64, 0x9e, 0x33, 0x1d, + 0x3a, 0x6f, 0x95, 0xbe, 0x7d, 0x73, 0xc5, 0xf8, 0xfb, 0x9b, 0x2b, 0xc6, 0x3f, 0xdf, 0x5c, 0x31, + 0x4e, 0x0a, 0xe2, 0x7f, 0xce, 0xdb, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xc4, 0x91, 0xe5, 0xca, + 0x70, 0x1e, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -4122,6 +4134,20 @@ func (m *SolveRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.SourcePolicies) > 0 { + for iNdEx := len(m.SourcePolicies) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.SourcePolicies[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGateway(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x7a + } + } if m.Evaluate { i-- if m.Evaluate { @@ -6015,6 +6041,12 @@ func (m *SolveRequest) Size() (n int) { if m.Evaluate { n += 2 } + if len(m.SourcePolicies) > 0 { + for _, e := range m.SourcePolicies { + l = e.Size() + n += 1 + l + sovGateway(uint64(l)) + } + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -9408,6 +9440,40 @@ func (m *SolveRequest) Unmarshal(dAtA []byte) error { } } m.Evaluate = bool(v != 0) + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SourcePolicies", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGateway + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGateway + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGateway + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SourcePolicies = append(m.SourcePolicies, &pb1.Policy{}) + if err := m.SourcePolicies[len(m.SourcePolicies)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGateway(dAtA[iNdEx:]) @@ -10761,7 +10827,7 @@ func (m *PongResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.FrontendAPICaps = append(m.FrontendAPICaps, pb1.APICap{}) + m.FrontendAPICaps = append(m.FrontendAPICaps, pb2.APICap{}) if err := m.FrontendAPICaps[len(m.FrontendAPICaps)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -10795,7 +10861,7 @@ func (m *PongResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.LLBCaps = append(m.LLBCaps, pb1.APICap{}) + m.LLBCaps = append(m.LLBCaps, pb2.APICap{}) if err := m.LLBCaps[len(m.LLBCaps)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/frontend/gateway/pb/gateway.proto b/frontend/gateway/pb/gateway.proto index 6fd3a9ae9..2e55f1db8 100644 --- a/frontend/gateway/pb/gateway.proto +++ b/frontend/gateway/pb/gateway.proto @@ -8,6 +8,7 @@ import "github.com/moby/buildkit/solver/pb/ops.proto"; import "github.com/moby/buildkit/api/types/worker.proto"; import "github.com/moby/buildkit/util/apicaps/pb/caps.proto"; import "github.com/tonistiigi/fsutil/types/stat.proto"; +import "github.com/moby/buildkit/sourcepolicy/pb/policy.proto"; option (gogoproto.sizer_all) = true; @@ -149,6 +150,8 @@ message SolveRequest { map FrontendInputs = 13; bool Evaluate = 14; + + repeated moby.buildkit.v1.sourcepolicy.Policy SourcePolicies = 15; } // CacheOptionsEntry corresponds to the control.CacheOptionsEntry diff --git a/solver/llbsolver/bridge.go b/solver/llbsolver/bridge.go index d79aefb8d..d69abe25f 100644 --- a/solver/llbsolver/bridge.go +++ b/solver/llbsolver/bridge.go @@ -21,6 +21,7 @@ import ( "github.com/moby/buildkit/solver/llbsolver/provenance" "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/sourcepolicy" + spb "github.com/moby/buildkit/sourcepolicy/pb" "github.com/moby/buildkit/util/bklog" "github.com/moby/buildkit/util/flightcontrol" "github.com/moby/buildkit/util/progress" @@ -63,7 +64,7 @@ func (b *llbBridge) Warn(ctx context.Context, dgst digest.Digest, msg string, op }) } -func (b *llbBridge) loadResult(ctx context.Context, def *pb.Definition, cacheImports []gw.CacheOptionsEntry) (solver.CachedResultWithProvenance, error) { +func (b *llbBridge) loadResult(ctx context.Context, def *pb.Definition, cacheImports []gw.CacheOptionsEntry, pol []*spb.Policy) (solver.CachedResultWithProvenance, error) { w, err := b.resolveWorker() if err != nil { return nil, err @@ -77,8 +78,12 @@ func (b *llbBridge) loadResult(ctx context.Context, def *pb.Definition, cacheImp return nil, err } var polEngine SourcePolicyEvaluator - if srcPol != nil { - polEngine = sourcepolicy.NewEngine(srcPol, sourcepolicy.MatcherFn(sourcepolicy.Match), sourcepolicy.MutateFn(sourcepolicy.Mutate)) + if srcPol != nil || len(pol) > 0 { + if srcPol != nil { + pol = append([]*spb.Policy{srcPol}, pol...) + } + + polEngine = sourcepolicy.NewEngine(pol, sourcepolicy.MatcherFn(sourcepolicy.Match), sourcepolicy.MutateFn(sourcepolicy.Mutate)) if err != nil { return nil, err } @@ -219,7 +224,7 @@ func (rp *resultProxy) wrapError(err error) error { } func (rp *resultProxy) loadResult(ctx context.Context) (solver.CachedResultWithProvenance, error) { - res, err := rp.b.loadResult(ctx, rp.req.Definition, rp.req.CacheImports) + res, err := rp.b.loadResult(ctx, rp.req.Definition, rp.req.CacheImports, rp.req.SourcePolicies) var ee *llberrdefs.ExecError if errors.As(err, &ee) { ee.EachRef(func(res solver.Result) error { diff --git a/solver/llbsolver/solver.go b/solver/llbsolver/solver.go index 3ec4f1b5f..e628adc34 100644 --- a/solver/llbsolver/solver.go +++ b/solver/llbsolver/solver.go @@ -26,7 +26,7 @@ import ( "github.com/moby/buildkit/solver" "github.com/moby/buildkit/solver/llbsolver/provenance" "github.com/moby/buildkit/solver/result" - sourcepolicypb "github.com/moby/buildkit/sourcepolicy/pb" + spb "github.com/moby/buildkit/sourcepolicy/pb" "github.com/moby/buildkit/util/attestation" "github.com/moby/buildkit/util/buildinfo" "github.com/moby/buildkit/util/compression" @@ -385,7 +385,7 @@ func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend }, nil } -func (s *Solver) Solve(ctx context.Context, id string, sessionID string, req frontend.SolveRequest, exp ExporterRequest, ent []entitlements.Entitlement, post []Processor, internal bool, srcPol *sourcepolicypb.Policy) (_ *client.SolveResponse, err error) { +func (s *Solver) Solve(ctx context.Context, id string, sessionID string, req frontend.SolveRequest, exp ExporterRequest, ent []entitlements.Entitlement, post []Processor, internal bool, srcPol *spb.Policy) (_ *client.SolveResponse, err error) { j, err := s.solver.NewJob(id) if err != nil { return nil, err @@ -953,10 +953,10 @@ func loadEntitlements(b solver.Builder) (entitlements.Set, error) { return ent, nil } -func loadSourcePolicy(b solver.Builder) (*sourcepolicypb.Policy, error) { - set := make(map[sourcepolicypb.Rule]struct{}, 0) +func loadSourcePolicy(b solver.Builder) (*spb.Policy, error) { + set := make(map[spb.Rule]struct{}, 0) err := b.EachValue(context.TODO(), keySourcePolicy, func(v interface{}) error { - x, ok := v.(sourcepolicypb.Policy) + x, ok := v.(spb.Policy) if !ok { return errors.Errorf("invalid source policy %T", v) } @@ -968,9 +968,9 @@ func loadSourcePolicy(b solver.Builder) (*sourcepolicypb.Policy, error) { if err != nil { return nil, err } - var srcPol *sourcepolicypb.Policy + var srcPol *spb.Policy if len(set) > 0 { - srcPol = &sourcepolicypb.Policy{} + srcPol = &spb.Policy{} for k := range set { k := k srcPol.Rules = append(srcPol.Rules, &k) diff --git a/sourcepolicy/engine.go b/sourcepolicy/engine.go index e10035eb8..b63c4dd81 100644 --- a/sourcepolicy/engine.go +++ b/sourcepolicy/engine.go @@ -25,14 +25,14 @@ var ( // Rule matching is delegated to the `Matcher` interface. // Mutations are delegated to the `Mutater` interface. type Engine struct { - pol *spb.Policy + pol []*spb.Policy matcher Matcher mutater Mutater sources map[string]*Source } // NewEngine creates a new source policy engine. -func NewEngine(pol *spb.Policy, matcher Matcher, mutater Mutater) *Engine { +func NewEngine(pol []*spb.Policy, matcher Matcher, mutater Mutater) *Engine { if matcher == nil { matcher = DefaultMatcher } @@ -71,7 +71,7 @@ func (e *Engine) source(src *spb.Source) *Source { // // An error is returned when the source is denied by the policy. func (e *Engine) Evaluate(ctx context.Context, op *pb.Op) (bool, error) { - if len(e.pol.Rules) == 0 { + if len(e.pol) == 0 { return false, nil } @@ -94,7 +94,7 @@ func (e *Engine) Evaluate(ctx context.Context, op *pb.Op) (bool, error) { ctx = bklog.WithLogger(ctx, bklog.G(ctx).WithField("orig", *srcOp).WithField("updated", op.GetSource())) } - mut, err := e.evaluateRules(ctx, srcOp, &st) + mut, err := e.evaluatePolicies(ctx, srcOp, &st) if mut { mutated = true } @@ -109,7 +109,7 @@ func (e *Engine) Evaluate(ctx context.Context, op *pb.Op) (bool, error) { return mutated, nil } -func (e *Engine) evaluateRules(ctx context.Context, srcOp *pb.SourceOp, st *evalState) (bool, error) { +func (e *Engine) evaluatePolicies(ctx context.Context, srcOp *pb.SourceOp, st *evalState) (bool, error) { ident := srcOp.GetIdentifier() scheme, ref, found := strings.Cut(ident, "://") if !found || ref == "" { @@ -121,13 +121,20 @@ func (e *Engine) evaluateRules(ctx context.Context, srcOp *pb.SourceOp, st *eval "ref": ref, })) - for _, rule := range e.pol.Rules { - mut, err := e.evaluateRule(ctx, rule, scheme, ref, srcOp, st) - if err != nil { - return false, err + for _, pol := range e.pol { + mut, err := e.evaluatePolicy(ctx, pol, srcOp, st, scheme, ref) + if mut || err != nil { + return mut, err } - if mut { - return true, nil + } + return false, nil +} + +func (e *Engine) evaluatePolicy(ctx context.Context, pol *spb.Policy, srcOp *pb.SourceOp, st *evalState, scheme, ref string) (bool, error) { + for _, rule := range pol.Rules { + mut, err := e.evaluateRule(ctx, rule, scheme, ref, srcOp, st) + if mut || err != nil { + return mut, err } } return false, nil diff --git a/sourcepolicy/engine_test.go b/sourcepolicy/engine_test.go index a39114a71..c4b53aec8 100644 --- a/sourcepolicy/engine_test.go +++ b/sourcepolicy/engine_test.go @@ -26,39 +26,41 @@ func TestEngineEvaluate(t *testing.T) { } func testConvertMultiple(t *testing.T) { - pol := &spb.Policy{ - Rules: []*spb.Rule{ - { - Action: spb.PolicyAction_CONVERT, - Source: &spb.Source{ - Type: "docker-image", - Identifier: "docker.io/library/busybox:latest", + pol := []*spb.Policy{ + { + Rules: []*spb.Rule{ + { + Action: spb.PolicyAction_CONVERT, + Source: &spb.Source{ + Type: "docker-image", + Identifier: "docker.io/library/busybox:latest", + }, + Destination: &spb.Destination{ + Type: "docker-image", + Identifier: "docker.io/library/alpine:latest", + }, }, - Destination: &spb.Destination{ - Type: "docker-image", - Identifier: "docker.io/library/alpine:latest", + { + Action: spb.PolicyAction_CONVERT, + Source: &spb.Source{ + Type: "docker-image", + Identifier: "docker.io/library/alpine:latest", + }, + Destination: &spb.Destination{ + Type: "docker-image", + Identifier: "docker.io/library/debian:buster", + }, }, - }, - { - Action: spb.PolicyAction_CONVERT, - Source: &spb.Source{ - Type: "docker-image", - Identifier: "docker.io/library/alpine:latest", - }, - Destination: &spb.Destination{ - Type: "docker-image", - Identifier: "docker.io/library/debian:buster", - }, - }, - { - Action: spb.PolicyAction_CONVERT, - Source: &spb.Source{ - Type: "docker-image", - Identifier: "docker.io/library/debian:buster", - }, - Destination: &spb.Destination{ - Type: "docker-image", - Identifier: "docker.io/library/debian:bullseye", + { + Action: spb.PolicyAction_CONVERT, + Source: &spb.Source{ + Type: "docker-image", + Identifier: "docker.io/library/debian:buster", + }, + Destination: &spb.Destination{ + Type: "docker-image", + Identifier: "docker.io/library/debian:bullseye", + }, }, }, }, @@ -81,18 +83,20 @@ func testConvertMultiple(t *testing.T) { } func testConvertWildcard(t *testing.T) { - pol := &spb.Policy{ - Rules: []*spb.Rule{ - { - Action: spb.PolicyAction_CONVERT, - Source: &spb.Source{ - Type: "docker-image", - Identifier: `docker.io/library/golang:*`, - MatchType: spb.MatchType_WILDCARD, - }, - Destination: &spb.Destination{ - Type: "docker-image", - Identifier: "fakereg.io/library/golang:${1}", + pol := []*spb.Policy{ + { + Rules: []*spb.Rule{ + { + Action: spb.PolicyAction_CONVERT, + Source: &spb.Source{ + Type: "docker-image", + Identifier: `docker.io/library/golang:*`, + MatchType: spb.MatchType_WILDCARD, + }, + Destination: &spb.Destination{ + Type: "docker-image", + Identifier: "fakereg.io/library/golang:${1}", + }, }, }, }, @@ -142,7 +146,7 @@ func testConvertRegex(t *testing.T) { } ctx := context.Background() - e := NewEngine(pol, nil, nil) + e := NewEngine([]*spb.Policy{pol}, nil, nil) mutated, err := e.Evaluate(ctx, op) require.True(t, mutated) @@ -175,7 +179,7 @@ func testConvertHTTP(t *testing.T) { } ctx := context.Background() - e := NewEngine(pol, nil, nil) + e := NewEngine([]*spb.Policy{pol}, nil, nil) mutated, err := e.Evaluate(ctx, op) require.True(t, mutated) @@ -220,7 +224,7 @@ func testConvertLoop(t *testing.T) { } ctx := context.Background() - e := NewEngine(pol, nil, nil) + e := NewEngine([]*spb.Policy{pol}, nil, nil) mutated, err := e.Evaluate(ctx, op) require.True(t, mutated) @@ -274,7 +278,7 @@ func testAllowConvertDeny(t *testing.T) { } ctx := context.Background() - e := NewEngine(pol, nil, nil) + e := NewEngine([]*spb.Policy{pol}, nil, nil) mutated, err := e.Evaluate(ctx, op) require.True(t, mutated) @@ -315,7 +319,7 @@ func testConvertDeny(t *testing.T) { } ctx := context.Background() - e := NewEngine(pol, nil, nil) + e := NewEngine([]*spb.Policy{pol}, nil, nil) mutated, err := e.Evaluate(ctx, op) require.True(t, mutated) @@ -359,7 +363,7 @@ func testConvert(t *testing.T) { } ctx := context.Background() - e := NewEngine(pol, nil, nil) + e := NewEngine([]*spb.Policy{pol}, nil, nil) mutated, err := e.Evaluate(ctx, op) require.True(t, mutated) @@ -397,7 +401,7 @@ func testAllowDeny(t *testing.T) { } ctx := context.Background() - e := NewEngine(pol, nil, nil) + e := NewEngine([]*spb.Policy{pol}, nil, nil) mutated, err := e.Evaluate(ctx, op) require.False(t, mutated) @@ -437,7 +441,7 @@ func testDenyAll(t *testing.T) { }, } - e := NewEngine(pol, nil, nil) + e := NewEngine([]*spb.Policy{pol}, nil, nil) ctx := context.Background() op := &pb.Op{