From 31a4f2029109222bc6770e0ec63f6db310c8334b Mon Sep 17 00:00:00 2001 From: Ryan Currah Date: Fri, 17 May 2024 13:28:17 -0400 Subject: [PATCH] feat(eventsources/bitbucketserver): add OneEventPerChange config option for webhook event handling Add OneEventPerChange config option to control whether to process each change in a repo:refs_changed webhook event as a separate event. This allows independent processing of each tag or reference update in a single webhook event useful for triggering distinct workflows in Argo Workflows. Signed-off-by: Ryan Currah --- api/event-source.html | 19 +- api/event-source.md | 24 +- api/jsonschema/schema.json | 18 +- api/openapi-spec/swagger.json | 18 +- .../bitbucketserver/bitbucketserverclients.go | 148 +++ .../custombitbucketserverclient.go | 117 +++ eventsources/sources/bitbucketserver/start.go | 735 ++++++------- eventsources/sources/bitbucketserver/types.go | 6 +- .../sources/bitbucketserver/validate.go | 3 - .../sources/bitbucketserver/validate_test.go | 4 +- go.mod | 2 +- pkg/apis/eventsource/v1alpha1/generated.pb.go | 978 +++++++++--------- pkg/apis/eventsource/v1alpha1/generated.proto | 27 +- .../eventsource/v1alpha1/openapi_generated.go | 9 +- pkg/apis/eventsource/v1alpha1/types.go | 31 +- pkg/apis/eventsource/v1alpha1/types_test.go | 91 ++ 16 files changed, 1309 insertions(+), 921 deletions(-) create mode 100644 eventsources/sources/bitbucketserver/bitbucketserverclients.go create mode 100644 eventsources/sources/bitbucketserver/custombitbucketserverclient.go diff --git a/api/event-source.html b/api/event-source.html index 9f18c1ecd6..071c62b720 100644 --- a/api/event-source.html +++ b/api/event-source.html @@ -917,7 +917,7 @@

BitbucketBasicAuth BitbucketAuth)

-

BasicAuth holds the information required to authenticate user via basic auth mechanism

+

BitbucketBasicAuth holds the information required to authenticate user via basic auth mechanism

@@ -1252,6 +1252,21 @@

BitbucketServerEventSou

+ + + + @@ -1273,6 +1289,7 @@

BitbucketServerEventSou

diff --git a/api/event-source.md b/api/event-source.md index 2496e283d4..a4cbdf696e 100644 --- a/api/event-source.md +++ b/api/event-source.md @@ -966,8 +966,8 @@ BitbucketBasicAuth

-BasicAuth holds the information required to authenticate user via basic -auth mechanism +BitbucketBasicAuth holds the information required to authenticate user +via basic auth mechanism

+oneEventPerChange
+ +bool + +
+(Optional) +

OneEventPerChange controls whether to process each change in a repo:refs_changed webhook event as a separate event. This setting is useful when multiple tags are +pushed simultaneously for the same commit, and each tag needs to independently trigger an action, such as a distinct workflow in Argo Workflows. When enabled, the +BitbucketServerEventSource publishes an individual BitbucketServerEventData for each change, ensuring independent processing of each tag or reference update in a +single webhook event.

+
accessToken
@@ -1260,6 +1275,7 @@

BitbucketServerEventSou

+(Optional)

AccessToken is reference to K8s secret which holds the bitbucket api access information.

+(Optional)

WebhookSecret is reference to K8s secret which holds the bitbucket webhook secret (for HMAC validation).

@@ -1318,11 +1318,30 @@ under review. + + + +
+oneEventPerChange
bool +
+(Optional) +

+OneEventPerChange controls whether to process each change in a +repo:refs_changed webhook event as a separate event. This setting is +useful when multiple tags are pushed simultaneously for the same commit, +and each tag needs to independently trigger an action, such as a +distinct workflow in Argo Workflows. When enabled, the +BitbucketServerEventSource publishes an individual +BitbucketServerEventData for each change, ensuring independent +processing of each tag or reference update in a single webhook event. +

+
accessToken
Kubernetes core/v1.SecretKeySelector
+(Optional)

AccessToken is reference to K8s secret which holds the bitbucket api access information. @@ -1336,6 +1355,7 @@ access information. Kubernetes core/v1.SecretKeySelector

+(Optional)

WebhookSecret is reference to K8s secret which holds the bitbucket webhook secret (for HMAC validation). diff --git a/api/jsonschema/schema.json b/api/jsonschema/schema.json index e66bae75ec..ed93dd76e3 100644 --- a/api/jsonschema/schema.json +++ b/api/jsonschema/schema.json @@ -1055,7 +1055,7 @@ "type": "object" }, "io.argoproj.eventsource.v1alpha1.BitbucketBasicAuth": { - "description": "BasicAuth holds the information required to authenticate user via basic auth mechanism", + "description": "BitbucketBasicAuth holds the information required to authenticate user via basic auth mechanism", "properties": { "password": { "$ref": "#/definitions/io.k8s.api.core.v1.SecretKeySelector", @@ -1186,6 +1186,10 @@ "description": "Metadata holds the user defined metadata which will passed along the event payload.", "type": "object" }, + "oneEventPerChange": { + "description": "OneEventPerChange controls whether to process each change in a repo:refs_changed webhook event as a separate event. This setting is useful when multiple tags are pushed simultaneously for the same commit, and each tag needs to independently trigger an action, such as a distinct workflow in Argo Workflows. When enabled, the BitbucketServerEventSource publishes an individual BitbucketServerEventData for each change, ensuring independent processing of each tag or reference update in a single webhook event.", + "type": "boolean" + }, "projectKey": { "description": "DeprecatedProjectKey is the key of project for which integration needs to set up. Deprecated: use Repositories instead. Will be unsupported in v1.8.", "type": "string" @@ -5381,6 +5385,9 @@ "description": "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" } }, + "required": [ + "items" + ], "type": "object", "x-kubernetes-group-version-kind": [ { @@ -5439,6 +5446,9 @@ "description": "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" } }, + "required": [ + "items" + ], "type": "object", "x-kubernetes-group-version-kind": [ { @@ -5854,6 +5864,9 @@ "description": "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" } }, + "required": [ + "items" + ], "type": "object", "x-kubernetes-group-version-kind": [ { @@ -5912,6 +5925,9 @@ "description": "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" } }, + "required": [ + "items" + ], "type": "object", "x-kubernetes-group-version-kind": [ { diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 11fb93c340..52fd059cda 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -1047,7 +1047,7 @@ } }, "io.argoproj.eventsource.v1alpha1.BitbucketBasicAuth": { - "description": "BasicAuth holds the information required to authenticate user via basic auth mechanism", + "description": "BitbucketBasicAuth holds the information required to authenticate user via basic auth mechanism", "type": "object", "required": [ "username", @@ -1182,6 +1182,10 @@ "type": "string" } }, + "oneEventPerChange": { + "description": "OneEventPerChange controls whether to process each change in a repo:refs_changed webhook event as a separate event. This setting is useful when multiple tags are pushed simultaneously for the same commit, and each tag needs to independently trigger an action, such as a distinct workflow in Argo Workflows. When enabled, the BitbucketServerEventSource publishes an individual BitbucketServerEventData for each change, ensuring independent processing of each tag or reference update in a single webhook event.", + "type": "boolean" + }, "projectKey": { "description": "DeprecatedProjectKey is the key of project for which integration needs to set up. Deprecated: use Repositories instead. Will be unsupported in v1.8.", "type": "string" @@ -5335,6 +5339,9 @@ "io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBindingList": { "description": "ValidatingAdmissionPolicyBindingList is a list of ValidatingAdmissionPolicyBinding.", "type": "object", + "required": [ + "items" + ], "properties": { "apiVersion": { "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", @@ -5393,6 +5400,9 @@ "io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyList": { "description": "ValidatingAdmissionPolicyList is a list of ValidatingAdmissionPolicy.", "type": "object", + "required": [ + "items" + ], "properties": { "apiVersion": { "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", @@ -5808,6 +5818,9 @@ "io.k8s.api.admissionregistration.v1beta1.ValidatingAdmissionPolicyBindingList": { "description": "ValidatingAdmissionPolicyBindingList is a list of ValidatingAdmissionPolicyBinding.", "type": "object", + "required": [ + "items" + ], "properties": { "apiVersion": { "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", @@ -5866,6 +5879,9 @@ "io.k8s.api.admissionregistration.v1beta1.ValidatingAdmissionPolicyList": { "description": "ValidatingAdmissionPolicyList is a list of ValidatingAdmissionPolicy.", "type": "object", + "required": [ + "items" + ], "properties": { "apiVersion": { "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", diff --git a/eventsources/sources/bitbucketserver/bitbucketserverclients.go b/eventsources/sources/bitbucketserver/bitbucketserverclients.go new file mode 100644 index 0000000000..e5b5d651c0 --- /dev/null +++ b/eventsources/sources/bitbucketserver/bitbucketserverclients.go @@ -0,0 +1,148 @@ +package bitbucketserver + +import ( + "context" + "fmt" + "net/http" + + "github.com/argoproj/argo-events/common" + "github.com/argoproj/argo-events/pkg/apis/eventsource/v1alpha1" + bitbucketv1 "github.com/gfleury/go-bitbucket-v1" + "github.com/mitchellh/mapstructure" +) + +func newBitbucketServerClientCfg(bitbucketserverEventSource *v1alpha1.BitbucketServerEventSource) (*bitbucketv1.Configuration, error) { + bitbucketCfg := bitbucketv1.NewConfiguration(bitbucketserverEventSource.BitbucketServerBaseURL) + bitbucketCfg.AddDefaultHeader("x-atlassian-token", "no-check") + bitbucketCfg.AddDefaultHeader("x-requested-with", "XMLHttpRequest") + bitbucketCfg.HTTPClient = &http.Client{} + + if bitbucketserverEventSource.TLS != nil { + tlsConfig, err := common.GetTLSConfig(bitbucketserverEventSource.TLS) + if err != nil { + return nil, fmt.Errorf("failed to get the tls configuration: %w", err) + } + + bitbucketCfg.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: tlsConfig, + } + } + + return bitbucketCfg, nil +} + +func newBitbucketServerClient(ctx context.Context, bitbucketConfig *bitbucketv1.Configuration, bitbucketToken string) *bitbucketv1.APIClient { + ctx = context.WithValue(ctx, bitbucketv1.ContextAccessToken, bitbucketToken) + return bitbucketv1.NewAPIClient(ctx, bitbucketConfig) +} + +type bitbucketServerReposPager struct { + Size int `json:"size"` + Limit int `json:"limit"` + Start int `json:"start"` + NextPageStart int `json:"nextPageStart"` + IsLastPage bool `json:"isLastPage"` + Values []bitbucketv1.Repository `json:"values"` +} + +// getProjectRepositories returns all the Bitbucket Server repositories in the provided projects. +func getProjectRepositories(client *bitbucketv1.APIClient, projects []string) ([]v1alpha1.BitbucketServerRepository, error) { + var bitbucketRepos []bitbucketv1.Repository + for _, project := range projects { + paginationOptions := map[string]interface{}{"start": 0, "limit": 500} + for { + response, err := client.DefaultApi.GetRepositoriesWithOptions(project, paginationOptions) + if err != nil { + return nil, fmt.Errorf("unable to list repositories for project %s: %w", project, err) + } + + var reposPager bitbucketServerReposPager + err = mapstructure.Decode(response.Values, &reposPager) + if err != nil { + return nil, fmt.Errorf("unable to decode repositories for project %s: %w", project, err) + } + + bitbucketRepos = append(bitbucketRepos, reposPager.Values...) + + if reposPager.IsLastPage { + break + } + + paginationOptions["start"] = reposPager.NextPageStart + } + } + + var repositories []v1alpha1.BitbucketServerRepository + for n := range bitbucketRepos { + repositories = append(repositories, v1alpha1.BitbucketServerRepository{ + ProjectKey: bitbucketRepos[n].Project.Key, + RepositorySlug: bitbucketRepos[n].Slug, + }) + } + + return repositories, nil +} + +type refsChangedWebhookEvent struct { + EventKey string `json:"eventKey"` + Date string `json:"date"` + Actor struct { + Name string `json:"name"` + EmailAddress string `json:"emailAddress"` + ID int `json:"id"` + DisplayName string `json:"displayName"` + Active bool `json:"active"` + Slug string `json:"slug"` + Type string `json:"type"` + Links struct { + Self []struct { + Href string `json:"href"` + } `json:"self"` + } `json:"links"` + } `json:"actor"` + Repository struct { + Slug string `json:"slug"` + ID int `json:"id"` + Name string `json:"name"` + HierarchyID string `json:"hierarchyId"` + ScmID string `json:"scmId"` + State string `json:"state"` + StatusMessage string `json:"statusMessage"` + Forkable bool `json:"forkable"` + Project struct { + Key string `json:"key"` + ID int `json:"id"` + Name string `json:"name"` + Public bool `json:"public"` + Type string `json:"type"` + Links struct { + Self []struct { + Href string `json:"href"` + } `json:"self"` + } `json:"links"` + } `json:"project"` + Public bool `json:"public"` + Links struct { + Clone []struct { + Href string `json:"href"` + Name string `json:"name"` + } `json:"clone"` + Self []struct { + Href string `json:"href"` + } `json:"self"` + } `json:"links"` + } `json:"repository"` + Changes []refsChangedWebHookEventChange `json:"changes"` +} + +type refsChangedWebHookEventChange struct { + Ref struct { + ID string `json:"id"` + DisplayID string `json:"displayId"` + Type string `json:"type"` + } `json:"ref"` + RefID string `json:"refId"` + FromHash string `json:"fromHash"` + ToHash string `json:"toHash"` + Type string `json:"type"` +} diff --git a/eventsources/sources/bitbucketserver/custombitbucketserverclient.go b/eventsources/sources/bitbucketserver/custombitbucketserverclient.go new file mode 100644 index 0000000000..69f6150e6c --- /dev/null +++ b/eventsources/sources/bitbucketserver/custombitbucketserverclient.go @@ -0,0 +1,117 @@ +package bitbucketserver + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strconv" +) + +// customBitbucketServerClient returns a Bitbucket Server HTTP client that implements methods that gfleury/go-bitbucket-v1 does not. +// Specifically getting Pull Requests associated to a commit is not supported by gfleury/go-bitbucket-v1. +type customBitbucketServerClient struct { + client *http.Client + ctx context.Context + token string + url *url.URL +} + +// pullRequestRes is a struct containing information about the Pull Request. +type pullRequestRes struct { + ID int `json:"id"` + State string `json:"state"` +} + +// pagedPullRequestsRes is a paged response with values of pullRequestRes. +type pagedPullRequestsRes struct { + Size int `json:"size"` + Limit int `json:"limit"` + IsLastPage bool `json:"isLastPage"` + Values []pullRequestRes `json:"values"` + Start int `json:"start"` + NextPageStart int `json:"nextPageStart"` +} + +type pagination struct { + Start int + Limit int +} + +func (p *pagination) StartStr() string { + return strconv.Itoa(p.Start) +} + +func (p *pagination) LimitStr() string { + return strconv.Itoa(p.Limit) +} + +func (c *customBitbucketServerClient) authHeader(req *http.Request) { + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.token)) +} + +func (c *customBitbucketServerClient) get(u string) ([]byte, error) { + req, err := http.NewRequestWithContext(c.ctx, http.MethodGet, u, nil) + if err != nil { + return nil, err + } + + c.authHeader(req) + + res, err := c.client.Do(req) + if err != nil { + return nil, err + } + defer func() { + _ = res.Body.Close() + }() + + if res.StatusCode > 299 { + resBody, readErr := io.ReadAll(res.Body) + if readErr != nil { + return nil, readErr + } + + return nil, fmt.Errorf("calling endpoint '%s' failed: status %d: response body: %s", u, res.StatusCode, resBody) + } + + return io.ReadAll(res.Body) +} + +// GetCommitPullRequests returns all the Pull Requests associated to the commit id. +func (c *customBitbucketServerClient) GetCommitPullRequests(project, repository, commit string) ([]pullRequestRes, error) { + p := pagination{Start: 0, Limit: 500} + + commitsURL := c.url.JoinPath(fmt.Sprintf("api/1.0/projects/%s/repos/%s/commits/%s/pull-requests", project, repository, commit)) + query := commitsURL.Query() + query.Set("limit", p.LimitStr()) + + var pullRequests []pullRequestRes + for { + query.Set("start", p.StartStr()) + commitsURL.RawQuery = query.Encode() + + body, err := c.get(commitsURL.String()) + if err != nil { + return nil, err + } + + var pagedPullRequests pagedPullRequestsRes + err = json.Unmarshal(body, &pagedPullRequests) + if err != nil { + return nil, err + } + + pullRequests = append(pullRequests, pagedPullRequests.Values...) + + if pagedPullRequests.IsLastPage { + break + } + + p.Start = pagedPullRequests.NextPageStart + } + + return pullRequests, nil +} diff --git a/eventsources/sources/bitbucketserver/start.go b/eventsources/sources/bitbucketserver/start.go index 39a659e030..8ae3c6c7ef 100644 --- a/eventsources/sources/bitbucketserver/start.go +++ b/eventsources/sources/bitbucketserver/start.go @@ -27,13 +27,12 @@ import ( "math/big" "net/http" "net/url" - "strconv" "strings" "time" bitbucketv1 "github.com/gfleury/go-bitbucket-v1" "github.com/mitchellh/mapstructure" - "golang.org/x/exp/slices" + "go.uber.org/zap" "github.com/argoproj/argo-events/common" "github.com/argoproj/argo-events/common/logging" @@ -42,19 +41,61 @@ import ( "github.com/argoproj/argo-events/eventsources/sources" "github.com/argoproj/argo-events/pkg/apis/events" "github.com/argoproj/argo-events/pkg/apis/eventsource/v1alpha1" - "go.uber.org/zap" ) // controller controls the webhook operations -var ( - controller = webhook.NewController() -) +var controller = webhook.NewController() // set up the activation and inactivation channels to control the state of routes. func init() { go webhook.ProcessRouteStatus(controller) } +// StartListening starts an event source +func (el *EventListener) StartListening(ctx context.Context, dispatch func([]byte, ...eventsourcecommon.Option) error) error { + defer sources.Recover(el.GetEventName()) + + bitbucketServerEventSource := &el.BitbucketServerEventSource + + logger := logging.FromContext(ctx).With( + logging.LabelEventSourceType, el.GetEventSourceType(), + logging.LabelEventName, el.GetEventName(), + "base-url", bitbucketServerEventSource.BitbucketServerBaseURL, + ) + + logger.Info("started processing the bitbucketserver event source...") + + route := webhook.NewRoute(bitbucketServerEventSource.Webhook, logger, el.GetEventSourceName(), el.GetEventName(), el.Metrics) + router := &Router{ + route: route, + bitbucketServerEventSource: bitbucketServerEventSource, + hookIDs: make(map[string]int), + } + + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + if bitbucketServerEventSource.AccessToken != nil { + err := setupBitbucketServerClients(ctx, router, bitbucketServerEventSource) + if err != nil { + return fmt.Errorf("setting up bitbucketserver clients failed: %w", err) + } + } else { + logger.Info("skipping setting up bitbucketserver clients: access token not specified") + } + + if bitbucketServerEventSource.ShouldCreateWebhooks() { + err := router.manageBitbucketServerWebhooks(ctx, bitbucketServerEventSource) + if err != nil { + return fmt.Errorf("managing bitbucketserver webhooks failed: %w", err) + } + } else { + logger.Info("skipping managing bitbucketserver webhooks: access token or webhook url or projects or repositories not specified") + } + + return webhook.ManageRoute(ctx, router, controller, dispatch) +} + // Implement Router // 1. GetRoute // 2. HandleRoute @@ -68,7 +109,7 @@ func (router *Router) GetRoute() *webhook.Route { // HandleRoute handles incoming requests on the route func (router *Router) HandleRoute(writer http.ResponseWriter, request *http.Request) { - bitbucketserverEventSource := router.bitbucketserverEventSource + bitbucketServerEventSource := router.bitbucketServerEventSource route := router.GetRoute() logger := route.Logger.With( @@ -89,66 +130,41 @@ func (router *Router) HandleRoute(writer http.ResponseWriter, request *http.Requ route.Metrics.EventProcessingDuration(route.EventSourceName, route.EventName, float64(time.Since(start)/time.Millisecond)) }(time.Now()) - request.Body = http.MaxBytesReader(writer, request.Body, route.Context.GetMaxPayloadSize()) - body, err := router.parseAndValidateBitbucketServerRequest(request) + bitbucketServerEvents, err := processBitbucketServerWebhook( + router.customClient, + router.hookSecret, + writer, + request, + route.Context.GetMaxPayloadSize(), + bitbucketServerEventSource.SkipBranchRefsChangedOnOpenPR, + bitbucketServerEventSource.OneEventPerChange, + ) if err != nil { - logger.Errorw("failed to parse/validate request", zap.Error(err)) + logger.Errorw("failed to handle event", zap.Error(err)) common.SendErrorResponse(writer, err.Error()) route.Metrics.EventProcessingFailed(route.EventSourceName, route.EventName) return } - // When SkipBranchRefsChangedOnOpenPR is enabled and webhook event type is repo:refs_changed, - // check if a Pull Request is opened for the commit, if one is opened the event will be skipped. - if bitbucketserverEventSource.SkipBranchRefsChangedOnOpenPR && slices.Contains(bitbucketserverEventSource.Events, "repo:refs_changed") { - refsChanged := refsChangedWebhookEvent{} - err := json.Unmarshal(body, &refsChanged) - if err != nil { - logger.Errorf("reading webhook body", zap.Error(err)) - common.SendErrorResponse(writer, err.Error()) - route.Metrics.EventProcessingFailed(route.EventSourceName, route.EventName) - return + for _, bitbucketServerEvent := range bitbucketServerEvents { + event := &events.BitbucketServerEventData{ + Headers: request.Header, + Body: (*json.RawMessage)(&bitbucketServerEvent), + Metadata: router.bitbucketServerEventSource.Metadata, } - if refsChanged.EventKey == "repo:refs_changed" && - len(refsChanged.Changes) > 0 && // Note refsChanged.Changes never has more or less than one change, not sure why Atlassian made it a list. - strings.EqualFold(refsChanged.Changes[0].Ref.Type, "BRANCH") && - !strings.EqualFold(refsChanged.Changes[0].Type, "DELETE") { - // Check if commit is associated to an open PR. - hasOpenPR, err := router.refsChangedHasOpenPullRequest(refsChanged.Repository.Project.Key, refsChanged.Repository.Slug, refsChanged.Changes[0].ToHash) - if err != nil { - logger.Errorf("checking if changed branch ref has an open pull request", zap.Error(err)) - common.SendErrorResponse(writer, err.Error()) - route.Metrics.EventProcessingFailed(route.EventSourceName, route.EventName) - return - } - - // Do not publish this Branch repo:refs_changed event if a related Pull Request is already opened for the commit. - if hasOpenPR { - logger.Info("skipping publishing event, commit has an open pull request") - common.SendSuccessResponse(writer, "success") - return - } + eventBody, jsonErr := json.Marshal(event) + if jsonErr != nil { + logger.Errorw("failed to parse event", zap.Error(jsonErr)) + common.SendErrorResponse(writer, "invalid event") + route.Metrics.EventProcessingFailed(route.EventSourceName, route.EventName) + return } - } - event := &events.BitbucketServerEventData{ - Headers: request.Header, - Body: (*json.RawMessage)(&body), - Metadata: router.bitbucketserverEventSource.Metadata, - } - - eventBody, err := json.Marshal(event) - if err != nil { - logger.Errorw("failed to parse event", zap.Error(err)) - common.SendErrorResponse(writer, "invalid event") - route.Metrics.EventProcessingFailed(route.EventSourceName, route.EventName) - return + logger.Info("dispatching event on route's data channel") + route.DataCh <- eventBody } - logger.Info("dispatching event on route's data channel") - route.DataCh <- eventBody - logger.Info("request successfully processed") common.SendSuccessResponse(writer, "success") } @@ -160,152 +176,107 @@ func (router *Router) PostActivate() error { // PostInactivate performs operations after the route is inactivated func (router *Router) PostInactivate() error { - bitbucketserverEventSource := router.bitbucketserverEventSource - route := router.route - logger := route.Logger - - if !bitbucketserverEventSource.DeleteHookOnFinish { - logger.Info("not configured to delete webhooks, skipping") - return nil - } + bitbucketServerEventSource := router.bitbucketServerEventSource - if len(router.hookIDs) == 0 { - logger.Info("no need to delete webhooks, skipping") + if !bitbucketServerEventSource.DeleteHookOnFinish || len(router.hookIDs) == 0 { return nil } - logger.Info("deleting webhooks from bitbucket") - - bitbucketRepositories := bitbucketserverEventSource.GetBitbucketServerRepositories() - - if len(bitbucketserverEventSource.Projects) > 0 { - bitbucketProjectRepositories, err := getProjectRepositories(router.deleteClient, bitbucketserverEventSource.Projects) - if err != nil { - return err - } + return router.deleteWebhooks(bitbucketServerEventSource) +} - bitbucketRepositories = append(bitbucketRepositories, bitbucketProjectRepositories...) +func (router *Router) listWebhooks(repo v1alpha1.BitbucketServerRepository) ([]bitbucketv1.Webhook, error) { + apiResponse, err := router.client.DefaultApi.FindWebhooks(repo.ProjectKey, repo.RepositorySlug, nil) + if err != nil { + return nil, fmt.Errorf("failed to list existing hooks to check for duplicates for repository %s/%s, %w", repo.ProjectKey, repo.RepositorySlug, err) } - for _, repo := range bitbucketRepositories { - id, ok := router.hookIDs[repo.ProjectKey+","+repo.RepositorySlug] - if !ok { - return fmt.Errorf("can not find hook ID for project-key: %s, repository-slug: %s", repo.ProjectKey, repo.RepositorySlug) - } - - _, err := router.deleteClient.DefaultApi.DeleteWebhook(repo.ProjectKey, repo.RepositorySlug, int32(id)) - if err != nil { - return fmt.Errorf("failed to delete bitbucketserver webhook. err: %w", err) - } - - logger.Infow("bitbucket server webhook deleted", - zap.String("project-key", repo.ProjectKey), zap.String("repository-slug", repo.RepositorySlug)) + hooks, err := bitbucketv1.GetWebhooksResponse(apiResponse) + if err != nil { + return nil, fmt.Errorf("failed to convert the list of webhooks for repository %s/%s, %w", repo.ProjectKey, repo.RepositorySlug, err) } - return nil + return hooks, nil } -// StartListening starts an event source -func (el *EventListener) StartListening(ctx context.Context, dispatch func([]byte, ...eventsourcecommon.Option) error) error { - defer sources.Recover(el.GetEventName()) - - bitbucketserverEventSource := &el.BitbucketServerEventSource - - logger := logging.FromContext(ctx).With( - logging.LabelEventSourceType, el.GetEventSourceType(), - logging.LabelEventName, el.GetEventName(), - "base-url", bitbucketserverEventSource.BitbucketServerBaseURL, - ) - - logger.Info("started processing the Bitbucket Server event source...") - - logger.Info("retrieving the access token credentials...") - bitbucketToken, err := common.GetSecretFromVolume(bitbucketserverEventSource.AccessToken) +func (router *Router) createWebhook(requestBody []byte, repo v1alpha1.BitbucketServerRepository) (*bitbucketv1.Webhook, error) { + apiResponse, err := router.client.DefaultApi.CreateWebhook(repo.ProjectKey, repo.RepositorySlug, requestBody, []string{"application/json"}) if err != nil { - return fmt.Errorf("getting bitbucketserver token. err: %w", err) + return nil, fmt.Errorf("failed to add webhook: %w", err) } - logger.Info("setting up the client to connect to Bitbucket Server...") - bitbucketConfig, err := newBitbucketServerClientCfg(bitbucketserverEventSource) + var createdHook *bitbucketv1.Webhook + err = mapstructure.Decode(apiResponse.Values, &createdHook) if err != nil { - return fmt.Errorf("initializing bitbucketserver client config. err: %w", err) + return nil, fmt.Errorf("failed to convert API response to webhook struct: %w", err) } - bitbucketURL, err := url.Parse(bitbucketserverEventSource.BitbucketServerBaseURL) - if err != nil { - return fmt.Errorf("parsing bitbucketserver url. err: %w", err) - } + return createdHook, nil +} - ctx, cancel := context.WithCancel(ctx) - defer cancel() +func (router *Router) updateWebhook(hookID int, requestBody []byte, repo v1alpha1.BitbucketServerRepository) error { + _, err := router.client.DefaultApi.UpdateWebhook(repo.ProjectKey, repo.RepositorySlug, int32(hookID), requestBody, []string{"application/json"}) - bitbucketClient := newBitbucketServerClient(ctx, bitbucketConfig, bitbucketToken) - bitbucketDeleteClient := newBitbucketServerClient(context.Background(), bitbucketConfig, bitbucketToken) + return err +} - route := webhook.NewRoute(bitbucketserverEventSource.Webhook, logger, el.GetEventSourceName(), el.GetEventName(), el.Metrics) - router := &Router{ - route: route, - client: bitbucketClient, - customClient: &customBitbucketClient{ - client: bitbucketConfig.HTTPClient, - ctx: ctx, - token: bitbucketToken, - url: bitbucketURL, - }, - deleteClient: bitbucketDeleteClient, - bitbucketserverEventSource: bitbucketserverEventSource, - hookIDs: make(map[string]int), - } +func (router *Router) shouldUpdateWebhook(existingHook bitbucketv1.Webhook, newHook bitbucketv1.Webhook) bool { + return !common.ElementsMatch(existingHook.Events, newHook.Events) || + existingHook.Configuration.Secret != newHook.Configuration.Secret +} - if !bitbucketserverEventSource.ShouldCreateWebhooks() { - logger.Info("access token or webhook configuration were not provided, skipping webhooks creation") - return webhook.ManageRoute(ctx, router, controller, dispatch) - } +func (router *Router) createRequestBodyFromWebhook(hook bitbucketv1.Webhook) ([]byte, error) { + var err error + var finalHook interface{} = hook - if bitbucketserverEventSource.WebhookSecret != nil { - logger.Info("retrieving the webhook secret...") - webhookSecret, err := common.GetSecretFromVolume(bitbucketserverEventSource.WebhookSecret) + // if the hook doesn't have a secret, the configuration field must be removed in order for the request to succeed, + // otherwise Bitbucket Server sends 500 response because of empty string value in the hook.Configuration.Secret field + if hook.Configuration.Secret == "" { + hookMap := make(map[string]interface{}) + err = common.StructToMap(hook, hookMap) if err != nil { - return fmt.Errorf("getting bitbucketserver webhook secret. err: %w", err) + return nil, fmt.Errorf("failed to convert webhook to map, %w", err) } - router.hookSecret = webhookSecret + delete(hookMap, "configuration") + + finalHook = hookMap } - applyWebhooks := func() { - bitbucketRepositories := bitbucketserverEventSource.GetBitbucketServerRepositories() + requestBody, err := json.Marshal(finalHook) + if err != nil { + return nil, fmt.Errorf("failed to marshal new webhook to JSON, %w", err) + } - if len(bitbucketserverEventSource.Projects) > 0 { - bitbucketProjectRepositories, err := getProjectRepositories(router.client, bitbucketserverEventSource.Projects) - if err != nil { - logger.Errorw("failed to apply Bitbucket webhook", zap.Error(err)) - } + return requestBody, nil +} - bitbucketRepositories = append(bitbucketRepositories, bitbucketProjectRepositories...) +func (router *Router) manageBitbucketServerWebhooks(ctx context.Context, bitbucketServerEventSource *v1alpha1.BitbucketServerEventSource) error { + if bitbucketServerEventSource.WebhookSecret != nil { + webhookSecret, err := common.GetSecretFromVolume(bitbucketServerEventSource.WebhookSecret) + if err != nil { + return fmt.Errorf("getting bitbucketserver webhook secret: %w", err) } - for _, repo := range bitbucketRepositories { - if err = router.applyBitbucketServerWebhook(repo); err != nil { - logger.Errorw("failed to apply Bitbucket webhook", - zap.String("project-key", repo.ProjectKey), zap.String("repository-slug", repo.RepositorySlug), zap.Error(err)) - continue - } - - time.Sleep(500 * time.Millisecond) - } + router.hookSecret = webhookSecret } // When running multiple replicas of this event source, they will try to create webhooks at the same time. // Randomly delay running the initial apply webhooks func to mitigate the issue. randomNum, _ := rand.Int(rand.Reader, big.NewInt(int64(2000))) time.Sleep(time.Duration(randomNum.Int64()) * time.Millisecond) - applyWebhooks() + + // Initial apply of webhooks on event source start. + err := router.applyBitbucketServerWebhooks(bitbucketServerEventSource) + if err != nil { + return fmt.Errorf("initial applying bitbucketserver webhooks failed: %w", err) + } var checkInterval time.Duration - if bitbucketserverEventSource.CheckInterval == "" { + if bitbucketServerEventSource.CheckInterval == "" { checkInterval = 60 * time.Second } else { - checkInterval, err = time.ParseDuration(bitbucketserverEventSource.CheckInterval) + checkInterval, err = time.ParseDuration(bitbucketServerEventSource.CheckInterval) if err != nil { return err } @@ -315,27 +286,56 @@ func (el *EventListener) StartListening(ctx context.Context, dispatch func([]byt // Another kind of race conditions might happen when pods do rolling upgrade - new pod starts // and old pod terminates, if DeleteHookOnFinish is true, the hook will be deleted from Bitbucket. // This is a workaround to mitigate the race conditions. - logger.Info("starting bitbucket hooks manager daemon") + router.route.Logger.Info("starting bitbucketserver webhooks manager") ticker := time.NewTicker(checkInterval) defer ticker.Stop() for { select { case <-ctx.Done(): - logger.Info("exiting bitbucket hooks manager daemon") + router.route.Logger.Info("exiting bitbucketserver webhooks manager") return case <-ticker.C: - applyWebhooks() + err = router.applyBitbucketServerWebhooks(bitbucketServerEventSource) + if err != nil { + router.route.Logger.Errorf("re-applying bitbucketserver webhooks failed: %w", err) + } } } }() - return webhook.ManageRoute(ctx, router, controller, dispatch) + return nil } -// applyBitbucketServerWebhook creates or updates the configured webhook in Bitbucket +// applyBitbucketServerWebhooks ensures all configured repositories have the correct webhook settings applied. +func (router *Router) applyBitbucketServerWebhooks(bitbucketServerEventSource *v1alpha1.BitbucketServerEventSource) error { + bitbucketRepositories := bitbucketServerEventSource.GetBitbucketServerRepositories() + + if len(bitbucketServerEventSource.Projects) > 0 { + bitbucketProjectRepositories, err := getProjectRepositories(router.client, bitbucketServerEventSource.Projects) + if err != nil { + return fmt.Errorf("getting list of bitbucketserver repositories from projects %v: %w", bitbucketServerEventSource.Projects, err) + } + + bitbucketRepositories = append(bitbucketRepositories, bitbucketProjectRepositories...) + } + + for _, repo := range bitbucketRepositories { + if err := router.applyBitbucketServerWebhook(repo); err != nil { + router.route.Logger.Errorw("failed to apply bitbucketserver webhook", + zap.String("project-key", repo.ProjectKey), zap.String("repository-slug", repo.RepositorySlug), zap.Error(err)) + continue + } + + time.Sleep(500 * time.Millisecond) + } + + return nil +} + +// applyBitbucketServerWebhook creates or updates the configured webhook in Bitbucket Server. func (router *Router) applyBitbucketServerWebhook(repo v1alpha1.BitbucketServerRepository) error { - bitbucketserverEventSource := router.bitbucketserverEventSource + bitbucketServerEventSource := router.bitbucketServerEventSource route := router.route logger := route.Logger.With( @@ -344,14 +344,13 @@ func (router *Router) applyBitbucketServerWebhook(repo v1alpha1.BitbucketServerR logging.LabelHTTPMethod, route.Context.Method, "project-key", repo.ProjectKey, "repository-slug", repo.RepositorySlug, - "base-url", bitbucketserverEventSource.BitbucketServerBaseURL, ) - formattedURL := common.FormattedURL(bitbucketserverEventSource.Webhook.URL, bitbucketserverEventSource.Webhook.Endpoint) + formattedURL := common.FormattedURL(bitbucketServerEventSource.Webhook.URL, bitbucketServerEventSource.Webhook.Endpoint) hooks, err := router.listWebhooks(repo) if err != nil { - return fmt.Errorf("failed to list existing hooks to check for duplicates for repository %s/%s, %w", repo.ProjectKey, repo.RepositorySlug, err) + return fmt.Errorf("failed to list existing hooks to check for duplicates for repository %s/%s: %w", repo.ProjectKey, repo.RepositorySlug, err) } var existingHook bitbucketv1.Webhook @@ -370,7 +369,7 @@ func (router *Router) applyBitbucketServerWebhook(repo v1alpha1.BitbucketServerR Name: "Argo Events", Url: formattedURL, Active: true, - Events: bitbucketserverEventSource.Events, + Events: bitbucketServerEventSource.Events, Configuration: bitbucketv1.WebhookConfiguration{Secret: router.hookSecret}, } @@ -379,333 +378,239 @@ func (router *Router) applyBitbucketServerWebhook(repo v1alpha1.BitbucketServerR return fmt.Errorf("failed to create request body from webhook, %w", err) } - // Update the webhook when it does exist and the events/configuration have changed + // Update the webhook when it does exist and the events/configuration have changed. if isAlreadyExists { - logger.Info("webhook already exists") if router.shouldUpdateWebhook(existingHook, newHook) { - logger.Info("webhook requires an update") err = router.updateWebhook(existingHook.ID, requestBody, repo) if err != nil { - return fmt.Errorf("failed to update webhook. err: %w", err) + return fmt.Errorf("failed to update bitbucketserver webhook: %w", err) } - logger.With("hook-id", existingHook.ID).Info("hook successfully updated") + logger.Infow("bitbucketserver webhook successfully updated", zap.Int("webhook-id", existingHook.ID)) } return nil } - // Create the webhook when it doesn't exist yet + // Create the webhook when it doesn't exist yet. createdHook, err := router.createWebhook(requestBody, repo) if err != nil { - return fmt.Errorf("failed to create webhook. err: %w", err) + return fmt.Errorf("failed to create bitbucketserver webhook: %w", err) } router.hookIDs[repo.ProjectKey+","+repo.RepositorySlug] = createdHook.ID - logger.With("hook-id", createdHook.ID).Info("hook successfully registered") + logger.Infow("bitbucketserver webhook successfully registered", zap.Int("webhook-id", createdHook.ID)) return nil } -func (router *Router) listWebhooks(repo v1alpha1.BitbucketServerRepository) ([]bitbucketv1.Webhook, error) { - apiResponse, err := router.client.DefaultApi.FindWebhooks(repo.ProjectKey, repo.RepositorySlug, nil) - if err != nil { - return nil, fmt.Errorf("failed to list existing hooks to check for duplicates for repository %s/%s, %w", repo.ProjectKey, repo.RepositorySlug, err) - } - - hooks, err := bitbucketv1.GetWebhooksResponse(apiResponse) - if err != nil { - return nil, fmt.Errorf("failed to convert the list of webhooks for repository %s/%s, %w", repo.ProjectKey, repo.RepositorySlug, err) - } - - return hooks, nil -} +func (router *Router) deleteWebhooks(bitbucketServerEventSource *v1alpha1.BitbucketServerEventSource) error { + bitbucketRepositories := bitbucketServerEventSource.GetBitbucketServerRepositories() -func (router *Router) createWebhook(requestBody []byte, repo v1alpha1.BitbucketServerRepository) (*bitbucketv1.Webhook, error) { - apiResponse, err := router.client.DefaultApi.CreateWebhook(repo.ProjectKey, repo.RepositorySlug, requestBody, []string{"application/json"}) - if err != nil { - return nil, fmt.Errorf("failed to add webhook. err: %w", err) - } + if len(bitbucketServerEventSource.Projects) > 0 { + bitbucketProjectRepositories, err := getProjectRepositories(router.deleteClient, bitbucketServerEventSource.Projects) + if err != nil { + return fmt.Errorf("getting list of bitbucketserver repositories from projects %v: %w", bitbucketServerEventSource.Projects, err) + } - var createdHook *bitbucketv1.Webhook - err = mapstructure.Decode(apiResponse.Values, &createdHook) - if err != nil { - return nil, fmt.Errorf("failed to convert API response to Webhook struct. err: %w", err) + bitbucketRepositories = append(bitbucketRepositories, bitbucketProjectRepositories...) } - return createdHook, nil -} - -func (router *Router) updateWebhook(hookID int, requestBody []byte, repo v1alpha1.BitbucketServerRepository) error { - _, err := router.client.DefaultApi.UpdateWebhook(repo.ProjectKey, repo.RepositorySlug, int32(hookID), requestBody, []string{"application/json"}) - - return err -} - -func (router *Router) shouldUpdateWebhook(existingHook bitbucketv1.Webhook, newHook bitbucketv1.Webhook) bool { - return !common.ElementsMatch(existingHook.Events, newHook.Events) || - existingHook.Configuration.Secret != newHook.Configuration.Secret -} - -func (router *Router) createRequestBodyFromWebhook(hook bitbucketv1.Webhook) ([]byte, error) { - var err error - var finalHook interface{} = hook + for _, repo := range bitbucketRepositories { + id, ok := router.hookIDs[repo.ProjectKey+","+repo.RepositorySlug] + if !ok { + router.route.Logger.Warnw("webhook id for bitbucketserver repository not defined", + zap.String("project-key", repo.ProjectKey), + zap.String("repository-slug", repo.RepositorySlug), + ) + continue + } - // if the hook doesn't have a secret, the configuration field must be removed in order for the request to succeed, - // otherwise Bitbucket Server sends 500 response because of empty string value in the hook.Configuration.Secret field - if hook.Configuration.Secret == "" { - hookMap := make(map[string]interface{}) - err = common.StructToMap(hook, hookMap) + _, err := router.deleteClient.DefaultApi.DeleteWebhook(repo.ProjectKey, repo.RepositorySlug, int32(id)) if err != nil { - return nil, fmt.Errorf("failed to convert webhook to map, %w", err) + return fmt.Errorf("failed to delete bitbucketserver webhook: %w", err) } - delete(hookMap, "configuration") - - finalHook = hookMap + router.route.Logger.Infow("bitbucketserver webhook deleted", + zap.Int("webhook-id", id), + zap.String("project-key", repo.ProjectKey), + zap.String("repository-slug", repo.RepositorySlug), + ) } - requestBody, err := json.Marshal(finalHook) - if err != nil { - return nil, fmt.Errorf("failed to marshal new webhook to JSON, %w", err) - } - - return requestBody, nil + return nil } -func (router *Router) parseAndValidateBitbucketServerRequest(request *http.Request) ([]byte, error) { - body, err := io.ReadAll(request.Body) +func setupBitbucketServerClients(ctx context.Context, router *Router, bitbucketServerEventSource *v1alpha1.BitbucketServerEventSource) error { + bitbucketToken, err := common.GetSecretFromVolume(bitbucketServerEventSource.AccessToken) if err != nil { - return nil, fmt.Errorf("failed to parse request body, %w", err) + return fmt.Errorf("retrieving the bitbucketserver access token credentials: %w", err) } - if len(router.hookSecret) != 0 { - signature := request.Header.Get("X-Hub-Signature") - if len(signature) == 0 { - return nil, fmt.Errorf("missing signature header") - } - - mac := hmac.New(sha256.New, []byte(router.hookSecret)) - _, _ = mac.Write(body) - expectedMAC := hex.EncodeToString(mac.Sum(nil)) - - if !hmac.Equal([]byte(signature[7:]), []byte(expectedMAC)) { - return nil, fmt.Errorf("hmac verification failed") - } + bitbucketConfig, err := newBitbucketServerClientCfg(bitbucketServerEventSource) + if err != nil { + return fmt.Errorf("initializing bitbucketserver client config: %w", err) } - return body, nil -} - -// refsChangedHasOpenPullRequest returns true if the changed commit has an open pull request -func (router *Router) refsChangedHasOpenPullRequest(project, repository, commit string) (bool, error) { - bitbucketPullRequests, err := router.customClient.GetCommitPullRequests(project, repository, commit) + bitbucketURL, err := url.Parse(bitbucketServerEventSource.BitbucketServerBaseURL) if err != nil { - return false, fmt.Errorf("getting commit pull requests for project %s, repository %s and commit %s: %w", - project, repository, commit, err) + return fmt.Errorf("parsing bitbucketserver url: %w", err) } - for _, bitbucketPullRequest := range bitbucketPullRequests { - if strings.EqualFold(bitbucketPullRequest.State, "OPEN") { - return true, nil - } + router.client = newBitbucketServerClient(ctx, bitbucketConfig, bitbucketToken) + router.deleteClient = newBitbucketServerClient(context.Background(), bitbucketConfig, bitbucketToken) + router.customClient = &customBitbucketServerClient{ + client: bitbucketConfig.HTTPClient, + ctx: ctx, + token: bitbucketToken, + url: bitbucketURL, } - return false, nil -} - -type bitbucketServerReposPager struct { - Size int `json:"size"` - Limit int `json:"limit"` - Start int `json:"start"` - NextPageStart int `json:"nextPageStart"` - IsLastPage bool `json:"isLastPage"` - Values []bitbucketv1.Repository `json:"values"` + return nil } -// getProjectRepositories returns all the Bitbucket Server repositories in the provided projects -func getProjectRepositories(client *bitbucketv1.APIClient, projects []string) ([]v1alpha1.BitbucketServerRepository, error) { - var bitbucketRepos []bitbucketv1.Repository - for _, project := range projects { - paginationOptions := map[string]interface{}{"start": 0, "limit": 500} - for { - response, err := client.DefaultApi.GetRepositoriesWithOptions(project, paginationOptions) - if err != nil { - return nil, fmt.Errorf("unable to list repositories for project %s: %w", project, err) - } +// processBitbucketServerWebhook processes Bitbucket Server webhook events specifically looking for "repo:refs_changed" events. +// It first checks if the incoming webhook is configured to be handled (i.e., it's a "repo:refs_changed" event). +// If not, it logs the discrepancy and returns the raw event. +// +// For valid "repo:refs_changed" events, it: +// - Unmarshals the JSON body into a refsChangedWebhookEvent struct. +// - Optionally filters out changes associated with open pull requests if SkipBranchRefsChangedOnOpenPR is enabled. +// - Depending on the OneEventPerChange setting, it either batches all changes into one event or creates individual events for each change. +// +// It returns a slice of byte slices containing the processed or original webhook events, and any error encountered during processing. +func processBitbucketServerWebhook(customBitbucketServerClient *customBitbucketServerClient, hookSecret string, writer http.ResponseWriter, request *http.Request, maxPayloadSize int64, skipBranchRefsChangedOnOpenPR bool, oneEventPerChange bool) ([][]byte, error) { + request.Body = http.MaxBytesReader(writer, request.Body, maxPayloadSize) + body, err := validateBitbucketServerRequest(hookSecret, request) + if err != nil { + return nil, fmt.Errorf("failed to validate bitbucketserver webhook request: %w", err) + } - var reposPager bitbucketServerReposPager - err = mapstructure.Decode(response.Values, &reposPager) - if err != nil { - return nil, fmt.Errorf("unable to decode repositories for project %s: %w", project, err) - } + if request.Header.Get("X-Event-Key") != "repo:refs_changed" { + // Don't continue if this is not a repo:refs_changed webhook event. + return [][]byte{body}, nil + } - bitbucketRepos = append(bitbucketRepos, reposPager.Values...) + refsChanged := refsChangedWebhookEvent{} + err = json.Unmarshal(body, &refsChanged) + if err != nil { + return nil, fmt.Errorf("decoding repo:refs_changed webhook: %w", err) + } - if reposPager.IsLastPage { - break - } + // When SkipBranchRefsChangedOnOpenPR is enabled, skip publishing the repo:refs_changed event if a Pull Request is already open for the commit. + // This prevents duplicate notifications when a branch is updated and a PR is already open for the latest commit. + if skipBranchRefsChangedOnOpenPR { + err = filterChangesForOpenPRs(customBitbucketServerClient, &refsChanged) + if err != nil { + return nil, fmt.Errorf("filtering changes for open prs: %w", err) + } - paginationOptions["start"] = reposPager.NextPageStart + if len(refsChanged.Changes) == 0 { + // No changes are present in the refsChanged event after filtering. Skip processing event + return [][]byte{}, nil } } - var repositories []v1alpha1.BitbucketServerRepository - for n := range bitbucketRepos { - repositories = append(repositories, v1alpha1.BitbucketServerRepository{ - ProjectKey: bitbucketRepos[n].Project.Key, - RepositorySlug: bitbucketRepos[n].Slug, - }) - } + var bitbucketEvents [][]byte - return repositories, nil -} + // Handle event batching based on OneEventPerChange configuration. + // If enabled, split the refsChanged event into individual events, one per change. + // Otherwise, send the entire refsChanged event as a single event. + if oneEventPerChange { + for _, change := range refsChanged.Changes { + rc := refsChanged -func newBitbucketServerClientCfg(bitbucketserverEventSource *v1alpha1.BitbucketServerEventSource) (*bitbucketv1.Configuration, error) { - bitbucketCfg := bitbucketv1.NewConfiguration(bitbucketserverEventSource.BitbucketServerBaseURL) - bitbucketCfg.AddDefaultHeader("x-atlassian-token", "no-check") - bitbucketCfg.AddDefaultHeader("x-requested-with", "XMLHttpRequest") - bitbucketCfg.HTTPClient = &http.Client{} + rc.Changes = []refsChangedWebHookEventChange{change} - if bitbucketserverEventSource.TLS != nil { - tlsConfig, err := common.GetTLSConfig(bitbucketserverEventSource.TLS) - if err != nil { - return nil, fmt.Errorf("failed to get the tls configuration. err: %w", err) - } + rcBytes, jsonErr := json.Marshal(&rc) + if jsonErr != nil { + return nil, fmt.Errorf("encoding repo:refs_changed webhook: %w", jsonErr) + } - bitbucketCfg.HTTPClient.Transport = &http.Transport{ - TLSClientConfig: tlsConfig, + bitbucketEvents = append(bitbucketEvents, rcBytes) } + } else { + bitbucketEvents = append(bitbucketEvents, body) } - return bitbucketCfg, nil + return bitbucketEvents, nil } -func newBitbucketServerClient(ctx context.Context, bitbucketConfig *bitbucketv1.Configuration, bitbucketToken string) *bitbucketv1.APIClient { - ctx = context.WithValue(ctx, bitbucketv1.ContextAccessToken, bitbucketToken) - return bitbucketv1.NewAPIClient(ctx, bitbucketConfig) -} +// filterChangesForOpenPRs removes changes from the refsChanged webhook event that are linked to open pull requests. +// It examines each change to determine if it pertains to a "BRANCH" that has not been deleted. +// For each relevant change, it checks whether there is an open pull request using the commit's hash. +// Changes with open PRs are excluded from the final list. The modified list of changes is then reassigned +// back to refsChanged.Changes. +func filterChangesForOpenPRs(customBitbucketServerClient *customBitbucketServerClient, refsChanged *refsChangedWebhookEvent) error { + var keptChanges []refsChangedWebHookEventChange -type refsChangedWebhookEvent struct { - EventKey string `json:"eventKey"` - Repository struct { - Slug string `json:"slug"` - Project struct { - Key string `json:"key"` - } `json:"project"` - } `json:"repository"` - Changes []struct { - Ref struct { - Type string `json:"type"` - } `json:"ref"` - ToHash string `json:"toHash"` - Type string `json:"type"` - } `json:"changes"` -} + for _, change := range refsChanged.Changes { + c := change -// customBitbucketClient returns a Bitbucket HTTP client that implements methods that gfleury/go-bitbucket-v1 does not. -// Specifically getting Pull Requests associated to a commit is not supported by gfleury/go-bitbucket-v1. -type customBitbucketClient struct { - client *http.Client - ctx context.Context - token string - url *url.URL -} + if c.Ref.Type != "BRANCH" || c.Type == "DELETE" { + keptChanges = append(keptChanges, c) + continue + } -type pagination struct { - Start int - Limit int -} + // Check if the current commit is associated with an open PR. + hasOpenPR, hasOpenPrErr := refsChangedHasOpenPullRequest( + customBitbucketServerClient, + refsChanged.Repository.Project.Key, + refsChanged.Repository.Slug, + c.ToHash, // Check for the current change's commit hash + ) + if hasOpenPrErr != nil { + return fmt.Errorf("checking if changed branch ref has an open pull request: %w", hasOpenPrErr) + } -func (p *pagination) StartStr() string { - return strconv.Itoa(p.Start) -} + if !hasOpenPR { + keptChanges = append(keptChanges, c) + } + } -func (p *pagination) LimitStr() string { - return strconv.Itoa(p.Limit) -} + refsChanged.Changes = keptChanges -func (c *customBitbucketClient) authHeader(req *http.Request) { - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.token)) + return nil } -func (c *customBitbucketClient) get(u string) ([]byte, error) { - req, err := http.NewRequestWithContext(c.ctx, http.MethodGet, u, nil) - if err != nil { - return nil, err - } - - c.authHeader(req) - - res, err := c.client.Do(req) +// refsChangedHasOpenPullRequest returns true if the changed commit has an open pull request. +func refsChangedHasOpenPullRequest(customBitbucketServerClient *customBitbucketServerClient, project, repository, commit string) (bool, error) { + bitbucketPullRequests, err := customBitbucketServerClient.GetCommitPullRequests(project, repository, commit) if err != nil { - return nil, err + return false, fmt.Errorf("getting commit pull requests for project %s, repository %s and commit %s: %w", + project, repository, commit, err) } - defer func() { - _ = res.Body.Close() - }() - if res.StatusCode > 299 { - resBody, readErr := io.ReadAll(res.Body) - if readErr != nil { - return nil, readErr + for _, bitbucketPullRequest := range bitbucketPullRequests { + if strings.EqualFold(bitbucketPullRequest.State, "OPEN") { + return true, nil } - - return nil, fmt.Errorf("calling endpoint '%s' failed: status %d: response body: %s", u, res.StatusCode, resBody) } - return io.ReadAll(res.Body) -} - -// pullRequestRes is a struct containing information about the Pull Request. -type pullRequestRes struct { - ID int `json:"id"` - State string `json:"state"` -} - -// pagedPullRequestsRes is a paged response with values of pullRequestRes. -type pagedPullRequestsRes struct { - Size int `json:"size"` - Limit int `json:"limit"` - IsLastPage bool `json:"isLastPage"` - Values []pullRequestRes `json:"values"` - Start int `json:"start"` - NextPageStart int `json:"nextPageStart"` + return false, nil } -// GetCommitPullRequests returns all the Pull Requests associated to the commit id. -func (c *customBitbucketClient) GetCommitPullRequests(project, repository, commit string) ([]pullRequestRes, error) { - p := pagination{Start: 0, Limit: 500} - - commitsURL := c.url.JoinPath(fmt.Sprintf("api/1.0/projects/%s/repos/%s/commits/%s/pull-requests", project, repository, commit)) - query := commitsURL.Query() - query.Set("limit", p.LimitStr()) - - var pullRequests []pullRequestRes - for { - query.Set("start", p.StartStr()) - commitsURL.RawQuery = query.Encode() - - body, err := c.get(commitsURL.String()) - if err != nil { - return nil, err - } +func validateBitbucketServerRequest(hookSecret string, request *http.Request) ([]byte, error) { + body, err := io.ReadAll(request.Body) + if err != nil { + return nil, fmt.Errorf("failed to parse request body, %w", err) + } - var pagedPullRequests pagedPullRequestsRes - err = json.Unmarshal(body, &pagedPullRequests) - if err != nil { - return nil, err + if len(hookSecret) != 0 { + signature := request.Header.Get("X-Hub-Signature") + if len(signature) == 0 { + return nil, fmt.Errorf("missing signature header") } - pullRequests = append(pullRequests, pagedPullRequests.Values...) + mac := hmac.New(sha256.New, []byte(hookSecret)) + _, _ = mac.Write(body) + expectedMAC := hex.EncodeToString(mac.Sum(nil)) - if pagedPullRequests.IsLastPage { - break + if !hmac.Equal([]byte(signature[7:]), []byte(expectedMAC)) { + return nil, fmt.Errorf("hmac verification failed") } - - p.Start = pagedPullRequests.NextPageStart } - return pullRequests, nil + return body, nil } diff --git a/eventsources/sources/bitbucketserver/types.go b/eventsources/sources/bitbucketserver/types.go index 45ad1d8af3..920f4ba1b3 100644 --- a/eventsources/sources/bitbucketserver/types.go +++ b/eventsources/sources/bitbucketserver/types.go @@ -53,7 +53,7 @@ type Router struct { // client is the bitbucket server client client *bitbucketv1.APIClient // customClient is a custom bitbucket server client which implements a method the gfleury/go-bitbucket-v1 client is missing - customClient *customBitbucketClient + customClient *customBitbucketServerClient // deleteClient is used to delete webhooks. This client does not contain the cancelable context of the default client deleteClient *bitbucketv1.APIClient // hookIDs is a map of webhook IDs @@ -63,6 +63,6 @@ type Router struct { hookIDs map[string]int // hookSecret is a Bitbucket Server webhook secret hookSecret string - // bitbucketserverEventSource is the event source that contains configuration necessary to consume events from Bitbucket Server - bitbucketserverEventSource *v1alpha1.BitbucketServerEventSource + // bitbucketServerEventSource is the event source that contains configuration necessary to consume events from Bitbucket Server + bitbucketServerEventSource *v1alpha1.BitbucketServerEventSource } diff --git a/eventsources/sources/bitbucketserver/validate.go b/eventsources/sources/bitbucketserver/validate.go index 2e1187a131..88965956f8 100644 --- a/eventsources/sources/bitbucketserver/validate.go +++ b/eventsources/sources/bitbucketserver/validate.go @@ -34,9 +34,6 @@ func validate(eventSource *v1alpha1.BitbucketServerEventSource) error { if eventSource == nil { return common.ErrNilEventSource } - if eventSource.GetBitbucketServerRepositories() == nil && len(eventSource.Projects) == 0 { - return fmt.Errorf("at least one project or repository configuration is required") - } if eventSource.ShouldCreateWebhooks() && len(eventSource.Events) == 0 { return fmt.Errorf("events must be defined to create a bitbucket server webhook") } diff --git a/eventsources/sources/bitbucketserver/validate_test.go b/eventsources/sources/bitbucketserver/validate_test.go index e767d6685d..9687f0fb43 100644 --- a/eventsources/sources/bitbucketserver/validate_test.go +++ b/eventsources/sources/bitbucketserver/validate_test.go @@ -28,12 +28,12 @@ import ( "github.com/argoproj/argo-events/pkg/apis/eventsource/v1alpha1" ) -func TestValidateEventSource(t *testing.T) { +func TestValidateBitbucketServerEventSource(t *testing.T) { listener := &EventListener{} err := listener.ValidateEventSource(context.Background()) assert.Error(t, err) - assert.Equal(t, "at least one project or repository configuration is required", err.Error()) + assert.Equal(t, "bitbucket server base url can't be empty", err.Error()) content, err := os.ReadFile(fmt.Sprintf("%s/%s", sources.EventSourceDir, "bitbucketserver.yaml")) assert.Nil(t, err) diff --git a/go.mod b/go.mod index 739df1339c..51a36858d6 100644 --- a/go.mod +++ b/go.mod @@ -81,7 +81,6 @@ require ( go.uber.org/ratelimit v0.3.1 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.25.0 - golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f google.golang.org/api v0.181.0 google.golang.org/grpc v1.63.2 gopkg.in/jcmturner/gokrb5.v5 v5.3.0 @@ -302,6 +301,7 @@ require ( go.opentelemetry.io/otel/trace v1.24.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect + golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/oauth2 v0.20.0 // indirect diff --git a/pkg/apis/eventsource/v1alpha1/generated.pb.go b/pkg/apis/eventsource/v1alpha1/generated.pb.go index 9109e8edfb..63d69344a1 100644 --- a/pkg/apis/eventsource/v1alpha1/generated.pb.go +++ b/pkg/apis/eventsource/v1alpha1/generated.pb.go @@ -1770,466 +1770,468 @@ func init() { } var fileDescriptor_c9ac5d6cd016403b = []byte{ - // 7343 bytes of a gzipped FileDescriptorProto + // 7364 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x6d, 0x6c, 0x24, 0xc7, 0x75, 0xa0, 0x86, 0x33, 0x1c, 0xce, 0xbc, 0xe1, 0x67, 0xed, 0x6a, 0x35, 0xa2, 0xb5, 0xcb, 0x3d, - 0x0a, 0x5e, 0x48, 0x77, 0x12, 0x79, 0xda, 0x3b, 0x9f, 0x65, 0xe9, 0x2c, 0x63, 0x86, 0x5c, 0xee, + 0x0a, 0x5e, 0x48, 0x77, 0x12, 0x79, 0xda, 0x3b, 0x9f, 0x65, 0xe9, 0x2c, 0x63, 0x86, 0xdc, 0xe5, 0x52, 0x4b, 0x72, 0x87, 0xd5, 0x5c, 0x69, 0x65, 0x59, 0x92, 0x9b, 0x3d, 0xc5, 0x61, 0x9b, 0x3d, 0xdd, 0xc3, 0xee, 0x9e, 0xdd, 0xe5, 0x02, 0x67, 0x1b, 0x06, 0x7c, 0x77, 0xd6, 0x87, 0x6d, 0xdd, - 0xc5, 0x49, 0x90, 0xc0, 0x40, 0x9c, 0x04, 0x0e, 0x82, 0x04, 0xf9, 0x17, 0x23, 0x7f, 0x83, 0xe4, - 0x87, 0x91, 0xe4, 0x87, 0x93, 0x5f, 0x4e, 0x0c, 0x2c, 0x6c, 0x06, 0xf9, 0x97, 0x3f, 0x81, 0x7f, - 0x25, 0xbf, 0x82, 0xfa, 0xe8, 0xea, 0xea, 0x8f, 0xe1, 0x72, 0x38, 0x3d, 0xe4, 0xca, 0xc8, 0x2f, - 0x72, 0xea, 0xbd, 0x7a, 0xef, 0x75, 0xf5, 0x7b, 0xaf, 0x5e, 0xbd, 0xaa, 0x7a, 0x0d, 0xeb, 0x2d, - 0xd3, 0xdf, 0xed, 0x6e, 0x2f, 0x18, 0x4e, 0x7b, 0x51, 0x77, 0x5b, 0x4e, 0xc7, 0x75, 0xbe, 0xc2, - 0xfe, 0x79, 0x91, 0xdc, 0x25, 0xb6, 0xef, 0x2d, 0x76, 0xf6, 0x5a, 0x8b, 0x7a, 0xc7, 0xf4, 0x16, - 0xf9, 0x6f, 0xa7, 0xeb, 0x1a, 0x64, 0xf1, 0xee, 0x4b, 0xba, 0xd5, 0xd9, 0xd5, 0x5f, 0x5a, 0x6c, - 0x11, 0x9b, 0xb8, 0xba, 0x4f, 0x9a, 0x0b, 0x1d, 0xd7, 0xf1, 0x1d, 0xf4, 0xf9, 0x90, 0xdc, 0x42, - 0x40, 0x8e, 0xfd, 0xf3, 0x1e, 0xef, 0xbe, 0xd0, 0xd9, 0x6b, 0x2d, 0x50, 0x72, 0x0b, 0x0a, 0xb9, - 0x85, 0x80, 0xdc, 0xec, 0x17, 0x8e, 0x2d, 0x8d, 0xe1, 0xb4, 0xdb, 0x8e, 0x1d, 0xe7, 0x3f, 0xfb, - 0xa2, 0x42, 0xa0, 0xe5, 0xb4, 0x9c, 0x45, 0xd6, 0xbc, 0xdd, 0xdd, 0x61, 0xbf, 0xd8, 0x0f, 0xf6, - 0x9f, 0x40, 0x9f, 0xdf, 0x7b, 0xd9, 0x5b, 0x30, 0x1d, 0x4a, 0x72, 0xd1, 0x70, 0x5c, 0xfa, 0x60, - 0x09, 0x92, 0xff, 0x3d, 0xc4, 0x69, 0xeb, 0xc6, 0xae, 0x69, 0x13, 0xf7, 0x20, 0x94, 0xa3, 0x4d, - 0x7c, 0x3d, 0xad, 0xd7, 0x62, 0xaf, 0x5e, 0x6e, 0xd7, 0xf6, 0xcd, 0x36, 0x49, 0x74, 0xf8, 0x1f, - 0x8f, 0xea, 0xe0, 0x19, 0xbb, 0xa4, 0xad, 0xc7, 0xfb, 0xcd, 0xff, 0x6b, 0x0e, 0x66, 0x6a, 0xeb, - 0x9b, 0x8d, 0x25, 0xc7, 0xf6, 0xba, 0x6d, 0xb2, 0xe4, 0xd8, 0x3b, 0x66, 0x0b, 0x7d, 0x06, 0x2a, - 0x06, 0x6f, 0x70, 0xb7, 0xf4, 0x56, 0x35, 0x77, 0x39, 0xf7, 0x5c, 0xb9, 0x7e, 0xee, 0xc7, 0x0f, - 0xe7, 0x9e, 0x38, 0x7c, 0x38, 0x57, 0x59, 0x0a, 0x41, 0x58, 0xc5, 0x43, 0xcf, 0xc3, 0x98, 0xde, - 0xf5, 0x9d, 0x9a, 0xb1, 0x57, 0x1d, 0xb9, 0x9c, 0x7b, 0xae, 0x54, 0x9f, 0x12, 0x5d, 0xc6, 0x6a, - 0xbc, 0x19, 0x07, 0x70, 0xb4, 0x08, 0x65, 0x72, 0xdf, 0xb0, 0xba, 0x9e, 0x79, 0x97, 0x54, 0xf3, - 0x0c, 0x79, 0x46, 0x20, 0x97, 0xaf, 0x05, 0x00, 0x1c, 0xe2, 0x50, 0xda, 0xb6, 0xb3, 0xe6, 0x18, - 0xba, 0x55, 0x2d, 0x44, 0x69, 0x6f, 0xf0, 0x66, 0x1c, 0xc0, 0xd1, 0x15, 0x28, 0xda, 0xce, 0x9b, - 0xba, 0xe9, 0x57, 0x47, 0x19, 0xe6, 0xa4, 0xc0, 0x2c, 0x6e, 0xb0, 0x56, 0x2c, 0xa0, 0xf3, 0xff, - 0x5c, 0x81, 0x29, 0xfa, 0xec, 0xd7, 0xa8, 0x72, 0x68, 0x4c, 0x97, 0xd0, 0x45, 0xc8, 0x77, 0x5d, - 0x4b, 0x3c, 0x71, 0x45, 0x74, 0xcc, 0xdf, 0xc6, 0x6b, 0x98, 0xb6, 0xa3, 0x97, 0x61, 0x9c, 0xdc, - 0x37, 0x76, 0x75, 0xbb, 0x45, 0x36, 0xf4, 0x36, 0x61, 0x8f, 0x59, 0xae, 0x9f, 0x17, 0x78, 0xe3, - 0xd7, 0x14, 0x18, 0x8e, 0x60, 0xaa, 0x3d, 0xb7, 0x0e, 0x3a, 0xfc, 0x99, 0x53, 0x7a, 0x52, 0x18, - 0x8e, 0x60, 0xa2, 0xab, 0x00, 0xae, 0xd3, 0xf5, 0x4d, 0xbb, 0x75, 0x93, 0x1c, 0xb0, 0x87, 0x2f, - 0xd7, 0x91, 0xe8, 0x07, 0x58, 0x42, 0xb0, 0x82, 0x85, 0xfe, 0x17, 0xcc, 0x18, 0x8e, 0x6d, 0x13, - 0xc3, 0x37, 0x1d, 0xbb, 0xae, 0x1b, 0x7b, 0xce, 0xce, 0x0e, 0x1b, 0x8d, 0xca, 0xd5, 0x97, 0x17, - 0x8e, 0x6d, 0x64, 0xdc, 0x4a, 0x16, 0x44, 0xff, 0xfa, 0x93, 0x87, 0x0f, 0xe7, 0x66, 0x96, 0xe2, - 0x64, 0x71, 0x92, 0x13, 0x7a, 0x01, 0x4a, 0x5f, 0xf1, 0x1c, 0xbb, 0xee, 0x34, 0x0f, 0xaa, 0x45, - 0xf6, 0x0e, 0xa6, 0x85, 0xc0, 0xa5, 0xd7, 0xb5, 0x5b, 0x1b, 0xb4, 0x1d, 0x4b, 0x0c, 0x74, 0x1b, - 0xf2, 0xbe, 0xe5, 0x55, 0xc7, 0x98, 0x78, 0xaf, 0xf4, 0x2d, 0xde, 0xd6, 0x9a, 0xc6, 0xd5, 0xb6, - 0x3e, 0x46, 0xdf, 0xd5, 0xd6, 0x9a, 0x86, 0x29, 0x3d, 0xf4, 0x7e, 0x0e, 0x4a, 0xd4, 0xbe, 0x9a, - 0xba, 0xaf, 0x57, 0x4b, 0x97, 0xf3, 0xcf, 0x55, 0xae, 0x7e, 0x69, 0x61, 0x20, 0x07, 0xb3, 0x10, - 0xd3, 0x96, 0x85, 0x75, 0x41, 0xfe, 0x9a, 0xed, 0xbb, 0x07, 0xe1, 0x33, 0x06, 0xcd, 0x58, 0xf2, - 0x47, 0xbf, 0x91, 0x83, 0xa9, 0xe0, 0xad, 0x2e, 0x13, 0xc3, 0xd2, 0x5d, 0x52, 0x2d, 0xb3, 0x07, - 0xbe, 0x93, 0x85, 0x4c, 0x51, 0xca, 0x62, 0x38, 0xce, 0x1d, 0x3e, 0x9c, 0x9b, 0x8a, 0x81, 0x70, - 0x5c, 0x0a, 0xf4, 0x41, 0x0e, 0xc6, 0xf7, 0xbb, 0xa4, 0x2b, 0xc5, 0x02, 0x26, 0xd6, 0xed, 0x0c, - 0xc4, 0xda, 0x54, 0xc8, 0x0a, 0x99, 0xa6, 0xa9, 0xb2, 0xab, 0xed, 0x38, 0xc2, 0x1c, 0x7d, 0x0d, - 0xca, 0xec, 0x77, 0xdd, 0xb4, 0x9b, 0xd5, 0x0a, 0x93, 0x04, 0x67, 0x25, 0x09, 0xa5, 0x29, 0xc4, - 0x98, 0xa0, 0x7e, 0x46, 0x36, 0xe2, 0x90, 0x27, 0xba, 0x07, 0x63, 0xc2, 0xa5, 0x55, 0xc7, 0x19, - 0xfb, 0x46, 0x06, 0xec, 0x23, 0xde, 0xb5, 0x5e, 0xa1, 0x5e, 0x4b, 0x34, 0xe1, 0x80, 0x1b, 0xba, - 0x03, 0x05, 0xbd, 0xeb, 0xef, 0x56, 0x27, 0x4e, 0x68, 0x06, 0x75, 0xdd, 0x33, 0x8d, 0x5a, 0xd7, - 0xdf, 0xad, 0x97, 0x0e, 0x1f, 0xce, 0x15, 0xe8, 0x7f, 0x98, 0x51, 0x44, 0x18, 0xca, 0x5d, 0xd7, - 0xd2, 0x88, 0xe1, 0x12, 0xbf, 0x3a, 0xc9, 0xc8, 0x7f, 0x7a, 0x81, 0xcf, 0x17, 0x94, 0xc2, 0x02, - 0x9d, 0xba, 0x16, 0xee, 0xbe, 0xb4, 0xc0, 0x31, 0x6e, 0x92, 0x03, 0x8d, 0x58, 0xc4, 0xf0, 0x1d, - 0x97, 0x0f, 0xd3, 0x6d, 0xbc, 0xc6, 0x21, 0x38, 0x24, 0x83, 0x7c, 0x28, 0xee, 0x98, 0x96, 0x4f, - 0xdc, 0xea, 0x54, 0x26, 0xa3, 0xa4, 0x58, 0xd5, 0x0a, 0xa3, 0x5b, 0x07, 0xea, 0xb1, 0xf9, 0xff, - 0x58, 0xf0, 0x9a, 0x7d, 0x15, 0x26, 0x22, 0x26, 0x87, 0xa6, 0x21, 0xbf, 0x47, 0x0e, 0xb8, 0xbb, - 0xc6, 0xf4, 0x5f, 0x74, 0x1e, 0x46, 0xef, 0xea, 0x56, 0x57, 0xb8, 0x66, 0xcc, 0x7f, 0xbc, 0x32, - 0xf2, 0x72, 0x6e, 0xfe, 0x27, 0x39, 0x78, 0xba, 0xa7, 0xb1, 0xd0, 0xf9, 0xa5, 0xd9, 0x75, 0xf5, - 0x6d, 0x8b, 0x30, 0x6a, 0xca, 0xfc, 0xb2, 0xcc, 0x9b, 0x71, 0x00, 0xa7, 0x0e, 0x99, 0x4e, 0x63, - 0xcb, 0xc4, 0x22, 0x3e, 0x11, 0x33, 0x9d, 0x74, 0xc8, 0x35, 0x09, 0xc1, 0x0a, 0x16, 0xf5, 0x88, - 0xa6, 0xed, 0x13, 0xd7, 0xd6, 0x2d, 0x31, 0xdd, 0x49, 0x6f, 0xb1, 0x2a, 0xda, 0xb1, 0xc4, 0x50, - 0x66, 0xb0, 0xc2, 0x91, 0x33, 0xd8, 0xe7, 0xe1, 0x5c, 0x8a, 0x76, 0x2b, 0xdd, 0x73, 0x47, 0x76, - 0xff, 0xbd, 0x11, 0xb8, 0x90, 0x6e, 0xa7, 0xe8, 0x32, 0x14, 0x6c, 0x3a, 0xc1, 0xf1, 0x89, 0x70, - 0x5c, 0x10, 0x28, 0xb0, 0x89, 0x8d, 0x41, 0xd4, 0x01, 0x1b, 0xe9, 0x6b, 0xc0, 0xf2, 0xc7, 0x1a, - 0xb0, 0x48, 0x80, 0x50, 0x38, 0x46, 0x80, 0x70, 0xcc, 0x59, 0x9f, 0x12, 0xd6, 0xdd, 0x56, 0xb7, - 0x4d, 0x95, 0x90, 0x4d, 0x4e, 0xe5, 0x90, 0x70, 0x2d, 0x00, 0xe0, 0x10, 0x67, 0xfe, 0xfd, 0x51, - 0x78, 0xba, 0xf6, 0xa0, 0xeb, 0x12, 0xa6, 0xa3, 0xde, 0x8d, 0xee, 0xb6, 0x1a, 0x30, 0x5c, 0x86, - 0xc2, 0xce, 0x7e, 0xd3, 0x8e, 0x0f, 0xd4, 0xca, 0xe6, 0xf2, 0x06, 0x66, 0x10, 0xd4, 0x81, 0x73, - 0xde, 0xae, 0xee, 0x92, 0x66, 0xcd, 0x30, 0x88, 0xe7, 0xdd, 0x24, 0x07, 0x32, 0x74, 0x38, 0xb6, - 0x21, 0x3e, 0x75, 0xf8, 0x70, 0xee, 0x9c, 0x96, 0xa4, 0x82, 0xd3, 0x48, 0xa3, 0x26, 0x4c, 0xc5, - 0x9a, 0xd9, 0xa0, 0x1f, 0x9b, 0x1b, 0x9b, 0x38, 0x62, 0xdc, 0x70, 0x9c, 0x24, 0x55, 0x80, 0xdd, - 0xee, 0x36, 0x7b, 0x16, 0x1e, 0x94, 0x48, 0x05, 0xb8, 0xc1, 0x9b, 0x71, 0x00, 0x47, 0xbf, 0xa6, - 0x4e, 0xc5, 0xa3, 0x6c, 0x2a, 0xde, 0x19, 0xd4, 0xad, 0xf6, 0x7a, 0x23, 0x7d, 0x4c, 0xca, 0xa1, - 0x13, 0x2b, 0x7e, 0x52, 0x9c, 0xd8, 0xef, 0x14, 0xe1, 0x19, 0xf6, 0xe8, 0xcc, 0x66, 0x35, 0xdf, - 0x71, 0xf5, 0x16, 0x51, 0xf5, 0xf1, 0x75, 0x40, 0x1e, 0x6f, 0xad, 0x19, 0x86, 0xd3, 0xb5, 0xfd, - 0x8d, 0xd0, 0x8c, 0x67, 0xc5, 0x58, 0x20, 0x2d, 0x81, 0x81, 0x53, 0x7a, 0xa1, 0x16, 0x4c, 0x87, - 0xb1, 0x9d, 0xe6, 0xbb, 0xa6, 0xdd, 0xea, 0x4f, 0x6d, 0xcf, 0x1f, 0x3e, 0x9c, 0x9b, 0x5e, 0x8a, - 0x91, 0xc0, 0x09, 0xa2, 0xd4, 0x26, 0xd9, 0x0c, 0xcc, 0x64, 0xcd, 0x47, 0x6d, 0x72, 0x33, 0x00, - 0xe0, 0x10, 0x27, 0x12, 0x60, 0x16, 0x1e, 0x19, 0x60, 0x5e, 0x84, 0x7c, 0xd3, 0xda, 0x17, 0x7e, - 0x41, 0x06, 0xf5, 0xcb, 0x6b, 0x9b, 0x98, 0xb6, 0xd3, 0xd8, 0x2c, 0xd4, 0xce, 0x22, 0xd3, 0x4e, - 0x33, 0x0b, 0xed, 0xec, 0xf1, 0x8a, 0x4e, 0xa4, 0xa0, 0x63, 0xa7, 0xa7, 0xa0, 0xe8, 0x55, 0x98, - 0x68, 0x12, 0xc3, 0x69, 0x92, 0x75, 0xe2, 0x79, 0x7a, 0x8b, 0x54, 0x4b, 0x6c, 0xe0, 0x9e, 0x14, - 0x82, 0x4e, 0x2c, 0xab, 0x40, 0x1c, 0xc5, 0x45, 0x4b, 0x30, 0x73, 0x4f, 0x37, 0xfd, 0x2d, 0xb3, - 0x4d, 0x56, 0x6d, 0x8d, 0x18, 0x8e, 0xdd, 0xf4, 0x58, 0xa4, 0x3b, 0xca, 0xd7, 0x0f, 0x6f, 0xc6, - 0x81, 0x38, 0x89, 0x3f, 0x98, 0x89, 0xfc, 0xb4, 0x08, 0xb3, 0x6c, 0xfc, 0x35, 0xe2, 0xde, 0x35, - 0x0d, 0x52, 0xef, 0x7a, 0xaa, 0x81, 0xa4, 0x29, 0x75, 0x6e, 0xe8, 0x4a, 0x3d, 0x72, 0x0c, 0xa5, - 0x5e, 0x84, 0xb2, 0xef, 0x74, 0x4c, 0x23, 0xcd, 0x0a, 0xb6, 0x02, 0x00, 0x0e, 0x71, 0xd0, 0x32, - 0x4c, 0x7b, 0xdd, 0x6d, 0xcf, 0x70, 0xcd, 0x0e, 0xe5, 0xab, 0xb8, 0xe2, 0xaa, 0xe8, 0x37, 0xad, - 0xc5, 0xe0, 0x38, 0xd1, 0x23, 0x58, 0x7e, 0x8d, 0x66, 0xbc, 0xfc, 0xea, 0x6f, 0x0d, 0xf8, 0x3d, - 0xd5, 0x06, 0xc7, 0x98, 0x0d, 0xb6, 0xb2, 0xb0, 0xc1, 0x54, 0x1d, 0x38, 0x91, 0x05, 0x96, 0x4e, - 0xd1, 0x02, 0xdf, 0x82, 0xa7, 0x76, 0xba, 0x96, 0x75, 0xb0, 0xd9, 0xd5, 0x2d, 0x73, 0xc7, 0x24, - 0x4d, 0xfa, 0xa2, 0xbc, 0x8e, 0x6e, 0xf0, 0x45, 0x63, 0xb9, 0x3e, 0x27, 0x44, 0x7e, 0x6a, 0x25, - 0x1d, 0x0d, 0xf7, 0xea, 0x3f, 0x98, 0x69, 0xfd, 0x43, 0x0e, 0x26, 0xea, 0xa6, 0xbf, 0xdd, 0x35, - 0xf6, 0x88, 0x4f, 0x57, 0x18, 0xc8, 0x85, 0xd1, 0x6d, 0xba, 0xf0, 0x10, 0x26, 0xb4, 0x39, 0xe0, - 0xf0, 0x48, 0xe2, 0xe1, 0x6a, 0xa6, 0x7c, 0xf8, 0x70, 0x6e, 0x94, 0xfd, 0xc4, 0x9c, 0x15, 0xba, - 0x0d, 0xe0, 0xd0, 0x85, 0xcd, 0x96, 0xb3, 0x47, 0xec, 0xfe, 0x26, 0xa4, 0x49, 0x1a, 0x71, 0xde, - 0xaa, 0x05, 0x9d, 0xb1, 0x42, 0x68, 0xfe, 0x47, 0x39, 0x40, 0x49, 0xfe, 0xe8, 0x16, 0x94, 0xba, - 0x1e, 0x0d, 0xcb, 0xc5, 0x34, 0x7a, 0x6c, 0x5e, 0xe3, 0x54, 0xa5, 0x6e, 0x8b, 0xae, 0x58, 0x12, - 0xa1, 0x04, 0x3b, 0xba, 0xe7, 0xdd, 0x73, 0xdc, 0x66, 0x7f, 0xc2, 0x33, 0x82, 0x0d, 0xd1, 0x15, - 0x4b, 0x22, 0xf3, 0xbf, 0x1c, 0x83, 0xf3, 0x52, 0xf0, 0x58, 0x2c, 0xd0, 0x64, 0xd1, 0xf4, 0x0d, - 0xc7, 0xd9, 0xbb, 0x65, 0xaf, 0x98, 0xb6, 0xe9, 0xed, 0x8a, 0x35, 0x81, 0x8c, 0x05, 0x96, 0x13, - 0x18, 0x38, 0xa5, 0x17, 0xfa, 0x8e, 0x6a, 0xa0, 0x23, 0xcc, 0x40, 0xf5, 0xac, 0x5e, 0xf6, 0x49, - 0x4d, 0x73, 0xec, 0x1e, 0xd9, 0xde, 0x75, 0x9c, 0x3d, 0x11, 0xdd, 0xae, 0x0f, 0x28, 0xcf, 0x9b, - 0x9c, 0xda, 0x92, 0x63, 0xfb, 0xe4, 0xbe, 0xcf, 0x97, 0xe9, 0xa2, 0x0d, 0x07, 0xac, 0xd0, 0x57, - 0xc4, 0x32, 0xbd, 0xc0, 0x58, 0xae, 0x65, 0x35, 0x04, 0xa9, 0x0b, 0xf7, 0x79, 0x28, 0xf2, 0x5e, - 0x2c, 0x66, 0x2e, 0x73, 0x57, 0xc1, 0x63, 0x5e, 0x2c, 0x20, 0xe8, 0x45, 0x18, 0x75, 0xee, 0xd9, - 0x22, 0x84, 0x2d, 0xd7, 0x9f, 0x12, 0x03, 0x36, 0xb5, 0x4c, 0x3a, 0x2e, 0x31, 0x74, 0x9f, 0x34, - 0x6f, 0x51, 0x30, 0xe6, 0x58, 0xe8, 0x7f, 0x02, 0x50, 0x11, 0x89, 0x41, 0x35, 0x8b, 0x45, 0x15, - 0xe5, 0xfa, 0x33, 0xa2, 0xcf, 0xf9, 0xb0, 0x4f, 0x43, 0xe2, 0x60, 0x05, 0x1f, 0xdd, 0x80, 0x49, - 0x97, 0x74, 0x1c, 0xcf, 0xf4, 0x1d, 0xf7, 0x40, 0xb3, 0xba, 0x2d, 0xe6, 0x15, 0xcb, 0xf5, 0xcb, - 0x82, 0x42, 0x35, 0xa4, 0x80, 0x23, 0x78, 0x38, 0xd6, 0x0f, 0x7d, 0x98, 0x83, 0x71, 0xd9, 0x64, - 0x12, 0x1a, 0x22, 0xe4, 0x33, 0xc8, 0xf5, 0xc8, 0xf1, 0x0c, 0xd9, 0x87, 0x39, 0x56, 0xac, 0xf0, - 0xc3, 0x11, 0xee, 0x8a, 0x9b, 0x87, 0x4f, 0xca, 0x4a, 0xe0, 0x01, 0x9c, 0x4b, 0x79, 0x5a, 0xf4, - 0x6c, 0xa0, 0x0f, 0x3c, 0xe4, 0x9f, 0x10, 0x0f, 0x3f, 0x1a, 0xd1, 0x82, 0xd7, 0x12, 0xef, 0x91, - 0xc7, 0x27, 0x17, 0x04, 0xf6, 0xe4, 0xd1, 0x6f, 0x6f, 0xfe, 0x0f, 0x2a, 0x30, 0x2b, 0x99, 0xd3, - 0x29, 0x96, 0xb8, 0xaa, 0xdf, 0x51, 0x2c, 0x33, 0x77, 0x7a, 0x96, 0x19, 0x55, 0xed, 0x91, 0x81, - 0x55, 0x3b, 0x7f, 0x42, 0xd5, 0x7e, 0x0e, 0x4a, 0x82, 0xae, 0x57, 0x2d, 0x30, 0xbb, 0xe5, 0x8e, - 0x5b, 0xb4, 0x61, 0x09, 0x45, 0xff, 0x2f, 0x6e, 0x04, 0x7c, 0x69, 0x7c, 0x27, 0x2b, 0x23, 0xe0, - 0x6f, 0xa6, 0x4f, 0x53, 0x08, 0x9d, 0x4e, 0xb1, 0xa7, 0xd3, 0xd9, 0x83, 0x8b, 0xde, 0x9e, 0xd9, - 0xa9, 0xbb, 0xba, 0x6d, 0xec, 0x62, 0xb2, 0xe3, 0x2d, 0xb1, 0x8c, 0x5a, 0xf3, 0x96, 0x7d, 0xab, - 0x43, 0xec, 0x06, 0x66, 0x8e, 0xa5, 0x54, 0xff, 0xb4, 0x60, 0x77, 0x51, 0x3b, 0x0a, 0x19, 0x1f, - 0x4d, 0x0b, 0xdd, 0x81, 0x8a, 0xce, 0x92, 0x0e, 0x7c, 0xbe, 0x2f, 0xf5, 0x33, 0x65, 0x4e, 0x1d, - 0x3e, 0x9c, 0xab, 0xd4, 0xc2, 0xde, 0x58, 0x25, 0x85, 0xde, 0x85, 0x09, 0xa1, 0x3c, 0x22, 0x39, - 0x5a, 0xee, 0x87, 0xf6, 0x0c, 0x5d, 0x0b, 0xbd, 0xa9, 0xf6, 0xc7, 0x51, 0x72, 0xe8, 0x0d, 0xb8, - 0xb0, 0x1d, 0xbc, 0x0b, 0x8f, 0xbd, 0x8b, 0xba, 0xee, 0x91, 0xdb, 0x78, 0x8d, 0x79, 0x99, 0x72, - 0xfd, 0x92, 0x18, 0x9f, 0x0b, 0xb1, 0x37, 0x26, 0xb0, 0x70, 0x8f, 0xde, 0x3d, 0xe6, 0xf5, 0xca, - 0x89, 0xe6, 0xf5, 0x48, 0xe0, 0x3d, 0x9e, 0x49, 0xe0, 0xdd, 0xdb, 0x33, 0x9c, 0x28, 0xf0, 0x9e, - 0x38, 0xc5, 0xc0, 0x5b, 0xac, 0x85, 0x26, 0x33, 0x5e, 0x0b, 0xbd, 0x0a, 0x13, 0xc6, 0x2e, 0x31, - 0xf6, 0x58, 0xaa, 0xf7, 0xae, 0x6e, 0xb1, 0xa4, 0x79, 0x39, 0x5c, 0x51, 0x2f, 0xa9, 0x40, 0x1c, - 0xc5, 0x1d, 0x6c, 0x96, 0xf8, 0x4e, 0x0e, 0x9e, 0xee, 0xe9, 0x0f, 0xd0, 0xd5, 0x88, 0xcb, 0xcc, - 0x45, 0xb7, 0x16, 0x7b, 0x38, 0xca, 0x41, 0xe7, 0x8e, 0xdf, 0x1f, 0x85, 0x73, 0x4b, 0xba, 0x45, - 0xec, 0xa6, 0x1e, 0x99, 0x34, 0x5e, 0x80, 0x92, 0x67, 0xec, 0x92, 0x66, 0xd7, 0x0a, 0xd2, 0x55, - 0x52, 0x3d, 0x34, 0xd1, 0x8e, 0x25, 0x86, 0xcc, 0xa7, 0xd3, 0xc1, 0x1c, 0x89, 0x62, 0xcb, 0x71, - 0x94, 0x18, 0xe8, 0x15, 0x98, 0x14, 0x89, 0x62, 0xc7, 0x5e, 0xd6, 0x7d, 0xe2, 0x55, 0xf3, 0xcc, - 0xb7, 0x21, 0x2a, 0xef, 0xb5, 0x08, 0x04, 0xc7, 0x30, 0x29, 0x27, 0xdf, 0x6c, 0x93, 0x07, 0x8e, - 0x1d, 0x2c, 0xae, 0x25, 0xa7, 0x2d, 0xd1, 0x8e, 0x25, 0x06, 0xfa, 0x76, 0x32, 0xd3, 0xf9, 0xe5, - 0x01, 0x35, 0x37, 0x65, 0xb0, 0xfa, 0xb0, 0xa3, 0x6f, 0xe4, 0xa0, 0xd2, 0x21, 0xae, 0x67, 0x7a, - 0x3e, 0xb1, 0x0d, 0x22, 0x32, 0x9d, 0xb7, 0xb2, 0xb0, 0xa6, 0x46, 0x48, 0x96, 0x3b, 0x5a, 0xa5, - 0x01, 0xab, 0x4c, 0xcf, 0x66, 0x15, 0x3d, 0x98, 0xe1, 0xdc, 0x87, 0xf3, 0x4b, 0xba, 0x6f, 0xec, - 0x76, 0x3b, 0xdc, 0xa2, 0xbb, 0xae, 0xee, 0x9b, 0x8e, 0x8d, 0x9e, 0x87, 0x31, 0x62, 0xeb, 0xdb, - 0x16, 0x69, 0xc6, 0xf7, 0x89, 0xae, 0xf1, 0x66, 0x1c, 0xc0, 0xd1, 0x67, 0xa0, 0xd2, 0xd6, 0xef, - 0x2f, 0x8b, 0x9e, 0x42, 0x4d, 0xe5, 0x29, 0x8a, 0xf5, 0x10, 0x84, 0x55, 0xbc, 0xf9, 0xaf, 0xc2, - 0x79, 0xce, 0x72, 0x5d, 0xef, 0x28, 0x23, 0x7a, 0x8c, 0x2d, 0x99, 0x65, 0x98, 0x36, 0x5c, 0xa2, - 0xfb, 0x64, 0x75, 0x67, 0xc3, 0xf1, 0xaf, 0xdd, 0x37, 0x3d, 0x5f, 0xec, 0xcd, 0xc8, 0x7c, 0xd0, - 0x52, 0x0c, 0x8e, 0x13, 0x3d, 0xe6, 0xbf, 0x3b, 0x06, 0xe8, 0x5a, 0xdb, 0xf4, 0xfd, 0x68, 0x50, - 0x77, 0x05, 0x8a, 0xdb, 0xae, 0xb3, 0x27, 0x23, 0x4b, 0xb9, 0xbf, 0x52, 0x67, 0xad, 0x58, 0x40, - 0xa9, 0x4f, 0x31, 0x76, 0x75, 0xdb, 0x26, 0x56, 0x18, 0x86, 0x49, 0x9f, 0xb2, 0x24, 0x21, 0x58, - 0xc1, 0x62, 0xe7, 0x4d, 0xf8, 0x2f, 0x25, 0xf7, 0x15, 0x9e, 0x37, 0x09, 0x41, 0x58, 0xc5, 0x8b, - 0x2c, 0xcd, 0x0b, 0x59, 0x2f, 0xcd, 0x47, 0x33, 0x58, 0x9a, 0xa7, 0x9f, 0xc3, 0x28, 0x9e, 0xc9, - 0x39, 0x8c, 0xb1, 0xe3, 0x9e, 0xc3, 0x28, 0x65, 0x3c, 0xf9, 0x7d, 0xa4, 0xba, 0x44, 0xbe, 0xcc, - 0x7b, 0x6f, 0x50, 0xfb, 0x4f, 0xa8, 0xe7, 0x89, 0x22, 0x8b, 0x4f, 0xcc, 0x5a, 0xef, 0xe3, 0x11, - 0x98, 0x8e, 0xbb, 0x5c, 0xf4, 0x00, 0xc6, 0x0c, 0xee, 0xa1, 0xc4, 0x2a, 0x4b, 0x1b, 0x78, 0xa2, - 0x49, 0xfa, 0x3b, 0x71, 0x58, 0x81, 0x43, 0x70, 0xc0, 0x10, 0x7d, 0x3d, 0x07, 0x65, 0x23, 0x70, - 0x52, 0x22, 0x8b, 0x35, 0x30, 0xfb, 0x14, 0xa7, 0xc7, 0x4f, 0x20, 0x48, 0x08, 0x0e, 0x99, 0xce, - 0xff, 0x6c, 0x04, 0x2a, 0xaa, 0x7f, 0xfa, 0xb2, 0xa2, 0x65, 0x7c, 0x3c, 0xfe, 0xab, 0x62, 0xbb, - 0xf2, 0x50, 0x5c, 0x28, 0x04, 0xc5, 0xa6, 0xd6, 0x7c, 0x6b, 0x9b, 0x86, 0x36, 0xf4, 0xe5, 0x84, - 0x7e, 0x2a, 0x6c, 0x53, 0x14, 0xa7, 0x03, 0x05, 0xaf, 0x43, 0x0c, 0xf1, 0xb8, 0x1b, 0xd9, 0xa9, - 0x8d, 0xd6, 0x21, 0x46, 0xe8, 0xd0, 0xe9, 0x2f, 0xcc, 0x38, 0xa1, 0xfb, 0x50, 0xf4, 0x7c, 0xdd, - 0xef, 0x7a, 0x22, 0xc3, 0x95, 0xa1, 0xaa, 0x6a, 0x8c, 0x6e, 0xe8, 0xc5, 0xf9, 0x6f, 0x2c, 0xf8, - 0xcd, 0x5f, 0x87, 0x99, 0x84, 0x5e, 0x53, 0xd7, 0x4e, 0xee, 0x77, 0x5c, 0xe2, 0xd1, 0xe8, 0x28, - 0x1e, 0x2e, 0x5e, 0x93, 0x10, 0xac, 0x60, 0xcd, 0xff, 0x3c, 0x07, 0x53, 0x0a, 0xa5, 0x35, 0xd3, - 0xf3, 0xd1, 0x97, 0x12, 0xaf, 0x6a, 0xe1, 0x78, 0xaf, 0x8a, 0xf6, 0x66, 0x2f, 0x4a, 0xda, 0x77, - 0xd0, 0xa2, 0xbc, 0x26, 0x07, 0x46, 0x4d, 0x9f, 0xb4, 0x3d, 0x91, 0xa5, 0x7c, 0x3d, 0xbb, 0x31, - 0x0b, 0xb3, 0x29, 0xab, 0x94, 0x01, 0xe6, 0x7c, 0xe6, 0xff, 0x62, 0x25, 0xf2, 0x88, 0xf4, 0xfd, - 0xb1, 0xe3, 0x7e, 0xb4, 0xa9, 0xde, 0xf5, 0x94, 0x0d, 0xd8, 0xf0, 0xb8, 0x9f, 0x02, 0xc3, 0x11, - 0x4c, 0xb4, 0x0f, 0x25, 0x9f, 0xb4, 0x3b, 0x96, 0xee, 0x07, 0x67, 0x04, 0xae, 0x0f, 0xf8, 0x04, - 0x5b, 0x82, 0x1c, 0x9f, 0xa5, 0x82, 0x5f, 0x58, 0xb2, 0x41, 0x6d, 0x18, 0xf3, 0xf8, 0x3e, 0x89, - 0xd0, 0xb3, 0x95, 0x01, 0x39, 0x06, 0xbb, 0x2e, 0xcc, 0x79, 0x88, 0x1f, 0x38, 0xe0, 0x81, 0xbe, - 0x0a, 0xa3, 0x6d, 0xd3, 0x36, 0x1d, 0x96, 0x1d, 0xa9, 0x5c, 0x7d, 0x2b, 0x5b, 0x43, 0x5a, 0x58, - 0xa7, 0xb4, 0xf9, 0x34, 0x20, 0xdf, 0x17, 0x6b, 0xc3, 0x9c, 0x2d, 0x3b, 0x18, 0x68, 0x88, 0xa0, - 0x5a, 0xc4, 0xe8, 0x5f, 0xca, 0x58, 0x06, 0x19, 0xb3, 0x47, 0x67, 0xa3, 0xa0, 0x19, 0x4b, 0xfe, - 0xe8, 0x01, 0x14, 0x76, 0x4c, 0x8b, 0x88, 0x7d, 0xe7, 0x3b, 0x19, 0xcb, 0xb1, 0x62, 0x5a, 0x84, - 0xcb, 0x10, 0x9e, 0x4c, 0x31, 0x2d, 0x82, 0x19, 0x4f, 0x36, 0x10, 0x2e, 0xe1, 0x34, 0xc4, 0xa6, - 0x5b, 0xd6, 0x03, 0x81, 0x05, 0xf9, 0xd8, 0x40, 0x04, 0xcd, 0x58, 0xf2, 0x47, 0xff, 0x3b, 0x17, - 0x66, 0x0d, 0xf9, 0x69, 0xcd, 0xb7, 0x33, 0x96, 0x45, 0xe4, 0x6a, 0xb8, 0x28, 0x32, 0x6c, 0x4f, - 0xe4, 0x11, 0x1f, 0x40, 0x41, 0x6f, 0xef, 0x77, 0x44, 0xa8, 0x92, 0xf5, 0x1b, 0xa9, 0xb5, 0xf7, - 0x3b, 0xb1, 0x37, 0x52, 0x5b, 0xdf, 0x6c, 0x60, 0xc6, 0x93, 0x9a, 0xc6, 0x9e, 0xbe, 0xb3, 0xa7, - 0x57, 0x61, 0x28, 0xa6, 0x71, 0x93, 0xd2, 0x8e, 0x99, 0x06, 0x6b, 0xc3, 0x9c, 0x2d, 0x7d, 0xf6, - 0xf6, 0xbe, 0xef, 0x57, 0x2b, 0x43, 0x79, 0xf6, 0xf5, 0x7d, 0xdf, 0x8f, 0x3d, 0xfb, 0xfa, 0xe6, - 0xd6, 0x16, 0x66, 0x3c, 0x29, 0x6f, 0x5b, 0xf7, 0x3d, 0x91, 0x84, 0xca, 0x9a, 0xf7, 0x86, 0xee, - 0x7b, 0x31, 0xde, 0x1b, 0xb5, 0x2d, 0x0d, 0x33, 0x9e, 0xe8, 0x2e, 0xe4, 0x3d, 0xdb, 0xab, 0x4e, - 0x30, 0xd6, 0x6f, 0x66, 0xcc, 0x5a, 0xb3, 0x05, 0x67, 0x79, 0xf4, 0x44, 0xdb, 0xd0, 0x30, 0x65, - 0xc8, 0xf8, 0xee, 0x7b, 0xd5, 0xc9, 0xe1, 0xf0, 0xdd, 0x4f, 0xf0, 0xdd, 0xa4, 0x7c, 0xf7, 0x3d, - 0xf4, 0x8d, 0x1c, 0x14, 0x3b, 0xdd, 0x6d, 0xad, 0xbb, 0x5d, 0x9d, 0x62, 0xbc, 0xbf, 0x98, 0x31, - 0xef, 0x06, 0x23, 0xce, 0xd9, 0xcb, 0x18, 0x83, 0x37, 0x62, 0xc1, 0x99, 0x09, 0xc1, 0xb9, 0x56, - 0xa7, 0x87, 0x22, 0xc4, 0x75, 0x46, 0x2d, 0x26, 0x04, 0x6f, 0xc4, 0x82, 0x73, 0x20, 0x84, 0xa5, - 0x6f, 0x57, 0x67, 0x86, 0x25, 0x84, 0xa5, 0xa7, 0x08, 0x61, 0xe9, 0x5c, 0x08, 0x4b, 0xdf, 0xa6, - 0xaa, 0xbf, 0xdb, 0xdc, 0xf1, 0xaa, 0x68, 0x28, 0xaa, 0x7f, 0xa3, 0xb9, 0x13, 0x57, 0xfd, 0x1b, - 0xcb, 0x2b, 0x1a, 0x66, 0x3c, 0xa9, 0xcb, 0xf1, 0x2c, 0xdd, 0xd8, 0xab, 0x9e, 0x1b, 0x8a, 0xcb, - 0xd1, 0x28, 0xed, 0x98, 0xcb, 0x61, 0x6d, 0x98, 0xb3, 0x45, 0xbf, 0x9e, 0x83, 0x8a, 0x38, 0x7b, - 0x76, 0xdd, 0x35, 0x9b, 0xd5, 0xf3, 0xd9, 0xac, 0x10, 0xe3, 0x62, 0x84, 0x1c, 0xb8, 0x30, 0x32, - 0xbb, 0xa0, 0x40, 0xb0, 0x2a, 0x08, 0xfa, 0xdd, 0x1c, 0x4c, 0xea, 0x91, 0x53, 0x86, 0xd5, 0x27, - 0x99, 0x6c, 0xdb, 0x59, 0x4f, 0x09, 0xd1, 0xa3, 0x8c, 0x4c, 0x3c, 0x99, 0x4d, 0x8d, 0x02, 0x71, - 0x4c, 0x22, 0xa6, 0xbe, 0x9e, 0xef, 0x9a, 0x1d, 0x52, 0xbd, 0x30, 0x14, 0xf5, 0xd5, 0x18, 0xf1, - 0x98, 0xfa, 0xf2, 0x46, 0x2c, 0x38, 0xb3, 0xa9, 0x9b, 0xf0, 0x25, 0x79, 0xf5, 0xa9, 0xa1, 0x4c, - 0xdd, 0xc1, 0x82, 0x3f, 0x3a, 0x75, 0x8b, 0x56, 0x1c, 0x30, 0xa7, 0xba, 0xec, 0x92, 0xa6, 0xe9, - 0x55, 0xab, 0x43, 0xd1, 0x65, 0x4c, 0x69, 0xc7, 0x74, 0x99, 0xb5, 0x61, 0xce, 0x96, 0xba, 0x73, - 0xdb, 0xdb, 0xaf, 0x3e, 0x3d, 0x14, 0x77, 0xbe, 0xe1, 0xed, 0xc7, 0xdc, 0xf9, 0x86, 0xb6, 0x89, - 0x29, 0x43, 0xe1, 0xce, 0x2d, 0x4f, 0x77, 0xab, 0xb3, 0x43, 0x72, 0xe7, 0x94, 0x78, 0xc2, 0x9d, - 0xd3, 0x46, 0x2c, 0x38, 0x33, 0x2d, 0x60, 0xd7, 0xcb, 0x4c, 0xa3, 0xfa, 0xa9, 0xa1, 0x68, 0xc1, - 0x75, 0x4e, 0x3d, 0xa6, 0x05, 0xa2, 0x15, 0x07, 0xcc, 0xd1, 0x73, 0x34, 0xaa, 0xed, 0x58, 0xa6, - 0xa1, 0x7b, 0xd5, 0x67, 0xd8, 0xc9, 0xc3, 0x71, 0x1e, 0x73, 0xf2, 0x36, 0x2c, 0xa1, 0xe8, 0x87, - 0x39, 0x98, 0x8a, 0xed, 0xb1, 0x55, 0x2f, 0x32, 0xd1, 0x8d, 0x8c, 0x45, 0xaf, 0x47, 0xb9, 0xf0, - 0x47, 0x90, 0x87, 0x35, 0xe2, 0x3b, 0x34, 0x71, 0xa1, 0xd0, 0xb7, 0x73, 0x50, 0x96, 0x6d, 0xd5, - 0x4b, 0x4c, 0xc4, 0x77, 0x86, 0x25, 0x22, 0x17, 0x4e, 0x1e, 0x3d, 0x0c, 0x4f, 0x19, 0x84, 0x22, - 0x30, 0xaf, 0xcd, 0x74, 0x5e, 0xf3, 0x5d, 0xa2, 0xb7, 0xab, 0x73, 0x43, 0xf1, 0xda, 0x38, 0xe4, - 0x10, 0xf3, 0xda, 0x0a, 0x04, 0xab, 0x82, 0xb0, 0x57, 0xaa, 0x47, 0x4f, 0xfe, 0x55, 0x2f, 0x0f, - 0xe5, 0x95, 0xc6, 0xcf, 0x17, 0x46, 0x5f, 0x69, 0x0c, 0x8a, 0xe3, 0x42, 0xa1, 0x3f, 0xc9, 0xc1, - 0x8c, 0x1e, 0x3f, 0x26, 0x5c, 0xfd, 0x4f, 0x4c, 0x54, 0x32, 0x0c, 0x51, 0x23, 0xc7, 0x91, 0x99, - 0xb0, 0x4f, 0x0b, 0x61, 0x67, 0x12, 0x70, 0x9c, 0x14, 0x8d, 0x06, 0x29, 0xde, 0x8e, 0xdf, 0xa9, - 0xce, 0x0f, 0x25, 0x48, 0xd1, 0x76, 0xfc, 0xf8, 0xba, 0x48, 0x5b, 0xd9, 0x6a, 0x60, 0xc6, 0x93, - 0x47, 0x69, 0xc4, 0x75, 0x4d, 0xbf, 0xfa, 0xec, 0x70, 0xa2, 0x34, 0x46, 0x3c, 0x1e, 0xa5, 0xb1, - 0x46, 0x2c, 0x38, 0xcf, 0x76, 0x01, 0xc2, 0xdc, 0x42, 0x4a, 0xfe, 0x76, 0x53, 0xcd, 0xdf, 0x56, - 0xae, 0xbe, 0xda, 0x77, 0x06, 0x5d, 0xfb, 0x6f, 0x35, 0xd7, 0x37, 0x77, 0x74, 0xc3, 0x57, 0x92, - 0xbf, 0xb3, 0xdf, 0xc9, 0xc1, 0x44, 0x24, 0x9f, 0x90, 0xc2, 0x7a, 0x37, 0xca, 0x1a, 0x67, 0xbf, - 0xe5, 0xa8, 0x4a, 0xf4, 0x7f, 0x72, 0x50, 0x96, 0x99, 0x85, 0x14, 0x69, 0x9a, 0x51, 0x69, 0x06, - 0xcd, 0x94, 0x32, 0x56, 0xe9, 0x92, 0xd0, 0xb1, 0x89, 0xa4, 0x18, 0x86, 0x3f, 0x36, 0x92, 0x5d, - 0xba, 0x44, 0x1f, 0xe5, 0x60, 0x5c, 0x4d, 0x34, 0xa4, 0x08, 0xd4, 0x8a, 0x0a, 0xb4, 0x99, 0xcd, - 0xe1, 0xa8, 0x23, 0xde, 0x95, 0xcc, 0x39, 0x0c, 0xff, 0x5d, 0xc5, 0x6e, 0xc8, 0xaa, 0x92, 0x7c, - 0x2b, 0x07, 0x10, 0x26, 0x20, 0x52, 0x44, 0x21, 0x51, 0x51, 0x06, 0xdd, 0xa3, 0xe6, 0xbc, 0x7a, - 0x8f, 0x8a, 0xcc, 0x46, 0x0c, 0x7f, 0x54, 0xd6, 0x37, 0xb7, 0xb6, 0x7a, 0x48, 0xf2, 0x7f, 0x73, - 0x50, 0x96, 0xb9, 0x89, 0xe1, 0x0f, 0xca, 0x46, 0x6d, 0x4b, 0xe3, 0xab, 0x87, 0xa4, 0x28, 0xdf, - 0xcc, 0x41, 0x29, 0xc8, 0x55, 0xa4, 0x48, 0x62, 0x44, 0x25, 0x19, 0xf4, 0x4c, 0x9f, 0xb6, 0xa1, - 0xf5, 0x18, 0x12, 0x26, 0xc7, 0xfe, 0xa9, 0xc9, 0xb1, 0xd9, 0x4b, 0x8e, 0x0f, 0x72, 0x50, 0x51, - 0xf2, 0x18, 0x29, 0xa2, 0xec, 0x44, 0x45, 0x19, 0x74, 0x7b, 0x46, 0x30, 0xeb, 0x2d, 0x8d, 0x92, - 0xd0, 0x18, 0xbe, 0x34, 0x82, 0xd9, 0x91, 0xd2, 0x04, 0x99, 0x8d, 0x53, 0x91, 0x86, 0x32, 0xeb, - 0x6d, 0xce, 0x32, 0xcb, 0x31, 0x7c, 0x73, 0xbe, 0xb1, 0xbc, 0xa2, 0x1d, 0xe1, 0xe4, 0xc2, 0x94, - 0xc7, 0xf0, 0xed, 0x99, 0xf3, 0x4a, 0x97, 0xe5, 0x7b, 0x39, 0x98, 0x8e, 0xe7, 0x3d, 0x52, 0x24, - 0xda, 0x8b, 0x4a, 0x34, 0xe8, 0xc5, 0x7f, 0x95, 0x63, 0xba, 0x5c, 0xbf, 0x9d, 0x83, 0x73, 0x29, - 0x39, 0x8f, 0x14, 0xd1, 0xec, 0xa8, 0x68, 0x77, 0x86, 0x75, 0x67, 0x34, 0xae, 0xd9, 0x4a, 0xd2, - 0x63, 0xf8, 0x9a, 0x2d, 0x98, 0xf5, 0x0e, 0x27, 0xd4, 0xe4, 0xc7, 0xf0, 0xc3, 0x89, 0xe4, 0xd9, - 0x8a, 0xb8, 0x7e, 0x87, 0x69, 0x90, 0xe1, 0xeb, 0x37, 0xe7, 0xd5, 0x7b, 0x9e, 0x08, 0x92, 0x22, - 0xc3, 0x9f, 0x27, 0x36, 0xb4, 0xcd, 0x23, 0xe7, 0x09, 0x99, 0x20, 0x39, 0x8d, 0x79, 0x82, 0x31, - 0xeb, 0xad, 0x31, 0x6a, 0xa2, 0x64, 0xf8, 0x1a, 0x13, 0x70, 0x4b, 0x97, 0xe7, 0xfb, 0x39, 0xe5, - 0x76, 0x92, 0x92, 0xfd, 0x48, 0x91, 0xcb, 0x89, 0xca, 0xf5, 0xd6, 0xd0, 0xce, 0x21, 0xab, 0xf2, - 0x7d, 0x9c, 0x83, 0xc9, 0x68, 0xea, 0x23, 0x45, 0x32, 0x33, 0x2a, 0x99, 0x36, 0x84, 0x9b, 0x4f, - 0x71, 0xcf, 0x1d, 0xcf, 0x7d, 0x0c, 0xdf, 0x73, 0xab, 0x1c, 0x7b, 0xbf, 0xcb, 0xb4, 0xb4, 0xc7, - 0xf0, 0xdf, 0x65, 0xef, 0xcb, 0x9c, 0xaa, 0x7c, 0x3f, 0xc8, 0xc1, 0x85, 0xf4, 0x5c, 0x47, 0x8a, - 0x84, 0xfb, 0x51, 0x09, 0xdf, 0x1e, 0xe2, 0x95, 0xef, 0x78, 0xac, 0x22, 0x93, 0x1d, 0xc3, 0x8f, - 0x55, 0xb4, 0x95, 0xad, 0xc6, 0x51, 0x31, 0x5c, 0x98, 0xf7, 0x38, 0x85, 0x18, 0x8e, 0x33, 0x4b, - 0x95, 0x66, 0xde, 0x8f, 0x9c, 0x38, 0xe2, 0xc7, 0x91, 0xd0, 0x7b, 0xf2, 0x00, 0x14, 0x3f, 0x27, - 0xf4, 0xd9, 0xfe, 0x73, 0x2a, 0x47, 0x9f, 0x73, 0xfa, 0xf3, 0x02, 0x4c, 0xc5, 0xf2, 0x0b, 0xac, - 0xf4, 0x08, 0xfd, 0xc9, 0xea, 0x74, 0xe5, 0xa2, 0xf7, 0xb0, 0xaf, 0x05, 0x00, 0x1c, 0xe2, 0xa0, - 0x8f, 0x73, 0x30, 0x75, 0x4f, 0xf7, 0x8d, 0xdd, 0x86, 0xee, 0xef, 0xf2, 0xc3, 0x6a, 0x19, 0xbd, - 0xbd, 0x37, 0xa3, 0x54, 0xc3, 0xf4, 0x62, 0x0c, 0x80, 0xe3, 0xfc, 0xd1, 0xf3, 0x30, 0xd6, 0x71, - 0x2c, 0xcb, 0xb4, 0x5b, 0xa2, 0xe0, 0x8a, 0xcc, 0x97, 0x37, 0x78, 0x33, 0x0e, 0xe0, 0xd1, 0x42, - 0x59, 0x85, 0x4c, 0x8e, 0x81, 0xc4, 0x86, 0xf4, 0x44, 0xa7, 0x33, 0x47, 0x3f, 0x29, 0xa7, 0x33, - 0xff, 0xb6, 0x00, 0x28, 0x39, 0x07, 0x3e, 0xaa, 0x94, 0xdc, 0x15, 0x28, 0x1a, 0xa1, 0xaa, 0x28, - 0xe7, 0xa9, 0xc5, 0x1b, 0x15, 0x50, 0x7e, 0xd3, 0xc1, 0x23, 0x46, 0xd7, 0x25, 0xc9, 0xca, 0x41, - 0xbc, 0x1d, 0x4b, 0x8c, 0x3e, 0x0b, 0x63, 0x7c, 0x94, 0xbc, 0xad, 0xf0, 0x5e, 0xe6, 0xc1, 0x40, - 0x1f, 0x2f, 0xff, 0x36, 0x2b, 0x14, 0xb4, 0x2b, 0x6e, 0x63, 0x15, 0xfb, 0xbe, 0xd9, 0x5d, 0x93, - 0x9d, 0xb1, 0x42, 0xe8, 0x6c, 0xca, 0x68, 0x0c, 0xa6, 0x53, 0x3f, 0x2b, 0xc2, 0x4c, 0xc2, 0x5d, - 0x9e, 0xd1, 0xc5, 0xca, 0x17, 0xa0, 0x44, 0xff, 0x2a, 0x75, 0x2c, 0xe4, 0x3b, 0xbc, 0x21, 0xda, - 0xb1, 0xc4, 0x50, 0xee, 0x0f, 0xe6, 0x7b, 0xde, 0x1f, 0xbc, 0x13, 0xb9, 0x44, 0x9d, 0x65, 0xad, - 0xb3, 0x57, 0x61, 0x82, 0x67, 0xeb, 0x83, 0x9b, 0x76, 0xa3, 0xd1, 0x9b, 0x56, 0xd7, 0x55, 0x20, - 0x8e, 0xe2, 0xf6, 0xb8, 0x57, 0x57, 0x3c, 0xd1, 0xbd, 0xba, 0x0f, 0x93, 0x05, 0x2d, 0xde, 0xcd, - 0x7a, 0xfa, 0xec, 0xc3, 0xb2, 0xd4, 0x4b, 0xa9, 0xa5, 0x23, 0x2f, 0xa5, 0x2e, 0x42, 0xd9, 0xf3, - 0xac, 0x37, 0x88, 0x6b, 0xee, 0x1c, 0xb0, 0x0b, 0x91, 0x4a, 0xe1, 0x2d, 0x2d, 0x00, 0xe0, 0x10, - 0xe7, 0x93, 0x78, 0x9e, 0xfe, 0x6f, 0x72, 0x30, 0xc9, 0xd3, 0x5b, 0xb5, 0x4e, 0x67, 0xc9, 0x25, - 0x4d, 0x8f, 0xba, 0x9e, 0x8e, 0x6b, 0xde, 0xd5, 0x7d, 0x12, 0x5c, 0x85, 0xeb, 0xcf, 0xf5, 0x34, - 0x64, 0x67, 0xac, 0x10, 0x42, 0xcf, 0xc2, 0xa8, 0xde, 0xe9, 0xac, 0x2e, 0x33, 0x19, 0xf2, 0xe1, - 0xb1, 0x81, 0x1a, 0x6d, 0xc4, 0x1c, 0x86, 0x5e, 0x83, 0x49, 0xd3, 0xf6, 0x7c, 0xdd, 0xb2, 0xd8, - 0x99, 0xfb, 0xd5, 0x65, 0xe6, 0xe8, 0xf3, 0xe1, 0x21, 0x90, 0xd5, 0x08, 0x14, 0xc7, 0xb0, 0xe7, - 0xff, 0xb2, 0x02, 0x33, 0x89, 0x6c, 0x1d, 0x9a, 0x85, 0x11, 0x93, 0x5f, 0x52, 0xca, 0xd7, 0x41, - 0x50, 0x1a, 0x59, 0x5d, 0xc6, 0x23, 0x66, 0x53, 0x75, 0x24, 0x23, 0xa7, 0xe7, 0x48, 0x64, 0xad, - 0x82, 0xfc, 0x71, 0x6b, 0x15, 0x84, 0x77, 0x07, 0xc5, 0xdd, 0xbb, 0x94, 0x0b, 0xdd, 0xe1, 0x7d, - 0x43, 0xac, 0xe0, 0x1f, 0xab, 0x78, 0xc2, 0x2d, 0x28, 0xe9, 0x1d, 0x93, 0xdf, 0x2b, 0x2e, 0xf6, - 0x7d, 0xdf, 0xa7, 0xd6, 0x58, 0xe5, 0x97, 0x8a, 0x25, 0x91, 0xe4, 0x8d, 0xe2, 0xb1, 0x6c, 0x6f, - 0x14, 0xab, 0xc1, 0x40, 0xe9, 0x91, 0xc1, 0xc0, 0x15, 0x28, 0xea, 0x86, 0x6f, 0xde, 0x25, 0xc2, - 0x8e, 0x65, 0x88, 0x51, 0x63, 0xad, 0x58, 0x40, 0x45, 0xb9, 0x5f, 0x3f, 0x08, 0x79, 0x21, 0x51, - 0xee, 0x37, 0x00, 0x61, 0x15, 0x8f, 0xf9, 0x5a, 0xa6, 0x34, 0x81, 0xaf, 0xad, 0xc4, 0x7c, 0xad, - 0x0a, 0xc4, 0x51, 0x5c, 0x54, 0x83, 0x29, 0xde, 0x70, 0xbb, 0x63, 0x39, 0x7a, 0x93, 0x76, 0x1f, - 0x8f, 0x6a, 0xc5, 0xf5, 0x28, 0x18, 0xc7, 0xf1, 0x7b, 0xb8, 0xeb, 0x89, 0xc1, 0xdd, 0xf5, 0x64, - 0x36, 0xee, 0x3a, 0x6e, 0x91, 0x7d, 0xb8, 0xeb, 0xf7, 0xe3, 0x95, 0x01, 0xf8, 0x29, 0xcd, 0x41, - 0x5d, 0x2b, 0x35, 0xaf, 0xa6, 0x7a, 0xf7, 0xff, 0x58, 0x15, 0x01, 0x3e, 0x0b, 0x13, 0x8e, 0xdb, - 0xd2, 0x6d, 0xf3, 0x01, 0x73, 0x38, 0x1e, 0x3b, 0xad, 0x59, 0xe6, 0xda, 0x7a, 0x4b, 0x05, 0xe0, - 0x28, 0x1e, 0x7a, 0x00, 0xe5, 0x56, 0xe0, 0x65, 0xab, 0x33, 0x99, 0xf8, 0x99, 0xa8, 0xd7, 0xe6, - 0xd7, 0x83, 0x64, 0x1b, 0x0e, 0xd9, 0x29, 0xb3, 0x12, 0xfa, 0xa4, 0xcc, 0x4a, 0xef, 0x97, 0x98, - 0x1b, 0x8f, 0x6e, 0x73, 0x9c, 0x51, 0xcc, 0xf7, 0x39, 0x28, 0x8b, 0x88, 0x40, 0xcc, 0x5d, 0xe5, - 0xfa, 0xa7, 0x84, 0xaa, 0x9c, 0x4b, 0xd4, 0xd2, 0x58, 0x5d, 0xc6, 0x21, 0xf6, 0x31, 0x03, 0xc0, - 0x48, 0x4d, 0x87, 0x42, 0x76, 0x35, 0x1d, 0x34, 0x78, 0x92, 0xdf, 0xbf, 0xd5, 0xb4, 0x35, 0x16, - 0xa0, 0x98, 0x06, 0xbf, 0x7e, 0xcb, 0xab, 0xff, 0x5d, 0x14, 0x0f, 0xf1, 0xe4, 0xb5, 0x34, 0x24, - 0x9c, 0xde, 0x57, 0x78, 0x3a, 0x4b, 0x97, 0x9e, 0xae, 0x98, 0xf0, 0x74, 0x21, 0x10, 0x47, 0x71, - 0x7b, 0xb8, 0xa9, 0xd2, 0xe0, 0x6e, 0xaa, 0x9c, 0x95, 0x9b, 0x8a, 0x6a, 0xdc, 0x09, 0xa3, 0x4a, - 0x38, 0x32, 0xaa, 0xbc, 0x03, 0x15, 0x8f, 0xbd, 0x49, 0xfe, 0xc2, 0x2b, 0x7d, 0xbf, 0x70, 0x2d, - 0xec, 0x8d, 0x55, 0x52, 0x8a, 0xa1, 0x8f, 0x9f, 0x62, 0xa1, 0x88, 0x79, 0x28, 0xb6, 0x5c, 0xa7, - 0xdb, 0xe1, 0x77, 0x06, 0x84, 0x92, 0x5f, 0x67, 0x2d, 0x58, 0x40, 0x06, 0x73, 0x06, 0xdf, 0x2f, - 0xc3, 0x54, 0x6c, 0x9f, 0x31, 0x35, 0xcf, 0x94, 0x3b, 0xe3, 0x3c, 0xd3, 0x65, 0x28, 0xf8, 0x34, - 0x68, 0x18, 0x89, 0xde, 0x4a, 0x67, 0xd1, 0x02, 0x83, 0x24, 0x8b, 0x5f, 0xe4, 0x8f, 0x5f, 0xfc, - 0x02, 0xfd, 0x17, 0x28, 0xeb, 0xcd, 0xa6, 0x4b, 0x3c, 0x8f, 0x04, 0xd5, 0x74, 0x98, 0xcf, 0xaf, - 0x05, 0x8d, 0x38, 0x84, 0xb3, 0x85, 0x6a, 0x73, 0xc7, 0xbb, 0xed, 0x89, 0xec, 0x91, 0xba, 0x50, - 0x5d, 0x5e, 0xd1, 0x68, 0x3b, 0x96, 0x18, 0xa8, 0x09, 0x53, 0x7b, 0xee, 0xf6, 0xd2, 0x92, 0x6e, - 0xec, 0x92, 0x93, 0x64, 0x1c, 0x58, 0x95, 0xdc, 0x9b, 0x51, 0x0a, 0x38, 0x4e, 0x52, 0x70, 0xb9, - 0x49, 0x0e, 0x7c, 0x7d, 0xfb, 0x24, 0x31, 0x61, 0xc0, 0x45, 0xa5, 0x80, 0xe3, 0x24, 0x69, 0x04, - 0xb7, 0xe7, 0x6e, 0x07, 0x37, 0xda, 0x45, 0x55, 0x2e, 0x19, 0xc1, 0xdd, 0x0c, 0x41, 0x58, 0xc5, - 0xa3, 0x03, 0xb6, 0xe7, 0x6e, 0x63, 0xa2, 0x5b, 0x6d, 0x51, 0x58, 0x50, 0x0e, 0xd8, 0x4d, 0xd1, - 0x8e, 0x25, 0x06, 0xea, 0x00, 0xa2, 0x4f, 0xc7, 0xde, 0xbb, 0xbc, 0x92, 0x2b, 0x16, 0x7d, 0xcf, - 0xa5, 0x3d, 0x8d, 0x44, 0x52, 0x1f, 0xe8, 0x02, 0x75, 0x77, 0x37, 0x13, 0x74, 0x70, 0x0a, 0x6d, - 0xf4, 0x16, 0x3c, 0xb5, 0xe7, 0x6e, 0x8b, 0xb4, 0x7f, 0xc3, 0x35, 0x6d, 0xc3, 0xec, 0xe8, 0xbc, - 0x46, 0x40, 0x25, 0x5a, 0x07, 0xf1, 0x66, 0x3a, 0x1a, 0xee, 0xd5, 0x3f, 0x9a, 0xf4, 0x1c, 0xcf, - 0x24, 0xe9, 0x19, 0x33, 0xd7, 0xc7, 0xbd, 0xd8, 0xcd, 0x60, 0xfe, 0xe9, 0x47, 0x39, 0x40, 0xec, - 0x84, 0x55, 0xf0, 0x35, 0x10, 0xe6, 0xfc, 0xd0, 0x22, 0x94, 0x99, 0xf7, 0x53, 0x2e, 0xbd, 0xca, - 0xec, 0xc1, 0xf5, 0x00, 0x80, 0x43, 0x1c, 0xba, 0x46, 0x71, 0xac, 0x26, 0x91, 0x95, 0x2a, 0xe4, - 0x1a, 0xe5, 0x16, 0x6b, 0xc5, 0x02, 0x8a, 0xae, 0xc3, 0x8c, 0x4b, 0xb6, 0x75, 0x4b, 0xb7, 0x0d, - 0xa2, 0xf9, 0xae, 0xee, 0x93, 0xd6, 0x81, 0xf0, 0x24, 0xf2, 0x18, 0x2b, 0x8e, 0x23, 0xe0, 0x64, - 0x9f, 0xf9, 0xbf, 0x2f, 0xc1, 0x74, 0xfc, 0x68, 0xd8, 0xa3, 0x72, 0xb5, 0x8b, 0x50, 0xee, 0xe8, - 0xae, 0x6f, 0x2a, 0x75, 0x3c, 0xe4, 0x53, 0x35, 0x02, 0x00, 0x0e, 0x71, 0xe8, 0xb2, 0x9f, 0x95, - 0x69, 0x15, 0x12, 0xca, 0x65, 0x3f, 0x2b, 0xe3, 0x8a, 0x39, 0x2c, 0xbd, 0x38, 0x44, 0xe1, 0xd4, - 0x8a, 0x43, 0x3c, 0x16, 0x75, 0x5f, 0x3f, 0x48, 0xa6, 0xc9, 0xde, 0xc9, 0xf8, 0xdc, 0x5f, 0x7f, - 0xcb, 0xae, 0x09, 0x43, 0xd5, 0x67, 0x51, 0x0c, 0x63, 0x33, 0x0b, 0x91, 0x22, 0x86, 0xc2, 0x57, - 0x4f, 0x91, 0x26, 0x1c, 0x65, 0x8d, 0x1a, 0x70, 0xde, 0x32, 0xdb, 0x22, 0xe1, 0xe7, 0x35, 0x88, - 0xcb, 0xab, 0x23, 0x33, 0x47, 0x9d, 0x0f, 0x13, 0x21, 0x6b, 0x29, 0x38, 0x38, 0xb5, 0x27, 0x7a, - 0x1e, 0xc6, 0xee, 0x12, 0x97, 0x5d, 0xde, 0x87, 0x68, 0xc5, 0xf6, 0x37, 0x78, 0x33, 0x0e, 0xe0, - 0xe8, 0x2d, 0x28, 0x78, 0xba, 0x67, 0x89, 0x40, 0xed, 0x04, 0x47, 0x99, 0x6b, 0xda, 0x9a, 0x50, - 0x0f, 0x96, 0xa2, 0xa5, 0xbf, 0x31, 0x23, 0x79, 0x46, 0x01, 0x5b, 0xb8, 0xdd, 0x32, 0x71, 0xd4, - 0x76, 0xcb, 0x60, 0x4e, 0xf1, 0x07, 0x45, 0x98, 0x8a, 0x9d, 0xf5, 0x7c, 0x94, 0x6b, 0x91, 0x9e, - 0x62, 0xe4, 0x08, 0x4f, 0xf1, 0x02, 0x94, 0x0c, 0xcb, 0x24, 0xb6, 0xbf, 0xda, 0x14, 0x1e, 0x25, - 0xbc, 0x52, 0xce, 0xdb, 0x97, 0xb1, 0xc4, 0x38, 0x6b, 0xbf, 0xa2, 0x3a, 0x80, 0xd1, 0xe3, 0x16, - 0x9d, 0x29, 0x0e, 0xf3, 0xe3, 0x3f, 0xd9, 0x5c, 0x6d, 0x8f, 0xbd, 0xd8, 0xc7, 0xbe, 0x88, 0x74, - 0xb0, 0xc9, 0x52, 0xce, 0x7a, 0x93, 0x65, 0x30, 0x1b, 0xf9, 0xeb, 0x11, 0x28, 0x6d, 0xd4, 0xb6, - 0x34, 0x56, 0x5c, 0xf9, 0xed, 0x68, 0xf9, 0xe8, 0x41, 0x84, 0x4c, 0xd6, 0x89, 0x5e, 0xa1, 0xa6, - 0xd5, 0x77, 0x89, 0xe8, 0x32, 0xb7, 0x3e, 0xba, 0xce, 0xe4, 0xdd, 0xd1, 0x12, 0x14, 0xec, 0xbd, - 0x7e, 0xbf, 0xa1, 0xc1, 0xc6, 0x6c, 0xe3, 0x26, 0x39, 0xc0, 0xac, 0x33, 0xba, 0x0d, 0x60, 0xb8, - 0xa4, 0x49, 0x6c, 0xdf, 0x14, 0x9f, 0x30, 0xeb, 0x6f, 0x7f, 0x61, 0x49, 0x76, 0xc6, 0x0a, 0xa1, - 0xf9, 0x3f, 0x2c, 0xc2, 0x74, 0xfc, 0x4c, 0xf7, 0xa3, 0x5c, 0xce, 0xf3, 0x30, 0xe6, 0x75, 0x59, - 0x81, 0x1b, 0xe1, 0x74, 0xe4, 0x34, 0xa0, 0xf1, 0x66, 0x1c, 0xc0, 0xd3, 0x5d, 0x49, 0xfe, 0x4c, - 0x5c, 0x49, 0xe1, 0xb8, 0xae, 0x24, 0xeb, 0x80, 0xe6, 0x83, 0xe4, 0xe7, 0x21, 0xde, 0xc9, 0xf8, - 0x14, 0x7e, 0x1f, 0xbe, 0x84, 0x08, 0xab, 0x1e, 0xcb, 0xa4, 0x34, 0x4c, 0x60, 0x88, 0x89, 0x7d, - 0xd4, 0xb3, 0x71, 0x59, 0x73, 0x30, 0xca, 0x3e, 0x87, 0x20, 0x16, 0xa3, 0xcc, 0x14, 0xd9, 0x91, - 0x2a, 0xcc, 0xdb, 0x07, 0xac, 0x5e, 0x3f, 0x0a, 0x93, 0xd1, 0x53, 0x9c, 0x74, 0xdd, 0xbc, 0xeb, - 0x78, 0xbe, 0xc8, 0x26, 0xc4, 0x3f, 0x74, 0x78, 0x23, 0x04, 0x61, 0x15, 0xef, 0x78, 0x93, 0xf6, - 0xf3, 0x30, 0x26, 0x8a, 0xd5, 0x89, 0x39, 0x5b, 0x9a, 0x99, 0x28, 0x68, 0x87, 0x03, 0xf8, 0x7f, - 0xcc, 0xd8, 0x96, 0x87, 0xbe, 0x95, 0x9c, 0xb1, 0xdf, 0xce, 0xf4, 0xc8, 0xee, 0xe3, 0x3e, 0x61, - 0x0f, 0xa6, 0xdc, 0x6f, 0xc1, 0x4c, 0x62, 0x77, 0xe7, 0x78, 0xc5, 0xc0, 0xe7, 0x60, 0xd4, 0xd6, - 0xdb, 0x84, 0xd7, 0xcb, 0x12, 0x46, 0xc7, 0xbe, 0x17, 0x81, 0x79, 0xfb, 0xfc, 0x0f, 0x8b, 0x30, - 0x93, 0xb8, 0x9a, 0xc2, 0xd6, 0xc4, 0x72, 0x87, 0x20, 0xb6, 0xd2, 0x4f, 0xdd, 0x17, 0x78, 0x0d, - 0x26, 0x99, 0x61, 0x34, 0x62, 0xfb, 0x0a, 0x72, 0x97, 0x7b, 0x2b, 0x02, 0xc5, 0x31, 0xec, 0xe3, - 0xad, 0xa9, 0x5f, 0x83, 0x49, 0xf5, 0x03, 0x27, 0xab, 0xcb, 0x62, 0xdf, 0x58, 0x32, 0xd1, 0x22, - 0x50, 0x1c, 0xc3, 0x66, 0x5f, 0x87, 0x91, 0xb3, 0xab, 0xc8, 0xd7, 0x8d, 0xf6, 0xff, 0x75, 0x98, - 0x18, 0x09, 0x9c, 0x20, 0x8a, 0xb6, 0x61, 0x96, 0xe7, 0xf7, 0x55, 0x81, 0x62, 0x67, 0x4e, 0xe6, - 0x85, 0xd0, 0xb3, 0xcb, 0x3d, 0x31, 0xf1, 0x11, 0x54, 0xfa, 0x2c, 0xff, 0xf8, 0x61, 0xf2, 0x7b, - 0x99, 0xef, 0x66, 0x7d, 0xa1, 0xe9, 0x44, 0x36, 0x58, 0xfe, 0xa4, 0xd8, 0xe0, 0x0f, 0x2b, 0xd4, - 0x50, 0x62, 0x67, 0xf3, 0xd1, 0x3c, 0x14, 0x99, 0x6e, 0xd2, 0xe9, 0x45, 0x6e, 0x15, 0x30, 0xa5, - 0xf5, 0xb0, 0x80, 0x1c, 0x23, 0x8b, 0x2e, 0x62, 0xba, 0x7c, 0x8f, 0x98, 0xae, 0x03, 0xe7, 0x7c, - 0xcb, 0xdb, 0x72, 0xbb, 0x9e, 0xbf, 0x44, 0x5c, 0xdf, 0x13, 0xaa, 0x5b, 0xe8, 0xfb, 0x23, 0x73, - 0x5b, 0x6b, 0x5a, 0x9c, 0x0a, 0x4e, 0x23, 0x4d, 0x15, 0xd8, 0xb7, 0xbc, 0x9a, 0x65, 0x39, 0xf7, - 0x82, 0xa3, 0x07, 0xe1, 0x64, 0x23, 0xa6, 0x11, 0xa9, 0xc0, 0x5b, 0x6b, 0x5a, 0x0f, 0x4c, 0x7c, - 0x04, 0x15, 0xb4, 0xce, 0x9e, 0xea, 0x0d, 0xdd, 0x32, 0x9b, 0xba, 0x4f, 0xe8, 0x74, 0xcc, 0xd2, - 0xdb, 0xdc, 0x3a, 0xe4, 0x7e, 0xe4, 0xd6, 0x9a, 0x16, 0x47, 0xc1, 0x69, 0xfd, 0x86, 0xf5, 0xa1, - 0xd9, 0xd4, 0xd9, 0xbb, 0x74, 0x26, 0xb3, 0x77, 0xb9, 0x3f, 0x2b, 0x87, 0x8c, 0xac, 0x3c, 0xa6, - 0xf2, 0x7d, 0x58, 0x79, 0x13, 0xa6, 0xe4, 0x17, 0x78, 0x84, 0xce, 0x56, 0xfa, 0xde, 0x1e, 0xa9, - 0x45, 0x29, 0xe0, 0x38, 0xc9, 0x33, 0x4a, 0x39, 0xfd, 0x71, 0x0e, 0xa6, 0xa9, 0x24, 0x35, 0x7f, - 0x97, 0xd8, 0x0f, 0x1a, 0xba, 0xab, 0xb7, 0x83, 0x12, 0x63, 0x3b, 0x99, 0x0f, 0x79, 0x2d, 0xc6, - 0x88, 0x0f, 0xbd, 0xac, 0xfb, 0x1c, 0x07, 0xe3, 0x84, 0x64, 0x74, 0xea, 0x0b, 0xdb, 0x4e, 0xf2, - 0xb5, 0xd8, 0xf3, 0x51, 0x46, 0xc1, 0xd4, 0x17, 0x27, 0x3a, 0x90, 0x8f, 0x9d, 0x5d, 0x82, 0x27, - 0x53, 0x1f, 0xb5, 0x2f, 0x47, 0xfd, 0xcd, 0xa2, 0xb8, 0x5f, 0x93, 0xc1, 0x5a, 0x20, 0xeb, 0xcf, - 0x39, 0xd1, 0xc0, 0xca, 0x96, 0x9f, 0xfb, 0x8a, 0x7d, 0x06, 0x2e, 0xfc, 0xc0, 0x57, 0x88, 0x83, - 0x66, 0x61, 0xa4, 0xb9, 0xcd, 0x5c, 0xfd, 0x68, 0x78, 0xd0, 0x6f, 0xb9, 0x8e, 0x47, 0x9a, 0xdb, - 0xe8, 0x39, 0x28, 0x89, 0x45, 0x46, 0x70, 0x0e, 0x8e, 0xb1, 0x15, 0x2b, 0x10, 0x0f, 0x4b, 0xe8, - 0xb0, 0xc2, 0xfa, 0x21, 0x24, 0xf8, 0xe3, 0x6f, 0xee, 0xb1, 0xcf, 0xc4, 0xf5, 0xe7, 0xa1, 0x5f, - 0x50, 0xaa, 0x9a, 0x43, 0x34, 0xd9, 0x9b, 0x2c, 0x59, 0x3e, 0x58, 0xc0, 0xf2, 0x67, 0x45, 0xb8, - 0x90, 0x7e, 0xeb, 0xeb, 0xb1, 0xb1, 0x06, 0xae, 0xdc, 0xf9, 0x54, 0xe5, 0xfe, 0x34, 0x8c, 0x79, - 0x4c, 0xf0, 0xe0, 0x68, 0x00, 0xaf, 0x37, 0xcb, 0x9b, 0x70, 0x00, 0x43, 0xaf, 0x03, 0x6a, 0xeb, - 0xf7, 0xd7, 0xbd, 0xd6, 0x92, 0xd3, 0x65, 0x25, 0xb4, 0x31, 0xd1, 0x79, 0x7d, 0xf7, 0xd1, 0xf0, - 0x00, 0xce, 0x7a, 0x02, 0x03, 0xa7, 0xf4, 0x62, 0x87, 0x19, 0x22, 0x1b, 0x44, 0xb1, 0x93, 0x40, - 0x47, 0xee, 0xe8, 0x0c, 0x29, 0xfe, 0xf8, 0x38, 0x19, 0xb8, 0x1b, 0x43, 0xb9, 0x0a, 0xf8, 0xb8, - 0x47, 0xef, 0xa7, 0x69, 0x3a, 0x3f, 0x2b, 0xc0, 0xb9, 0x94, 0x52, 0x30, 0x51, 0xef, 0x9d, 0x3b, - 0x86, 0xf7, 0xde, 0x97, 0x23, 0x95, 0xcd, 0x49, 0xec, 0x40, 0xa8, 0x23, 0x86, 0xe9, 0xc3, 0x1c, - 0x9c, 0x67, 0x3b, 0xf0, 0xc1, 0xb6, 0x5f, 0x50, 0x03, 0x38, 0x2f, 0x34, 0xf3, 0x58, 0xc5, 0xb8, - 0xaf, 0xa7, 0x50, 0x08, 0xb7, 0x25, 0xd3, 0xa0, 0x38, 0x95, 0x2b, 0x5a, 0x02, 0x90, 0x77, 0xe9, - 0x02, 0x4b, 0x7e, 0x96, 0x95, 0x14, 0x97, 0xad, 0xff, 0xc6, 0x76, 0xf7, 0x95, 0xd1, 0x66, 0x2b, - 0x23, 0xa5, 0xdb, 0x30, 0x3e, 0xbc, 0x92, 0xf2, 0x7a, 0x8f, 0x6f, 0x01, 0x83, 0x69, 0xd7, 0x1f, - 0xe5, 0x61, 0x32, 0xfa, 0x22, 0xd1, 0x15, 0x28, 0x76, 0x5c, 0xb2, 0x63, 0xde, 0x8f, 0x7f, 0x7f, - 0xa3, 0xc1, 0x5a, 0xb1, 0x80, 0x22, 0x07, 0x8a, 0x96, 0xbe, 0x4d, 0xe7, 0x7b, 0x5e, 0xff, 0xfc, - 0xfa, 0xc0, 0xb5, 0xbc, 0x83, 0x6d, 0x88, 0x80, 0xe1, 0x1a, 0x23, 0x8f, 0x05, 0x1b, 0xca, 0x70, - 0xc7, 0x24, 0x56, 0x93, 0x9f, 0xf7, 0x1c, 0x06, 0xc3, 0x15, 0x46, 0x1e, 0x0b, 0x36, 0xe8, 0x6d, - 0x28, 0xf3, 0x8f, 0x96, 0x34, 0xeb, 0x07, 0x62, 0x85, 0xfb, 0x9f, 0x8f, 0xa7, 0xb2, 0x5b, 0x66, - 0x9b, 0x84, 0xe6, 0xb8, 0x14, 0x10, 0xc1, 0x21, 0x3d, 0xf6, 0xad, 0xfa, 0x1d, 0x9f, 0xb8, 0x9a, - 0xaf, 0xbb, 0xc1, 0xa7, 0xe4, 0xc3, 0x6f, 0xd5, 0x4b, 0x08, 0x56, 0xb0, 0xe6, 0xff, 0x74, 0x0c, - 0xa6, 0x62, 0xf7, 0x6c, 0x7f, 0x35, 0x2e, 0x91, 0xaa, 0x1f, 0x58, 0xc9, 0x67, 0xfd, 0x81, 0x95, - 0x42, 0x16, 0xe1, 0xc1, 0xdb, 0x30, 0xee, 0x79, 0xbb, 0x0c, 0xb3, 0xff, 0x5c, 0xdd, 0xf4, 0xe1, - 0xc3, 0xb9, 0x71, 0x4d, 0xbb, 0x21, 0xbb, 0xe3, 0x08, 0x31, 0xb4, 0x06, 0x63, 0xe2, 0x70, 0x61, - 0x7f, 0x27, 0x03, 0x59, 0x18, 0x12, 0x84, 0x47, 0x01, 0x89, 0x61, 0x6c, 0x49, 0xc7, 0x94, 0xee, - 0xb1, 0x0f, 0x84, 0x1b, 0x70, 0xbe, 0xe3, 0x58, 0x56, 0x70, 0xba, 0x53, 0x7e, 0x1a, 0xa9, 0x1c, - 0xbd, 0xdb, 0xd3, 0x48, 0xc1, 0xc1, 0xa9, 0x3d, 0x07, 0xf3, 0xb2, 0xff, 0x54, 0x84, 0xc9, 0x68, - 0x19, 0xaa, 0xb3, 0xbb, 0x61, 0xc9, 0x12, 0x81, 0x35, 0xd7, 0x8e, 0xdf, 0xb0, 0xdc, 0x12, 0xed, - 0x58, 0x62, 0x20, 0x0c, 0x65, 0x7e, 0xe2, 0xfd, 0x66, 0xbf, 0x9b, 0xd2, 0xfc, 0xe8, 0x6c, 0xd0, - 0x17, 0x87, 0x64, 0x28, 0x4d, 0x2f, 0x40, 0xef, 0xcf, 0x32, 0x19, 0x4d, 0xd9, 0x8c, 0x43, 0x32, - 0x74, 0xc6, 0x72, 0x49, 0x2b, 0xc8, 0x06, 0x2a, 0x33, 0x16, 0x66, 0xad, 0x58, 0x40, 0xd1, 0xf3, - 0x30, 0xe6, 0x3a, 0x16, 0xa9, 0xe1, 0x0d, 0x11, 0x4d, 0xcb, 0x8d, 0x32, 0xcc, 0x9b, 0x71, 0x00, - 0x1f, 0xc6, 0x26, 0x51, 0x54, 0x01, 0xfa, 0x30, 0xa1, 0xeb, 0x30, 0x73, 0x57, 0x64, 0x18, 0x35, - 0xb3, 0x65, 0xeb, 0x7e, 0x78, 0x29, 0x4b, 0x9e, 0x48, 0x7c, 0x23, 0x8e, 0x80, 0x93, 0x7d, 0xce, - 0x2e, 0x56, 0x26, 0x76, 0xb3, 0xe3, 0x98, 0xb6, 0x1f, 0x8f, 0x95, 0xaf, 0x89, 0x76, 0x2c, 0x31, - 0x06, 0xb3, 0xb3, 0xbf, 0x1a, 0x83, 0xc9, 0x68, 0x99, 0xb5, 0xa8, 0x0e, 0xe7, 0x86, 0xa0, 0xc3, - 0x23, 0x59, 0xeb, 0x70, 0xfe, 0x48, 0x1d, 0x7e, 0x36, 0xd8, 0xb9, 0x2e, 0x44, 0x37, 0xa7, 0xd4, - 0xdd, 0x6b, 0x54, 0xa3, 0x33, 0xbc, 0xe9, 0xd3, 0x28, 0x84, 0x9f, 0xc8, 0xe3, 0x87, 0x15, 0xf2, - 0xea, 0x8c, 0x1c, 0x01, 0xe3, 0x38, 0x7e, 0x3f, 0xb6, 0xd2, 0xdf, 0xee, 0xcf, 0x6b, 0x30, 0xc9, - 0x84, 0xac, 0x19, 0x06, 0x5d, 0xef, 0xae, 0x36, 0xc5, 0x21, 0x72, 0xb9, 0x71, 0xb6, 0xa9, 0x42, - 0x97, 0x71, 0x0c, 0x3b, 0x6a, 0x99, 0xe5, 0x6c, 0x2c, 0x73, 0xf3, 0x84, 0x96, 0x79, 0x11, 0xf2, - 0x4d, 0x6b, 0x9f, 0x69, 0x75, 0x29, 0xdc, 0x2b, 0x59, 0x5e, 0xdb, 0xc4, 0xb4, 0x5d, 0xb1, 0xb7, - 0xca, 0x19, 0xd9, 0xdb, 0xf8, 0xa3, 0xec, 0x8d, 0xc5, 0x35, 0xfc, 0x0b, 0x4a, 0xfc, 0xc2, 0xcc, - 0x44, 0xff, 0x71, 0x8d, 0xd2, 0x1d, 0x47, 0x88, 0x0d, 0x66, 0xcc, 0x5f, 0x83, 0x52, 0xc0, 0x88, - 0x0e, 0xb4, 0xec, 0x17, 0x0e, 0x34, 0x35, 0x21, 0x46, 0x64, 0x11, 0xca, 0x4e, 0x87, 0x44, 0x3e, - 0x7f, 0x28, 0x63, 0xe0, 0x5b, 0x01, 0x00, 0x87, 0x38, 0xd4, 0x8a, 0x38, 0xd7, 0xd8, 0x16, 0xef, - 0x1b, 0xb4, 0x51, 0x08, 0x31, 0xff, 0xf5, 0x1c, 0x04, 0xdf, 0x14, 0x42, 0xcb, 0x30, 0xda, 0x71, - 0x5c, 0x9f, 0x6f, 0xad, 0x55, 0xae, 0xce, 0xa5, 0x8f, 0x0f, 0x3f, 0xfe, 0xef, 0xb8, 0x7e, 0x48, - 0x91, 0xfe, 0xf2, 0x30, 0xef, 0x4c, 0xe5, 0x34, 0xac, 0xae, 0xe7, 0x13, 0x77, 0xb5, 0x11, 0x97, - 0x73, 0x29, 0x00, 0xe0, 0x10, 0x67, 0xfe, 0x5f, 0x0a, 0x30, 0x1d, 0xaf, 0xbc, 0x87, 0xde, 0x85, - 0x09, 0xcf, 0x6c, 0xd9, 0xa6, 0xdd, 0x12, 0xb1, 0x68, 0xae, 0xef, 0xbb, 0xbf, 0x9a, 0xda, 0x1f, - 0x47, 0xc9, 0x65, 0x76, 0x9c, 0xed, 0x6c, 0xbe, 0x9b, 0xff, 0x41, 0xb2, 0xc8, 0xcc, 0x3b, 0x19, - 0xd7, 0x3e, 0xfc, 0xd5, 0xae, 0x32, 0xf3, 0xcb, 0x51, 0xb8, 0x90, 0x5e, 0x5b, 0xf1, 0x8c, 0x82, - 0xd6, 0xf0, 0x9e, 0xe7, 0x48, 0xcf, 0x7b, 0x9e, 0xe1, 0x38, 0xe7, 0x33, 0xaa, 0x95, 0x28, 0x07, - 0xe0, 0x68, 0x57, 0x2b, 0xc3, 0xe9, 0xc2, 0x23, 0xc3, 0xe9, 0x2b, 0x50, 0x14, 0x75, 0xf5, 0x63, - 0x61, 0x6a, 0x9d, 0x57, 0xbd, 0x17, 0x50, 0x25, 0x14, 0x28, 0x1e, 0x19, 0x0a, 0xd0, 0xd0, 0x26, - 0xd8, 0x7f, 0xec, 0xef, 0xae, 0x17, 0x0f, 0x6d, 0x82, 0xbe, 0x38, 0x24, 0xc3, 0x6e, 0xf2, 0x77, - 0xcc, 0xdb, 0x78, 0x4d, 0xcc, 0xca, 0xe1, 0x4d, 0xfe, 0xc6, 0xea, 0x6d, 0xbc, 0x86, 0x05, 0x34, - 0x9a, 0x0a, 0x2e, 0x67, 0x92, 0x0a, 0x4e, 0xd7, 0xb9, 0xd3, 0x4a, 0x84, 0x19, 0x30, 0x93, 0x78, - 0xe7, 0xc7, 0x4e, 0x85, 0x5d, 0x81, 0xa2, 0xd7, 0xdd, 0xa1, 0x78, 0xb1, 0x12, 0x4b, 0x1a, 0x6b, - 0xc5, 0x02, 0x3a, 0xff, 0xdd, 0x02, 0xe5, 0x12, 0xab, 0xc2, 0x79, 0x46, 0x56, 0xf5, 0x2a, 0x4c, - 0xf0, 0x64, 0xd4, 0x9b, 0x4a, 0x7d, 0x8e, 0x92, 0xb2, 0xc1, 0xa0, 0x02, 0x71, 0x14, 0x17, 0xad, - 0x32, 0x35, 0xe9, 0x7b, 0x59, 0x08, 0x42, 0x93, 0xe8, 0xc4, 0x2d, 0x08, 0xa0, 0x97, 0xa0, 0xc2, - 0x1e, 0x82, 0x0f, 0xb9, 0xc8, 0xca, 0xb2, 0x9b, 0xb8, 0xd7, 0xc2, 0x66, 0xac, 0xe2, 0x44, 0x8f, - 0x16, 0x8c, 0x66, 0x72, 0xb4, 0x20, 0xf1, 0x56, 0x4e, 0x4b, 0xef, 0xbe, 0x5d, 0x02, 0xf9, 0xa5, - 0x44, 0x64, 0x24, 0xbe, 0x57, 0xf9, 0xb9, 0xbe, 0x37, 0x6f, 0x02, 0x51, 0x78, 0x26, 0x2b, 0x65, - 0x4a, 0x7a, 0x1d, 0x90, 0xf8, 0x40, 0xa2, 0x08, 0xaa, 0x95, 0x7a, 0x4b, 0x72, 0x97, 0x4a, 0x4b, - 0x60, 0xe0, 0x94, 0x5e, 0xe8, 0x75, 0xf6, 0x75, 0x56, 0x5f, 0x37, 0x6d, 0xe9, 0x79, 0x2f, 0xf6, - 0xb8, 0xa0, 0xc9, 0x91, 0xe4, 0x77, 0x56, 0xf9, 0x4f, 0x1c, 0x76, 0x47, 0xd7, 0x60, 0xec, 0xae, - 0x63, 0x75, 0xdb, 0x22, 0x35, 0x5f, 0xb9, 0x3a, 0x9b, 0x46, 0xe9, 0x0d, 0x86, 0xa2, 0x5c, 0x28, - 0xe2, 0x5d, 0x70, 0xd0, 0x17, 0x11, 0x98, 0x62, 0xc7, 0x7b, 0x4c, 0xff, 0x40, 0x18, 0x80, 0x98, - 0x7a, 0xaf, 0xa4, 0x91, 0x6b, 0x38, 0x4d, 0x2d, 0x8a, 0xcd, 0x4f, 0x7a, 0xc4, 0x1a, 0x71, 0x9c, - 0x26, 0x5a, 0x81, 0x92, 0xbe, 0xb3, 0x63, 0xda, 0xa6, 0x7f, 0x20, 0x72, 0x76, 0xcf, 0xa4, 0xd1, - 0xaf, 0x09, 0x1c, 0x51, 0xc8, 0x45, 0xfc, 0xc2, 0xb2, 0x2f, 0xba, 0x0d, 0x15, 0xdf, 0xb1, 0x44, - 0x5c, 0xea, 0x89, 0x54, 0xc3, 0xa5, 0x34, 0x52, 0x5b, 0x12, 0x2d, 0xdc, 0x1e, 0x0d, 0xdb, 0x3c, - 0xac, 0xd2, 0x41, 0xff, 0x3f, 0x07, 0xe3, 0xb6, 0xd3, 0x24, 0x81, 0xe9, 0x89, 0xed, 0xba, 0xb7, - 0x32, 0xfa, 0xc2, 0xe7, 0xc2, 0x86, 0x42, 0x9b, 0x5b, 0x88, 0x2c, 0xf0, 0xa1, 0x82, 0x70, 0x44, - 0x08, 0x64, 0xc3, 0xb4, 0xd9, 0xd6, 0x5b, 0xa4, 0xd1, 0xb5, 0xc4, 0xf1, 0x44, 0x4f, 0x4c, 0x1e, - 0xa9, 0xd7, 0x7a, 0xd7, 0x1c, 0x43, 0xb7, 0xf8, 0x17, 0x72, 0x31, 0xd9, 0x21, 0x2e, 0xfb, 0x50, - 0xaf, 0x3c, 0x69, 0xb2, 0x1a, 0xa3, 0x84, 0x13, 0xb4, 0xd1, 0x75, 0x98, 0xe9, 0xb8, 0xa6, 0xc3, - 0xde, 0x9b, 0xa5, 0x7b, 0xfc, 0x0b, 0xa9, 0x10, 0xbd, 0xcb, 0xd9, 0x88, 0x23, 0xe0, 0x64, 0x1f, - 0x5e, 0x7f, 0x80, 0x37, 0xb2, 0xb5, 0xdc, 0x68, 0x50, 0x7f, 0x80, 0xb7, 0x61, 0x09, 0x9d, 0xfd, - 0x02, 0xcc, 0x24, 0xc6, 0xa6, 0x2f, 0x87, 0xf0, 0x9b, 0x39, 0x88, 0xe7, 0xcb, 0xe9, 0xba, 0xa1, - 0x69, 0xba, 0x8c, 0xe0, 0x41, 0x3c, 0xc7, 0xbf, 0x1c, 0x00, 0x70, 0x88, 0x83, 0x2e, 0x43, 0xa1, - 0xa3, 0xfb, 0xbb, 0xf1, 0x63, 0x7e, 0x94, 0x24, 0x66, 0x10, 0x74, 0x15, 0x80, 0xfe, 0xc5, 0xa4, - 0x45, 0xee, 0x77, 0xc4, 0x32, 0x48, 0x6e, 0x3f, 0x34, 0x24, 0x04, 0x2b, 0x58, 0xf3, 0x7f, 0x37, - 0x0a, 0x93, 0xd1, 0xb9, 0x25, 0xb2, 0xd8, 0xcc, 0x3d, 0x72, 0xb1, 0x79, 0x05, 0x8a, 0x6d, 0xe2, - 0xef, 0x3a, 0xcd, 0xf8, 0x3c, 0xb9, 0xce, 0x5a, 0xb1, 0x80, 0x32, 0xf1, 0x1d, 0xd7, 0x17, 0x62, - 0x85, 0xe2, 0x3b, 0xae, 0x8f, 0x19, 0x24, 0x38, 0xa5, 0x58, 0xe8, 0x71, 0x4a, 0xb1, 0x05, 0xd3, - 0xbc, 0x02, 0xf0, 0x12, 0x71, 0xfd, 0x13, 0x9f, 0xae, 0xd5, 0x62, 0x24, 0x70, 0x82, 0x28, 0x6a, - 0x52, 0x6f, 0x43, 0xdb, 0xc2, 0x9d, 0x81, 0xfe, 0xef, 0xf6, 0x6b, 0x51, 0x0a, 0x38, 0x4e, 0x72, - 0x18, 0xd9, 0xc8, 0xe8, 0x7b, 0x3c, 0x71, 0xe9, 0xc4, 0x52, 0x56, 0xa5, 0x13, 0x5f, 0x81, 0xc9, - 0xb6, 0x7e, 0xbf, 0xa1, 0x1f, 0x58, 0x8e, 0xde, 0xd4, 0xcc, 0x07, 0x44, 0x5c, 0x3f, 0x45, 0x87, - 0x0f, 0xe7, 0x26, 0xd7, 0x23, 0x10, 0x1c, 0xc3, 0x1c, 0x6c, 0x02, 0xfe, 0xad, 0x11, 0x40, 0xc9, - 0x2f, 0x9b, 0xa0, 0x8f, 0x72, 0x30, 0x79, 0x2f, 0x32, 0x46, 0xc3, 0x09, 0xce, 0x64, 0xda, 0x2b, - 0xda, 0x8e, 0x63, 0xcc, 0x95, 0x05, 0xce, 0xc8, 0xe9, 0x2d, 0x24, 0xeb, 0xc6, 0x8f, 0x7f, 0x71, - 0xe9, 0x89, 0x9f, 0xfc, 0xe2, 0xd2, 0x13, 0x3f, 0xfd, 0xc5, 0xa5, 0x27, 0xbe, 0x7e, 0x78, 0x29, - 0xf7, 0xe3, 0xc3, 0x4b, 0xb9, 0x9f, 0x1c, 0x5e, 0xca, 0xfd, 0xf4, 0xf0, 0x52, 0xee, 0xe7, 0x87, - 0x97, 0x72, 0xdf, 0xfd, 0xc7, 0x4b, 0x4f, 0x7c, 0xf1, 0xf3, 0xa1, 0x28, 0x8b, 0x81, 0x28, 0xec, - 0x9f, 0x17, 0x39, 0xeb, 0xc5, 0xce, 0x5e, 0x6b, 0x91, 0x8a, 0xb2, 0xa8, 0x88, 0xb2, 0x18, 0x88, - 0xf2, 0xef, 0x01, 0x00, 0x00, 0xff, 0xff, 0x62, 0x2f, 0xb6, 0x86, 0xdc, 0xa5, 0x00, 0x00, + 0xc5, 0x49, 0x90, 0xc0, 0x40, 0x9c, 0x04, 0x06, 0x82, 0x04, 0xf9, 0x17, 0x23, 0x7f, 0x83, 0xe4, + 0x87, 0x91, 0xe4, 0x87, 0x93, 0x5f, 0x4e, 0x0c, 0x2c, 0x6c, 0x06, 0xf9, 0x97, 0x1f, 0x09, 0xfc, + 0x2b, 0xf9, 0x15, 0xd4, 0x47, 0x57, 0x57, 0x7f, 0x0c, 0x97, 0xc3, 0xe9, 0x21, 0xb5, 0x46, 0x7e, + 0x91, 0x53, 0xef, 0xd5, 0x7b, 0xaf, 0xab, 0xdf, 0x7b, 0xf5, 0xea, 0x55, 0xd5, 0x6b, 0x58, 0x6f, + 0x99, 0xfe, 0x6e, 0x77, 0x7b, 0xc1, 0x70, 0xda, 0x8b, 0xba, 0xdb, 0x72, 0x3a, 0xae, 0xf3, 0x15, + 0xf6, 0xcf, 0x8b, 0xe4, 0x2e, 0xb1, 0x7d, 0x6f, 0xb1, 0xb3, 0xd7, 0x5a, 0xd4, 0x3b, 0xa6, 0xb7, + 0xc8, 0x7f, 0x3b, 0x5d, 0xd7, 0x20, 0x8b, 0x77, 0x5f, 0xd2, 0xad, 0xce, 0xae, 0xfe, 0xd2, 0x62, + 0x8b, 0xd8, 0xc4, 0xd5, 0x7d, 0xd2, 0x5c, 0xe8, 0xb8, 0x8e, 0xef, 0xa0, 0xcf, 0x87, 0xe4, 0x16, + 0x02, 0x72, 0xec, 0x9f, 0xf7, 0x78, 0xf7, 0x85, 0xce, 0x5e, 0x6b, 0x81, 0x92, 0x5b, 0x50, 0xc8, + 0x2d, 0x04, 0xe4, 0x66, 0xbf, 0x70, 0x6c, 0x69, 0x0c, 0xa7, 0xdd, 0x76, 0xec, 0x38, 0xff, 0xd9, + 0x17, 0x15, 0x02, 0x2d, 0xa7, 0xe5, 0x2c, 0xb2, 0xe6, 0xed, 0xee, 0x0e, 0xfb, 0xc5, 0x7e, 0xb0, + 0xff, 0x04, 0xfa, 0xfc, 0xde, 0xcb, 0xde, 0x82, 0xe9, 0x50, 0x92, 0x8b, 0x86, 0xe3, 0xd2, 0x07, + 0x4b, 0x90, 0xfc, 0xef, 0x21, 0x4e, 0x5b, 0x37, 0x76, 0x4d, 0x9b, 0xb8, 0x07, 0xa1, 0x1c, 0x6d, + 0xe2, 0xeb, 0x69, 0xbd, 0x16, 0x7b, 0xf5, 0x72, 0xbb, 0xb6, 0x6f, 0xb6, 0x49, 0xa2, 0xc3, 0xff, + 0x78, 0x54, 0x07, 0xcf, 0xd8, 0x25, 0x6d, 0x3d, 0xde, 0x6f, 0xfe, 0x5f, 0x73, 0x30, 0x53, 0x5b, + 0xdf, 0x6c, 0x2c, 0x39, 0xb6, 0xd7, 0x6d, 0x93, 0x25, 0xc7, 0xde, 0x31, 0x5b, 0xe8, 0x33, 0x50, + 0x31, 0x78, 0x83, 0xbb, 0xa5, 0xb7, 0xaa, 0xb9, 0xcb, 0xb9, 0xe7, 0xca, 0xf5, 0x73, 0x3f, 0x7e, + 0x38, 0xf7, 0xc4, 0xe1, 0xc3, 0xb9, 0xca, 0x52, 0x08, 0xc2, 0x2a, 0x1e, 0x7a, 0x1e, 0xc6, 0xf4, + 0xae, 0xef, 0xd4, 0x8c, 0xbd, 0xea, 0xc8, 0xe5, 0xdc, 0x73, 0xa5, 0xfa, 0x94, 0xe8, 0x32, 0x56, + 0xe3, 0xcd, 0x38, 0x80, 0xa3, 0x45, 0x28, 0x93, 0xfb, 0x86, 0xd5, 0xf5, 0xcc, 0xbb, 0xa4, 0x9a, + 0x67, 0xc8, 0x33, 0x02, 0xb9, 0x7c, 0x2d, 0x00, 0xe0, 0x10, 0x87, 0xd2, 0xb6, 0x9d, 0x35, 0xc7, + 0xd0, 0xad, 0x6a, 0x21, 0x4a, 0x7b, 0x83, 0x37, 0xe3, 0x00, 0x8e, 0xae, 0x40, 0xd1, 0x76, 0xde, + 0xd4, 0x4d, 0xbf, 0x3a, 0xca, 0x30, 0x27, 0x05, 0x66, 0x71, 0x83, 0xb5, 0x62, 0x01, 0x9d, 0xff, + 0xa7, 0x0a, 0x4c, 0xd1, 0x67, 0xbf, 0x46, 0x95, 0x43, 0x63, 0xba, 0x84, 0x2e, 0x42, 0xbe, 0xeb, + 0x5a, 0xe2, 0x89, 0x2b, 0xa2, 0x63, 0xfe, 0x36, 0x5e, 0xc3, 0xb4, 0x1d, 0xbd, 0x0c, 0xe3, 0xe4, + 0xbe, 0xb1, 0xab, 0xdb, 0x2d, 0xb2, 0xa1, 0xb7, 0x09, 0x7b, 0xcc, 0x72, 0xfd, 0xbc, 0xc0, 0x1b, + 0xbf, 0xa6, 0xc0, 0x70, 0x04, 0x53, 0xed, 0xb9, 0x75, 0xd0, 0xe1, 0xcf, 0x9c, 0xd2, 0x93, 0xc2, + 0x70, 0x04, 0x13, 0x5d, 0x05, 0x70, 0x9d, 0xae, 0x6f, 0xda, 0xad, 0x9b, 0xe4, 0x80, 0x3d, 0x7c, + 0xb9, 0x8e, 0x44, 0x3f, 0xc0, 0x12, 0x82, 0x15, 0x2c, 0xf4, 0xbf, 0x60, 0xc6, 0x70, 0x6c, 0x9b, + 0x18, 0xbe, 0xe9, 0xd8, 0x75, 0xdd, 0xd8, 0x73, 0x76, 0x76, 0xd8, 0x68, 0x54, 0xae, 0xbe, 0xbc, + 0x70, 0x6c, 0x23, 0xe3, 0x56, 0xb2, 0x20, 0xfa, 0xd7, 0x9f, 0x3c, 0x7c, 0x38, 0x37, 0xb3, 0x14, + 0x27, 0x8b, 0x93, 0x9c, 0xd0, 0x0b, 0x50, 0xfa, 0x8a, 0xe7, 0xd8, 0x75, 0xa7, 0x79, 0x50, 0x2d, + 0xb2, 0x77, 0x30, 0x2d, 0x04, 0x2e, 0xbd, 0xae, 0xdd, 0xda, 0xa0, 0xed, 0x58, 0x62, 0xa0, 0xdb, + 0x90, 0xf7, 0x2d, 0xaf, 0x3a, 0xc6, 0xc4, 0x7b, 0xa5, 0x6f, 0xf1, 0xb6, 0xd6, 0x34, 0xae, 0xb6, + 0xf5, 0x31, 0xfa, 0xae, 0xb6, 0xd6, 0x34, 0x4c, 0xe9, 0xa1, 0xf7, 0x73, 0x50, 0xa2, 0xf6, 0xd5, + 0xd4, 0x7d, 0xbd, 0x5a, 0xba, 0x9c, 0x7f, 0xae, 0x72, 0xf5, 0x4b, 0x0b, 0x03, 0x39, 0x98, 0x85, + 0x98, 0xb6, 0x2c, 0xac, 0x0b, 0xf2, 0xd7, 0x6c, 0xdf, 0x3d, 0x08, 0x9f, 0x31, 0x68, 0xc6, 0x92, + 0x3f, 0xfa, 0x8d, 0x1c, 0x4c, 0x05, 0x6f, 0x75, 0x99, 0x18, 0x96, 0xee, 0x92, 0x6a, 0x99, 0x3d, + 0xf0, 0x9d, 0x2c, 0x64, 0x8a, 0x52, 0x16, 0xc3, 0x71, 0xee, 0xf0, 0xe1, 0xdc, 0x54, 0x0c, 0x84, + 0xe3, 0x52, 0xa0, 0x0f, 0x72, 0x30, 0xbe, 0xdf, 0x25, 0x5d, 0x29, 0x16, 0x30, 0xb1, 0x6e, 0x67, + 0x20, 0xd6, 0xa6, 0x42, 0x56, 0xc8, 0x34, 0x4d, 0x95, 0x5d, 0x6d, 0xc7, 0x11, 0xe6, 0xe8, 0x6b, + 0x50, 0x66, 0xbf, 0xeb, 0xa6, 0xdd, 0xac, 0x56, 0x98, 0x24, 0x38, 0x2b, 0x49, 0x28, 0x4d, 0x21, + 0xc6, 0x04, 0xf5, 0x33, 0xb2, 0x11, 0x87, 0x3c, 0xd1, 0x3d, 0x18, 0x13, 0x2e, 0xad, 0x3a, 0xce, + 0xd8, 0x37, 0x32, 0x60, 0x1f, 0xf1, 0xae, 0xf5, 0x0a, 0xf5, 0x5a, 0xa2, 0x09, 0x07, 0xdc, 0xd0, + 0x1d, 0x28, 0xe8, 0x5d, 0x7f, 0xb7, 0x3a, 0x71, 0x42, 0x33, 0xa8, 0xeb, 0x9e, 0x69, 0xd4, 0xba, + 0xfe, 0x6e, 0xbd, 0x74, 0xf8, 0x70, 0xae, 0x40, 0xff, 0xc3, 0x8c, 0x22, 0xc2, 0x50, 0xee, 0xba, + 0x96, 0x46, 0x0c, 0x97, 0xf8, 0xd5, 0x49, 0x46, 0xfe, 0xd3, 0x0b, 0x7c, 0xbe, 0xa0, 0x14, 0x16, + 0xe8, 0xd4, 0xb5, 0x70, 0xf7, 0xa5, 0x05, 0x8e, 0x71, 0x93, 0x1c, 0x68, 0xc4, 0x22, 0x86, 0xef, + 0xb8, 0x7c, 0x98, 0x6e, 0xe3, 0x35, 0x0e, 0xc1, 0x21, 0x19, 0xe4, 0x43, 0x71, 0xc7, 0xb4, 0x7c, + 0xe2, 0x56, 0xa7, 0x32, 0x19, 0x25, 0xc5, 0xaa, 0xae, 0x33, 0xba, 0x75, 0xa0, 0x1e, 0x9b, 0xff, + 0x8f, 0x05, 0xaf, 0xd9, 0x57, 0x61, 0x22, 0x62, 0x72, 0x68, 0x1a, 0xf2, 0x7b, 0xe4, 0x80, 0xbb, + 0x6b, 0x4c, 0xff, 0x45, 0xe7, 0x61, 0xf4, 0xae, 0x6e, 0x75, 0x85, 0x6b, 0xc6, 0xfc, 0xc7, 0x2b, + 0x23, 0x2f, 0xe7, 0xe6, 0x7f, 0x92, 0x83, 0xa7, 0x7b, 0x1a, 0x0b, 0x9d, 0x5f, 0x9a, 0x5d, 0x57, + 0xdf, 0xb6, 0x08, 0xa3, 0xa6, 0xcc, 0x2f, 0xcb, 0xbc, 0x19, 0x07, 0x70, 0xea, 0x90, 0xe9, 0x34, + 0xb6, 0x4c, 0x2c, 0xe2, 0x13, 0x31, 0xd3, 0x49, 0x87, 0x5c, 0x93, 0x10, 0xac, 0x60, 0x51, 0x8f, + 0x68, 0xda, 0x3e, 0x71, 0x6d, 0xdd, 0x12, 0xd3, 0x9d, 0xf4, 0x16, 0xab, 0xa2, 0x1d, 0x4b, 0x0c, + 0x65, 0x06, 0x2b, 0x1c, 0x39, 0x83, 0x7d, 0x1e, 0xce, 0xa5, 0x68, 0xb7, 0xd2, 0x3d, 0x77, 0x64, + 0xf7, 0xdf, 0x1b, 0x81, 0x0b, 0xe9, 0x76, 0x8a, 0x2e, 0x43, 0xc1, 0xa6, 0x13, 0x1c, 0x9f, 0x08, + 0xc7, 0x05, 0x81, 0x02, 0x9b, 0xd8, 0x18, 0x44, 0x1d, 0xb0, 0x91, 0xbe, 0x06, 0x2c, 0x7f, 0xac, + 0x01, 0x8b, 0x04, 0x08, 0x85, 0x63, 0x04, 0x08, 0xc7, 0x9c, 0xf5, 0x29, 0x61, 0xdd, 0x6d, 0x75, + 0xdb, 0x54, 0x09, 0xd9, 0xe4, 0x54, 0x0e, 0x09, 0xd7, 0x02, 0x00, 0x0e, 0x71, 0xe6, 0xdf, 0x1f, + 0x85, 0xa7, 0x6b, 0x0f, 0xba, 0x2e, 0x61, 0x3a, 0xea, 0xdd, 0xe8, 0x6e, 0xab, 0x01, 0xc3, 0x65, + 0x28, 0xec, 0xec, 0x37, 0xed, 0xf8, 0x40, 0x5d, 0xdf, 0x5c, 0xde, 0xc0, 0x0c, 0x82, 0x3a, 0x70, + 0xce, 0xdb, 0xd5, 0x5d, 0xd2, 0xac, 0x19, 0x06, 0xf1, 0xbc, 0x9b, 0xe4, 0x40, 0x86, 0x0e, 0xc7, + 0x36, 0xc4, 0xa7, 0x0e, 0x1f, 0xce, 0x9d, 0xd3, 0x92, 0x54, 0x70, 0x1a, 0x69, 0xd4, 0x84, 0xa9, + 0x58, 0x33, 0x1b, 0xf4, 0x63, 0x73, 0x63, 0x13, 0x47, 0x8c, 0x1b, 0x8e, 0x93, 0xa4, 0x0a, 0xb0, + 0xdb, 0xdd, 0x66, 0xcf, 0xc2, 0x83, 0x12, 0xa9, 0x00, 0x37, 0x78, 0x33, 0x0e, 0xe0, 0xe8, 0xd7, + 0xd4, 0xa9, 0x78, 0x94, 0x4d, 0xc5, 0x3b, 0x83, 0xba, 0xd5, 0x5e, 0x6f, 0xa4, 0x8f, 0x49, 0x39, + 0x74, 0x62, 0xc5, 0xc7, 0xc5, 0x89, 0xfd, 0x4e, 0x11, 0x9e, 0x61, 0x8f, 0xce, 0x6c, 0x56, 0xf3, + 0x1d, 0x57, 0x6f, 0x11, 0x55, 0x1f, 0x5f, 0x07, 0xe4, 0xf1, 0xd6, 0x9a, 0x61, 0x38, 0x5d, 0xdb, + 0xdf, 0x08, 0xcd, 0x78, 0x56, 0x8c, 0x05, 0xd2, 0x12, 0x18, 0x38, 0xa5, 0x17, 0x6a, 0xc1, 0x74, + 0x18, 0xdb, 0x69, 0xbe, 0x6b, 0xda, 0xad, 0xfe, 0xd4, 0xf6, 0xfc, 0xe1, 0xc3, 0xb9, 0xe9, 0xa5, + 0x18, 0x09, 0x9c, 0x20, 0x4a, 0x6d, 0x92, 0xcd, 0xc0, 0x4c, 0xd6, 0x7c, 0xd4, 0x26, 0x37, 0x03, + 0x00, 0x0e, 0x71, 0x22, 0x01, 0x66, 0xe1, 0x91, 0x01, 0xe6, 0x45, 0xc8, 0x37, 0xad, 0x7d, 0xe1, + 0x17, 0x64, 0x50, 0xbf, 0xbc, 0xb6, 0x89, 0x69, 0x3b, 0x8d, 0xcd, 0x42, 0xed, 0x2c, 0x32, 0xed, + 0x34, 0xb3, 0xd0, 0xce, 0x1e, 0xaf, 0xe8, 0x44, 0x0a, 0x3a, 0x76, 0x7a, 0x0a, 0x8a, 0x5e, 0x85, + 0x89, 0x26, 0x31, 0x9c, 0x26, 0x59, 0x27, 0x9e, 0xa7, 0xb7, 0x48, 0xb5, 0xc4, 0x06, 0xee, 0x49, + 0x21, 0xe8, 0xc4, 0xb2, 0x0a, 0xc4, 0x51, 0x5c, 0xb4, 0x04, 0x33, 0xf7, 0x74, 0xd3, 0xdf, 0x32, + 0xdb, 0x64, 0xd5, 0xd6, 0x88, 0xe1, 0xd8, 0x4d, 0x8f, 0x45, 0xba, 0xa3, 0x7c, 0xfd, 0xf0, 0x66, + 0x1c, 0x88, 0x93, 0xf8, 0x83, 0x99, 0xc8, 0x4f, 0x8b, 0x30, 0xcb, 0xc6, 0x5f, 0x23, 0xee, 0x5d, + 0xd3, 0x20, 0xf5, 0xae, 0xa7, 0x1a, 0x48, 0x9a, 0x52, 0xe7, 0x86, 0xae, 0xd4, 0x23, 0xc7, 0x50, + 0xea, 0x45, 0x28, 0xfb, 0x4e, 0xc7, 0x34, 0xd2, 0xac, 0x60, 0x2b, 0x00, 0xe0, 0x10, 0x07, 0x2d, + 0xc3, 0xb4, 0xd7, 0xdd, 0xf6, 0x0c, 0xd7, 0xec, 0x50, 0xbe, 0x8a, 0x2b, 0xae, 0x8a, 0x7e, 0xd3, + 0x5a, 0x0c, 0x8e, 0x13, 0x3d, 0x82, 0xe5, 0xd7, 0x68, 0xc6, 0xcb, 0xaf, 0xfe, 0xd6, 0x80, 0xdf, + 0x53, 0x6d, 0x70, 0x8c, 0xd9, 0x60, 0x2b, 0x0b, 0x1b, 0x4c, 0xd5, 0x81, 0x13, 0x59, 0x60, 0xe9, + 0x14, 0x2d, 0xf0, 0x2d, 0x78, 0x6a, 0xa7, 0x6b, 0x59, 0x07, 0x9b, 0x5d, 0xdd, 0x32, 0x77, 0x4c, + 0xd2, 0xa4, 0x2f, 0xca, 0xeb, 0xe8, 0x06, 0x5f, 0x34, 0x96, 0xeb, 0x73, 0x42, 0xe4, 0xa7, 0xae, + 0xa7, 0xa3, 0xe1, 0x5e, 0xfd, 0x07, 0x33, 0xad, 0xbf, 0xcf, 0xc1, 0x44, 0xdd, 0xf4, 0xb7, 0xbb, + 0xc6, 0x1e, 0xf1, 0xe9, 0x0a, 0x03, 0xb9, 0x30, 0xba, 0x4d, 0x17, 0x1e, 0xc2, 0x84, 0x36, 0x07, + 0x1c, 0x1e, 0x49, 0x3c, 0x5c, 0xcd, 0x94, 0x0f, 0x1f, 0xce, 0x8d, 0xb2, 0x9f, 0x98, 0xb3, 0x42, + 0xb7, 0x01, 0x1c, 0xba, 0xb0, 0xd9, 0x72, 0xf6, 0x88, 0xdd, 0xdf, 0x84, 0x34, 0x49, 0x23, 0xce, + 0x5b, 0xb5, 0xa0, 0x33, 0x56, 0x08, 0xcd, 0xff, 0x28, 0x07, 0x28, 0xc9, 0x1f, 0xdd, 0x82, 0x52, + 0xd7, 0xa3, 0x61, 0xb9, 0x98, 0x46, 0x8f, 0xcd, 0x6b, 0x9c, 0xaa, 0xd4, 0x6d, 0xd1, 0x15, 0x4b, + 0x22, 0x94, 0x60, 0x47, 0xf7, 0xbc, 0x7b, 0x8e, 0xdb, 0xec, 0x4f, 0x78, 0x46, 0xb0, 0x21, 0xba, + 0x62, 0x49, 0x64, 0xfe, 0x97, 0x63, 0x70, 0x5e, 0x0a, 0x1e, 0x8b, 0x05, 0x9a, 0x2c, 0x9a, 0xbe, + 0xe1, 0x38, 0x7b, 0xb7, 0xec, 0xeb, 0xa6, 0x6d, 0x7a, 0xbb, 0x62, 0x4d, 0x20, 0x63, 0x81, 0xe5, + 0x04, 0x06, 0x4e, 0xe9, 0x85, 0xbe, 0xa3, 0x1a, 0xe8, 0x08, 0x33, 0x50, 0x3d, 0xab, 0x97, 0x7d, + 0x52, 0xd3, 0x1c, 0xbb, 0x47, 0xb6, 0x77, 0x1d, 0x67, 0x4f, 0x44, 0xb7, 0xeb, 0x03, 0xca, 0xf3, + 0x26, 0xa7, 0xb6, 0xe4, 0xd8, 0x3e, 0xb9, 0xef, 0xf3, 0x65, 0xba, 0x68, 0xc3, 0x01, 0x2b, 0xf4, + 0x15, 0xb1, 0x4c, 0x2f, 0x30, 0x96, 0x6b, 0x59, 0x0d, 0x41, 0xea, 0xc2, 0x7d, 0x1e, 0x8a, 0xbc, + 0x17, 0x8b, 0x99, 0xcb, 0xdc, 0x55, 0xf0, 0x98, 0x17, 0x0b, 0x08, 0x7a, 0x11, 0x46, 0x9d, 0x7b, + 0xb6, 0x08, 0x61, 0xcb, 0xf5, 0xa7, 0xc4, 0x80, 0x4d, 0x2d, 0x93, 0x8e, 0x4b, 0x0c, 0xdd, 0x27, + 0xcd, 0x5b, 0x14, 0x8c, 0x39, 0x16, 0xfa, 0x9f, 0x00, 0x54, 0x44, 0x62, 0x50, 0xcd, 0x62, 0x51, + 0x45, 0xb9, 0xfe, 0x8c, 0xe8, 0x73, 0x3e, 0xec, 0xd3, 0x90, 0x38, 0x58, 0xc1, 0x47, 0x37, 0x60, + 0xd2, 0x25, 0x1d, 0xc7, 0x33, 0x7d, 0xc7, 0x3d, 0xd0, 0xac, 0x6e, 0x8b, 0x79, 0xc5, 0x72, 0xfd, + 0xb2, 0xa0, 0x50, 0x0d, 0x29, 0xe0, 0x08, 0x1e, 0x8e, 0xf5, 0x43, 0x1f, 0xe6, 0x60, 0x5c, 0x36, + 0x99, 0x84, 0x86, 0x08, 0xf9, 0x0c, 0x72, 0x3d, 0x72, 0x3c, 0x43, 0xf6, 0x61, 0x8e, 0x15, 0x2b, + 0xfc, 0x70, 0x84, 0xbb, 0xe2, 0xe6, 0xe1, 0x71, 0x59, 0x09, 0x3c, 0x80, 0x73, 0x29, 0x4f, 0x8b, + 0x9e, 0x0d, 0xf4, 0x81, 0x87, 0xfc, 0x13, 0xe2, 0xe1, 0x47, 0x23, 0x5a, 0xf0, 0x5a, 0xe2, 0x3d, + 0xf2, 0xf8, 0xe4, 0x82, 0xc0, 0x9e, 0x3c, 0xfa, 0xed, 0xcd, 0xff, 0x73, 0x05, 0x66, 0x25, 0x73, + 0x3a, 0xc5, 0x12, 0x57, 0xf5, 0x3b, 0x8a, 0x65, 0xe6, 0x4e, 0xcf, 0x32, 0xa3, 0xaa, 0x3d, 0x32, + 0xb0, 0x6a, 0xe7, 0x4f, 0xa8, 0xda, 0xcf, 0x41, 0x49, 0xd0, 0xf5, 0xaa, 0x05, 0x66, 0xb7, 0xdc, + 0x71, 0x8b, 0x36, 0x2c, 0xa1, 0xe8, 0xff, 0xc5, 0x8d, 0x80, 0x2f, 0x8d, 0xef, 0x64, 0x65, 0x04, + 0xfc, 0xcd, 0xf4, 0x69, 0x0a, 0xa1, 0xd3, 0x29, 0xf6, 0x74, 0x3a, 0x7b, 0x70, 0xd1, 0xdb, 0x33, + 0x3b, 0x75, 0x57, 0xb7, 0x8d, 0x5d, 0x4c, 0x76, 0xbc, 0x25, 0x96, 0x51, 0x6b, 0xde, 0xb2, 0x6f, + 0x75, 0x88, 0xdd, 0xc0, 0xcc, 0xb1, 0x94, 0xea, 0x9f, 0x16, 0xec, 0x2e, 0x6a, 0x47, 0x21, 0xe3, + 0xa3, 0x69, 0xa1, 0x15, 0x98, 0x71, 0x6c, 0xbe, 0x80, 0x6a, 0x10, 0x97, 0x43, 0xc5, 0x92, 0xe4, + 0x69, 0xc1, 0x60, 0xe6, 0x56, 0x1c, 0x01, 0x27, 0xfb, 0xa0, 0x3b, 0x50, 0xd1, 0x59, 0xf6, 0x82, + 0x07, 0x0e, 0xe5, 0x7e, 0xe6, 0xde, 0xa9, 0xc3, 0x87, 0x73, 0x95, 0x5a, 0xd8, 0x1b, 0xab, 0xa4, + 0xd0, 0xbb, 0x30, 0x21, 0xb4, 0x50, 0x64, 0x59, 0xa1, 0x1f, 0xda, 0x33, 0x74, 0x51, 0xf5, 0xa6, + 0xda, 0x1f, 0x47, 0xc9, 0xa1, 0x37, 0xe0, 0xc2, 0x76, 0xf0, 0x52, 0x3d, 0xf6, 0x52, 0xeb, 0xba, + 0x47, 0x6e, 0xe3, 0x35, 0x96, 0x22, 0x2f, 0xd7, 0x2f, 0x89, 0x71, 0xb8, 0x10, 0x7b, 0xf5, 0x02, + 0x0b, 0xf7, 0xe8, 0xdd, 0x23, 0x40, 0x18, 0x3f, 0x51, 0x80, 0x10, 0x89, 0xe0, 0x27, 0x32, 0x89, + 0xe0, 0x7b, 0xbb, 0x98, 0x13, 0x45, 0xf0, 0x93, 0xa7, 0x18, 0xc1, 0x8b, 0x45, 0xd5, 0x54, 0xc6, + 0x8b, 0xaa, 0x57, 0x61, 0xc2, 0xd8, 0x25, 0xc6, 0x1e, 0xcb, 0x19, 0xdf, 0xd5, 0xad, 0xea, 0x34, + 0x7b, 0xff, 0x72, 0x69, 0xbe, 0xa4, 0x02, 0x71, 0x14, 0x77, 0xb0, 0xe9, 0xe6, 0x3b, 0x39, 0x78, + 0xba, 0xa7, 0x63, 0x41, 0x57, 0x23, 0xbe, 0x37, 0x17, 0xdd, 0xa3, 0xec, 0xe1, 0x71, 0x07, 0x9d, + 0x84, 0x7e, 0x7f, 0x14, 0xce, 0x2d, 0xe9, 0x16, 0xb1, 0x9b, 0x7a, 0x64, 0xf6, 0x79, 0x01, 0x4a, + 0x9e, 0xb1, 0x4b, 0x9a, 0x5d, 0x2b, 0xc8, 0x7b, 0x49, 0xf5, 0xd0, 0x44, 0x3b, 0x96, 0x18, 0x32, + 0x31, 0x4f, 0x07, 0x73, 0x24, 0x8a, 0x2d, 0xc7, 0x51, 0x62, 0xa0, 0x57, 0x60, 0x52, 0x64, 0x9c, + 0x1d, 0x7b, 0x59, 0xf7, 0x89, 0x57, 0xcd, 0x33, 0x27, 0x89, 0xa8, 0xbc, 0xd7, 0x22, 0x10, 0x1c, + 0xc3, 0xa4, 0x9c, 0x7c, 0xb3, 0x4d, 0x1e, 0x38, 0x76, 0xb0, 0x4a, 0x97, 0x9c, 0xb6, 0x44, 0x3b, + 0x96, 0x18, 0xe8, 0xdb, 0xc9, 0x94, 0xe9, 0x97, 0x07, 0xd4, 0xdc, 0x94, 0xc1, 0xea, 0xc3, 0x8e, + 0xbe, 0x91, 0x83, 0x4a, 0x87, 0xb8, 0x9e, 0xe9, 0xf9, 0xc4, 0x36, 0x88, 0x48, 0x99, 0xde, 0xca, + 0xc2, 0x9a, 0x1a, 0x21, 0x59, 0xee, 0x68, 0x95, 0x06, 0xac, 0x32, 0x3d, 0x9b, 0xe5, 0xf8, 0x60, + 0x86, 0x73, 0x1f, 0xce, 0x2f, 0xe9, 0xbe, 0xb1, 0xdb, 0xed, 0x70, 0x8b, 0xee, 0xba, 0xba, 0x6f, + 0x3a, 0x36, 0x7a, 0x1e, 0xc6, 0x88, 0xad, 0x6f, 0x5b, 0xa4, 0x19, 0xdf, 0x70, 0xba, 0xc6, 0x9b, + 0x71, 0x00, 0x47, 0x9f, 0x81, 0x4a, 0x5b, 0xbf, 0xbf, 0x2c, 0x7a, 0x0a, 0x35, 0x95, 0xc7, 0x31, + 0xd6, 0x43, 0x10, 0x56, 0xf1, 0xe6, 0xbf, 0x0a, 0xe7, 0x39, 0xcb, 0x75, 0xbd, 0xa3, 0x8c, 0xe8, + 0x31, 0xf6, 0x76, 0x96, 0x61, 0xda, 0x70, 0x89, 0xee, 0x93, 0xd5, 0x9d, 0x0d, 0xc7, 0xbf, 0x76, + 0xdf, 0xf4, 0x7c, 0xb1, 0xc9, 0x23, 0x13, 0x4b, 0x4b, 0x31, 0x38, 0x4e, 0xf4, 0x98, 0xff, 0xee, + 0x18, 0xa0, 0x6b, 0x6d, 0xd3, 0xf7, 0xa3, 0xd1, 0xe1, 0x15, 0x28, 0x6e, 0xbb, 0xce, 0x9e, 0x0c, + 0x51, 0xe5, 0x46, 0x4d, 0x9d, 0xb5, 0x62, 0x01, 0xa5, 0x3e, 0xc5, 0xd8, 0xd5, 0x6d, 0x9b, 0x58, + 0x61, 0x3c, 0x27, 0x7d, 0xca, 0x92, 0x84, 0x60, 0x05, 0x8b, 0x1d, 0x5c, 0xe1, 0xbf, 0x94, 0x24, + 0x5a, 0x78, 0x70, 0x25, 0x04, 0x61, 0x15, 0x2f, 0xb2, 0xc6, 0x2f, 0x64, 0xbd, 0xc6, 0x1f, 0xcd, + 0x60, 0x8d, 0x9f, 0x7e, 0xa0, 0xa3, 0x78, 0x26, 0x07, 0x3a, 0xc6, 0x8e, 0x7b, 0xa0, 0xa3, 0x94, + 0xf1, 0xe4, 0xf7, 0x91, 0xea, 0x12, 0xf9, 0x7a, 0xf1, 0xbd, 0x41, 0xed, 0x3f, 0xa1, 0x9e, 0x27, + 0x8a, 0x2c, 0x1e, 0x9b, 0x45, 0xe3, 0xc7, 0x23, 0x30, 0x1d, 0x77, 0xb9, 0xe8, 0x01, 0x8c, 0x19, + 0xdc, 0x43, 0x89, 0xe5, 0x9a, 0x36, 0xf0, 0x44, 0x93, 0xf4, 0x77, 0xe2, 0xd4, 0x03, 0x87, 0xe0, + 0x80, 0x21, 0xfa, 0x7a, 0x0e, 0xca, 0x46, 0xe0, 0xa4, 0x44, 0x3a, 0x6c, 0x60, 0xf6, 0x29, 0x4e, + 0x8f, 0x1f, 0x65, 0x90, 0x10, 0x1c, 0x32, 0x9d, 0xff, 0xd9, 0x08, 0x54, 0x54, 0xff, 0xf4, 0x65, + 0x45, 0xcb, 0xf8, 0x78, 0xfc, 0x57, 0xc5, 0x76, 0xe5, 0xe9, 0xba, 0x50, 0x08, 0x8a, 0x4d, 0xad, + 0xf9, 0xd6, 0x36, 0x0d, 0x6d, 0xe8, 0xcb, 0x09, 0xfd, 0x54, 0xd8, 0xa6, 0x28, 0x4e, 0x07, 0x0a, + 0x5e, 0x87, 0x18, 0xe2, 0x71, 0x37, 0xb2, 0x53, 0x1b, 0xad, 0x43, 0x8c, 0xd0, 0xa1, 0xd3, 0x5f, + 0x98, 0x71, 0x42, 0xf7, 0xa1, 0xe8, 0xf9, 0xba, 0xdf, 0xf5, 0x44, 0xaa, 0x2c, 0x43, 0x55, 0xd5, + 0x18, 0xdd, 0xd0, 0x8b, 0xf3, 0xdf, 0x58, 0xf0, 0x9b, 0x5f, 0x81, 0x99, 0x84, 0x5e, 0x53, 0xd7, + 0x4e, 0xee, 0x77, 0x5c, 0xe2, 0xd1, 0xe8, 0x28, 0x1e, 0x2e, 0x5e, 0x93, 0x10, 0xac, 0x60, 0xcd, + 0xff, 0x3c, 0x07, 0x53, 0x0a, 0xa5, 0x35, 0xd3, 0xf3, 0xd1, 0x97, 0x12, 0xaf, 0x6a, 0xe1, 0x78, + 0xaf, 0x8a, 0xf6, 0x66, 0x2f, 0x4a, 0xda, 0x77, 0xd0, 0xa2, 0xbc, 0x26, 0x07, 0x46, 0x4d, 0x9f, + 0xb4, 0x3d, 0x91, 0xee, 0x7c, 0x3d, 0xbb, 0x31, 0x0b, 0xd3, 0x32, 0xab, 0x94, 0x01, 0xe6, 0x7c, + 0xe6, 0xff, 0xfc, 0x7a, 0xe4, 0x11, 0xe9, 0xfb, 0x63, 0xe7, 0x06, 0x69, 0x53, 0xbd, 0xeb, 0x29, + 0x3b, 0xb9, 0xe1, 0xb9, 0x41, 0x05, 0x86, 0x23, 0x98, 0x68, 0x1f, 0x4a, 0x3e, 0x69, 0x77, 0x2c, + 0xdd, 0x0f, 0x0e, 0x1b, 0xac, 0x0c, 0xf8, 0x04, 0x5b, 0x82, 0x1c, 0x9f, 0xa5, 0x82, 0x5f, 0x58, + 0xb2, 0x41, 0x6d, 0x18, 0xf3, 0xf8, 0x86, 0x8b, 0xd0, 0xb3, 0xeb, 0x03, 0x72, 0x0c, 0xb6, 0x6f, + 0x98, 0xf3, 0x10, 0x3f, 0x70, 0xc0, 0x03, 0x7d, 0x15, 0x46, 0xdb, 0xa6, 0x6d, 0x3a, 0x2c, 0xcd, + 0x52, 0xb9, 0xfa, 0x56, 0xb6, 0x86, 0xb4, 0xb0, 0x4e, 0x69, 0xf3, 0x69, 0x40, 0xbe, 0x2f, 0xd6, + 0x86, 0x39, 0x5b, 0x76, 0xc2, 0xd0, 0x10, 0x41, 0xb5, 0x88, 0xd1, 0xbf, 0x94, 0xb1, 0x0c, 0x32, + 0x66, 0x8f, 0xce, 0x46, 0x41, 0x33, 0x96, 0xfc, 0xd1, 0x03, 0x28, 0xec, 0x98, 0x16, 0x11, 0x1b, + 0xd8, 0x77, 0x32, 0x96, 0xe3, 0xba, 0x69, 0x11, 0x2e, 0x43, 0x78, 0xc4, 0xc5, 0xb4, 0x08, 0x66, + 0x3c, 0xd9, 0x40, 0xb8, 0x84, 0xd3, 0x10, 0xbb, 0x77, 0x59, 0x0f, 0x04, 0x16, 0xe4, 0x63, 0x03, + 0x11, 0x34, 0x63, 0xc9, 0x1f, 0xfd, 0xef, 0x5c, 0x98, 0x7e, 0xe4, 0xc7, 0x3e, 0xdf, 0xce, 0x58, + 0x16, 0x91, 0xab, 0xe1, 0xa2, 0xc8, 0xb0, 0x3d, 0x91, 0x90, 0x7c, 0x00, 0x05, 0xbd, 0xbd, 0xdf, + 0x11, 0xa1, 0x4a, 0xd6, 0x6f, 0xa4, 0xd6, 0xde, 0xef, 0xc4, 0xde, 0x48, 0x6d, 0x7d, 0xb3, 0x81, + 0x19, 0x4f, 0x6a, 0x1a, 0x7b, 0xfa, 0xce, 0x9e, 0x5e, 0x85, 0xa1, 0x98, 0xc6, 0x4d, 0x4a, 0x3b, + 0x66, 0x1a, 0xac, 0x0d, 0x73, 0xb6, 0xf4, 0xd9, 0xdb, 0xfb, 0xbe, 0x5f, 0xad, 0x0c, 0xe5, 0xd9, + 0xd7, 0xf7, 0x7d, 0x3f, 0xf6, 0xec, 0xeb, 0x9b, 0x5b, 0x5b, 0x98, 0xf1, 0xa4, 0xbc, 0x6d, 0xdd, + 0xf7, 0xaa, 0xe3, 0x43, 0xe1, 0xbd, 0xa1, 0xfb, 0x5e, 0x8c, 0xf7, 0x46, 0x6d, 0x4b, 0xc3, 0x8c, + 0x27, 0xba, 0x0b, 0x79, 0xcf, 0xf6, 0x44, 0xfe, 0xeb, 0xcd, 0x8c, 0x59, 0x6b, 0xb6, 0xe0, 0x2c, + 0xcf, 0xb0, 0x68, 0x1b, 0x1a, 0xa6, 0x0c, 0x19, 0xdf, 0x7d, 0xaf, 0x3a, 0x39, 0x1c, 0xbe, 0xfb, + 0x09, 0xbe, 0x9b, 0x94, 0xef, 0xbe, 0x87, 0xbe, 0x91, 0x83, 0x62, 0xa7, 0xbb, 0xad, 0x75, 0xb7, + 0xab, 0x53, 0x8c, 0xf7, 0x17, 0x33, 0xe6, 0xdd, 0x60, 0xc4, 0x39, 0x7b, 0x19, 0x63, 0xf0, 0x46, + 0x2c, 0x38, 0x33, 0x21, 0x38, 0xd7, 0xea, 0xf4, 0x50, 0x84, 0x58, 0x61, 0xd4, 0x62, 0x42, 0xf0, + 0x46, 0x2c, 0x38, 0x07, 0x42, 0x58, 0xfa, 0x76, 0x75, 0x66, 0x58, 0x42, 0x58, 0x7a, 0x8a, 0x10, + 0x96, 0xce, 0x85, 0xb0, 0xf4, 0x6d, 0xaa, 0xfa, 0xbb, 0xcd, 0x1d, 0xaf, 0x8a, 0x86, 0xa2, 0xfa, + 0x37, 0x9a, 0x3b, 0x71, 0xd5, 0xbf, 0xb1, 0x7c, 0x5d, 0xc3, 0x8c, 0x27, 0x75, 0x39, 0x9e, 0xa5, + 0x1b, 0x7b, 0xd5, 0x73, 0x43, 0x71, 0x39, 0x1a, 0xa5, 0x1d, 0x73, 0x39, 0xac, 0x0d, 0x73, 0xb6, + 0xe8, 0xd7, 0x73, 0x50, 0x11, 0x87, 0xd8, 0x56, 0x5c, 0xb3, 0x59, 0x3d, 0x9f, 0xcd, 0x0a, 0x31, + 0x2e, 0x46, 0xc8, 0x81, 0x0b, 0x23, 0xb3, 0x0b, 0x0a, 0x04, 0xab, 0x82, 0xa0, 0xdf, 0xcd, 0xc1, + 0xa4, 0x1e, 0x39, 0xae, 0x58, 0x7d, 0x92, 0xc9, 0xb6, 0x9d, 0xf5, 0x94, 0x10, 0x3d, 0x13, 0xc9, + 0xc4, 0x93, 0xd9, 0xd4, 0x28, 0x10, 0xc7, 0x24, 0x62, 0xea, 0xeb, 0xf9, 0xae, 0xd9, 0x21, 0xd5, + 0x0b, 0x43, 0x51, 0x5f, 0x8d, 0x11, 0x8f, 0xa9, 0x2f, 0x6f, 0xc4, 0x82, 0x33, 0x9b, 0xba, 0x09, + 0x5f, 0x92, 0x57, 0x9f, 0x1a, 0xca, 0xd4, 0x1d, 0x2c, 0xf8, 0xa3, 0x53, 0xb7, 0x68, 0xc5, 0x01, + 0x73, 0xaa, 0xcb, 0x2e, 0x69, 0x9a, 0x5e, 0xb5, 0x3a, 0x14, 0x5d, 0xc6, 0x94, 0x76, 0x4c, 0x97, + 0x59, 0x1b, 0xe6, 0x6c, 0xa9, 0x3b, 0xb7, 0xbd, 0xfd, 0xea, 0xd3, 0x43, 0x71, 0xe7, 0x1b, 0xde, + 0x7e, 0xcc, 0x9d, 0x6f, 0x68, 0x9b, 0x98, 0x32, 0x14, 0xee, 0xdc, 0xf2, 0x74, 0xb7, 0x3a, 0x3b, + 0x24, 0x77, 0x4e, 0x89, 0x27, 0xdc, 0x39, 0x6d, 0xc4, 0x82, 0x33, 0xd3, 0x02, 0x76, 0x4f, 0xcd, + 0x34, 0xaa, 0x9f, 0x1a, 0x8a, 0x16, 0xac, 0x70, 0xea, 0x31, 0x2d, 0x10, 0xad, 0x38, 0x60, 0x8e, + 0x9e, 0xa3, 0x51, 0x6d, 0xc7, 0x32, 0x0d, 0xdd, 0xab, 0x3e, 0xc3, 0x8e, 0x30, 0x8e, 0xf3, 0x98, + 0x93, 0xb7, 0x61, 0x09, 0x45, 0x3f, 0xcc, 0xc1, 0x54, 0x6c, 0x8f, 0xad, 0x7a, 0x91, 0x89, 0x6e, + 0x64, 0x2c, 0x7a, 0x3d, 0xca, 0x85, 0x3f, 0x82, 0x3c, 0xf5, 0x11, 0xdf, 0xa1, 0x89, 0x0b, 0x85, + 0xbe, 0x9d, 0x83, 0xb2, 0x6c, 0xab, 0x5e, 0x62, 0x22, 0xbe, 0x33, 0x2c, 0x11, 0xb9, 0x70, 0xf2, + 0x0c, 0x63, 0x78, 0x5c, 0x21, 0x14, 0x81, 0x79, 0x6d, 0xa6, 0xf3, 0x9a, 0xef, 0x12, 0xbd, 0x5d, + 0x9d, 0x1b, 0x8a, 0xd7, 0xc6, 0x21, 0x87, 0x98, 0xd7, 0x56, 0x20, 0x58, 0x15, 0x84, 0xbd, 0x52, + 0x3d, 0x7a, 0x84, 0xb0, 0x7a, 0x79, 0x28, 0xaf, 0x34, 0x7e, 0x50, 0x31, 0xfa, 0x4a, 0x63, 0x50, + 0x1c, 0x17, 0x0a, 0xfd, 0x71, 0x0e, 0x66, 0xf4, 0xf8, 0x79, 0xe3, 0xea, 0x7f, 0x62, 0xa2, 0x92, + 0x61, 0x88, 0x1a, 0x39, 0xd7, 0xcc, 0x84, 0x95, 0xfb, 0xf0, 0x09, 0x38, 0x4e, 0x8a, 0x46, 0x83, + 0x14, 0x6f, 0xc7, 0xef, 0x54, 0xe7, 0x87, 0x12, 0xa4, 0x68, 0x3b, 0x7e, 0x7c, 0x5d, 0xa4, 0x5d, + 0xdf, 0x6a, 0x60, 0xc6, 0x93, 0x47, 0x69, 0xc4, 0x75, 0x4d, 0xbf, 0xfa, 0xec, 0x70, 0xa2, 0x34, + 0x46, 0x3c, 0x1e, 0xa5, 0xb1, 0x46, 0x2c, 0x38, 0xcf, 0x76, 0x01, 0xc2, 0xdc, 0x42, 0x4a, 0xfe, + 0x76, 0x53, 0xcd, 0xdf, 0x56, 0xae, 0xbe, 0xda, 0x77, 0x06, 0x5d, 0xfb, 0x6f, 0x35, 0xd7, 0x37, + 0x77, 0x74, 0xc3, 0x57, 0x92, 0xbf, 0xb3, 0xdf, 0xc9, 0xc1, 0x44, 0x24, 0x9f, 0x90, 0xc2, 0x7a, + 0x37, 0xca, 0x1a, 0x67, 0xbf, 0xe5, 0xa8, 0x4a, 0xf4, 0x7f, 0x72, 0x50, 0x96, 0x99, 0x85, 0x14, + 0x69, 0x9a, 0x51, 0x69, 0x06, 0xcd, 0x94, 0x32, 0x56, 0xe9, 0x92, 0xd0, 0xb1, 0x89, 0xa4, 0x18, + 0x86, 0x3f, 0x36, 0x92, 0x5d, 0xba, 0x44, 0x1f, 0xe5, 0x60, 0x5c, 0x4d, 0x34, 0xa4, 0x08, 0xd4, + 0x8a, 0x0a, 0xb4, 0x99, 0xcd, 0x29, 0xab, 0x23, 0xde, 0x95, 0xcc, 0x39, 0x0c, 0xff, 0x5d, 0xc5, + 0xae, 0xda, 0xaa, 0x92, 0x7c, 0x2b, 0x07, 0x10, 0x26, 0x20, 0x52, 0x44, 0x21, 0x51, 0x51, 0x06, + 0xdd, 0xa3, 0xe6, 0xbc, 0x7a, 0x8f, 0x8a, 0xcc, 0x46, 0x0c, 0x7f, 0x54, 0xd6, 0x37, 0xb7, 0xb6, + 0x7a, 0x48, 0xf2, 0x7f, 0x73, 0x50, 0x96, 0xb9, 0x89, 0xe1, 0x0f, 0xca, 0x46, 0x6d, 0x4b, 0xe3, + 0xab, 0x87, 0xa4, 0x28, 0xdf, 0xcc, 0x41, 0x29, 0xc8, 0x55, 0xa4, 0x48, 0x62, 0x44, 0x25, 0x19, + 0xf4, 0x70, 0xa0, 0xb6, 0xa1, 0xf5, 0x18, 0x12, 0x26, 0xc7, 0xfe, 0xa9, 0xc9, 0xb1, 0xd9, 0x4b, + 0x8e, 0x0f, 0x72, 0x50, 0x51, 0xf2, 0x18, 0x29, 0xa2, 0xec, 0x44, 0x45, 0x19, 0x74, 0x7b, 0x46, + 0x30, 0xeb, 0x2d, 0x8d, 0x92, 0xd0, 0x18, 0xbe, 0x34, 0x82, 0xd9, 0x91, 0xd2, 0x04, 0x99, 0x8d, + 0x53, 0x91, 0x86, 0x32, 0xeb, 0x6d, 0xce, 0x32, 0xcb, 0x31, 0x7c, 0x73, 0xbe, 0xb1, 0x7c, 0x5d, + 0x3b, 0xc2, 0xc9, 0x85, 0x29, 0x8f, 0xe1, 0xdb, 0x33, 0xe7, 0x95, 0x2e, 0xcb, 0xf7, 0x72, 0x30, + 0x1d, 0xcf, 0x7b, 0xa4, 0x48, 0xb4, 0x17, 0x95, 0x68, 0xd0, 0x0a, 0x02, 0x2a, 0xc7, 0x74, 0xb9, + 0x7e, 0x3b, 0x07, 0xe7, 0x52, 0x72, 0x1e, 0x29, 0xa2, 0xd9, 0x51, 0xd1, 0xee, 0x0c, 0xeb, 0xf2, + 0x69, 0x5c, 0xb3, 0x95, 0xa4, 0xc7, 0xf0, 0x35, 0x5b, 0x30, 0xeb, 0x1d, 0x4e, 0xa8, 0xc9, 0x8f, + 0xe1, 0x87, 0x13, 0xc9, 0xb3, 0x15, 0x71, 0xfd, 0x0e, 0xd3, 0x20, 0xc3, 0xd7, 0x6f, 0xce, 0xab, + 0xf7, 0x3c, 0x11, 0x24, 0x45, 0x86, 0x3f, 0x4f, 0x6c, 0x68, 0x9b, 0x47, 0xce, 0x13, 0x32, 0x41, + 0x72, 0x1a, 0xf3, 0x04, 0x63, 0xd6, 0x5b, 0x63, 0xd4, 0x44, 0xc9, 0xf0, 0x35, 0x26, 0xe0, 0x96, + 0x2e, 0xcf, 0xf7, 0x73, 0xca, 0x35, 0x27, 0x25, 0xfb, 0x91, 0x22, 0x97, 0x13, 0x95, 0xeb, 0xad, + 0xa1, 0x9d, 0x43, 0x56, 0xe5, 0xfb, 0x38, 0x07, 0x93, 0xd1, 0xd4, 0x47, 0x8a, 0x64, 0x66, 0x54, + 0x32, 0x6d, 0x08, 0x57, 0xa8, 0xe2, 0x9e, 0x3b, 0x9e, 0xfb, 0x18, 0xbe, 0xe7, 0x56, 0x39, 0xf6, + 0x7e, 0x97, 0x69, 0x69, 0x8f, 0xe1, 0xbf, 0xcb, 0xde, 0xb7, 0x42, 0x55, 0xf9, 0x7e, 0x90, 0x83, + 0x0b, 0xe9, 0xb9, 0x8e, 0x14, 0x09, 0xf7, 0xa3, 0x12, 0xbe, 0x3d, 0xc4, 0xbb, 0xe3, 0xf1, 0x58, + 0x45, 0x26, 0x3b, 0x86, 0x1f, 0xab, 0x68, 0xd7, 0xb7, 0x1a, 0x47, 0xc5, 0x70, 0x61, 0xde, 0xe3, + 0x14, 0x62, 0x38, 0xce, 0x2c, 0x55, 0x9a, 0x79, 0x3f, 0x72, 0xe2, 0x88, 0x1f, 0x47, 0x42, 0xef, + 0xc9, 0x03, 0x50, 0xfc, 0x9c, 0xd0, 0x67, 0xfb, 0xcf, 0xa9, 0x1c, 0x7d, 0xce, 0xe9, 0xcf, 0x0a, + 0x30, 0x15, 0xcb, 0x2f, 0xb0, 0x1a, 0x26, 0xf4, 0x27, 0x2b, 0xf8, 0x95, 0x8b, 0x5e, 0xe8, 0xbe, + 0x16, 0x00, 0x70, 0x88, 0x83, 0x3e, 0xce, 0xc1, 0xd4, 0x3d, 0xdd, 0x37, 0x76, 0x1b, 0xba, 0xbf, + 0xcb, 0x0f, 0xab, 0x65, 0xf4, 0xf6, 0xde, 0x8c, 0x52, 0x0d, 0xd3, 0x8b, 0x31, 0x00, 0x8e, 0xf3, + 0x47, 0xcf, 0xc3, 0x58, 0xc7, 0xb1, 0x2c, 0xd3, 0x6e, 0x89, 0xca, 0x2d, 0x32, 0x5f, 0xde, 0xe0, + 0xcd, 0x38, 0x80, 0x47, 0x2b, 0x6e, 0x15, 0x32, 0x39, 0x06, 0x12, 0x1b, 0xd2, 0x13, 0x9d, 0xce, + 0x1c, 0x7d, 0x5c, 0x4e, 0x67, 0xfe, 0x4d, 0x01, 0x50, 0x72, 0x0e, 0x7c, 0x54, 0x4d, 0xba, 0x2b, + 0x50, 0x34, 0x42, 0x55, 0x51, 0xce, 0x53, 0x8b, 0x37, 0x2a, 0xa0, 0xfc, 0xa6, 0x83, 0x47, 0x8c, + 0xae, 0x4b, 0x92, 0x25, 0x88, 0x78, 0x3b, 0x96, 0x18, 0x7d, 0x56, 0xd8, 0xf8, 0x28, 0x79, 0x5b, + 0xe1, 0xbd, 0xcc, 0x83, 0x81, 0x3e, 0x5e, 0xfe, 0x6d, 0x56, 0x71, 0x68, 0x57, 0xdc, 0xc6, 0x2a, + 0xf6, 0x7d, 0x45, 0xbc, 0x26, 0x3b, 0x63, 0x85, 0xd0, 0xd9, 0xd4, 0xe3, 0x18, 0x4c, 0xa7, 0x7e, + 0x56, 0x84, 0x99, 0x84, 0xbb, 0x3c, 0xa3, 0x1b, 0x9a, 0x2f, 0x40, 0x89, 0xfe, 0x55, 0x0a, 0x62, + 0xc8, 0x77, 0x78, 0x43, 0xb4, 0x63, 0x89, 0xa1, 0x5c, 0x44, 0xcc, 0xf7, 0xbc, 0x88, 0x78, 0x27, + 0x72, 0x1b, 0x3b, 0xcb, 0xa2, 0x69, 0xaf, 0xc2, 0x04, 0xcf, 0xd6, 0x07, 0x37, 0xed, 0x46, 0xa3, + 0x37, 0xad, 0x56, 0x54, 0x20, 0x8e, 0xe2, 0xf6, 0xb8, 0x57, 0x57, 0x3c, 0xd1, 0xbd, 0xba, 0x0f, + 0x93, 0x95, 0x31, 0xde, 0xcd, 0x7a, 0xfa, 0xec, 0xc3, 0xb2, 0xd4, 0xdb, 0xad, 0xa5, 0x23, 0x6f, + 0xb7, 0x2e, 0x42, 0xd9, 0xf3, 0xac, 0x37, 0x88, 0x6b, 0xee, 0x1c, 0xb0, 0xcb, 0x96, 0x4a, 0x05, + 0x2f, 0x2d, 0x00, 0xe0, 0x10, 0xe7, 0x71, 0x3c, 0x4f, 0xff, 0xd7, 0x39, 0x98, 0xe4, 0xe9, 0xad, + 0x5a, 0xa7, 0xb3, 0xe4, 0x92, 0xa6, 0x47, 0x5d, 0x4f, 0xc7, 0x35, 0xef, 0xea, 0x3e, 0x09, 0xae, + 0xc2, 0xf5, 0xe7, 0x7a, 0x1a, 0xb2, 0x33, 0x56, 0x08, 0xa1, 0x67, 0x61, 0x54, 0xef, 0x74, 0x56, + 0x97, 0x99, 0x0c, 0xf9, 0xf0, 0xd8, 0x40, 0x8d, 0x36, 0x62, 0x0e, 0x43, 0xaf, 0xc1, 0xa4, 0x69, + 0x7b, 0xbe, 0x6e, 0x59, 0xec, 0xcc, 0xfd, 0xea, 0x32, 0x73, 0xf4, 0xf9, 0xf0, 0x10, 0xc8, 0x6a, + 0x04, 0x8a, 0x63, 0xd8, 0xf3, 0x7f, 0x51, 0x81, 0x99, 0x44, 0xb6, 0x0e, 0xcd, 0xc2, 0x88, 0xc9, + 0x2f, 0x29, 0xe5, 0xeb, 0x20, 0x28, 0x8d, 0xac, 0x2e, 0xe3, 0x11, 0xb3, 0xa9, 0x3a, 0x92, 0x91, + 0xd3, 0x73, 0x24, 0xb2, 0xe8, 0x41, 0xfe, 0xb8, 0x45, 0x0f, 0xc2, 0xbb, 0x83, 0xe2, 0xee, 0x5d, + 0xca, 0xcd, 0xf0, 0xf0, 0xbe, 0x21, 0x56, 0xf0, 0x8f, 0x55, 0x85, 0xe1, 0x16, 0x94, 0xf4, 0x8e, + 0xc9, 0xef, 0x15, 0x17, 0xfb, 0xbe, 0xef, 0x53, 0x6b, 0xac, 0xf2, 0x4b, 0xc5, 0x92, 0x48, 0xf2, + 0x46, 0xf1, 0x58, 0xb6, 0x37, 0x8a, 0xd5, 0x60, 0xa0, 0xf4, 0xc8, 0x60, 0xe0, 0x0a, 0x14, 0x75, + 0xc3, 0x37, 0xef, 0x12, 0x61, 0xc7, 0x32, 0xc4, 0xa8, 0xb1, 0x56, 0x2c, 0xa0, 0xa2, 0x6e, 0xb0, + 0x1f, 0x84, 0xbc, 0x90, 0xa8, 0x1b, 0x1c, 0x80, 0xb0, 0x8a, 0xc7, 0x7c, 0x2d, 0x53, 0x9a, 0xe8, + 0xad, 0xe6, 0xd0, 0xd7, 0xaa, 0x40, 0x1c, 0xc5, 0x45, 0x35, 0x98, 0xe2, 0x0d, 0xb7, 0x3b, 0x96, + 0xa3, 0x37, 0x69, 0xf7, 0xf1, 0xa8, 0x56, 0xac, 0x44, 0xc1, 0x38, 0x8e, 0xdf, 0xc3, 0x5d, 0x4f, + 0x0c, 0xee, 0xae, 0x27, 0xb3, 0x71, 0xd7, 0x71, 0x8b, 0xec, 0xc3, 0x5d, 0xbf, 0x1f, 0x2f, 0x31, + 0xc0, 0x4f, 0x69, 0x0e, 0xea, 0x5a, 0xa9, 0x79, 0x35, 0xd5, 0x22, 0x02, 0xc7, 0x2a, 0x2d, 0xf0, + 0x59, 0x98, 0x70, 0xdc, 0x96, 0x6e, 0x9b, 0x0f, 0x98, 0xc3, 0xf1, 0xd8, 0x69, 0xcd, 0x32, 0xd7, + 0xd6, 0x5b, 0x2a, 0x00, 0x47, 0xf1, 0xd0, 0x03, 0x28, 0xb7, 0x02, 0x2f, 0x5b, 0x9d, 0xc9, 0xc4, + 0xcf, 0x44, 0xbd, 0x36, 0xbf, 0x1e, 0x24, 0xdb, 0x70, 0xc8, 0x4e, 0x99, 0x95, 0xd0, 0xe3, 0x32, + 0x2b, 0xbd, 0x5f, 0x62, 0x6e, 0x3c, 0xba, 0xcd, 0x71, 0x46, 0x31, 0xdf, 0xe7, 0xa0, 0x2c, 0x22, + 0x02, 0x31, 0x77, 0x95, 0xeb, 0x9f, 0x12, 0xaa, 0x72, 0x2e, 0x51, 0x94, 0x63, 0x75, 0x19, 0x87, + 0xd8, 0xc7, 0x0c, 0x00, 0x23, 0x35, 0x1d, 0x0a, 0xd9, 0xd5, 0x74, 0xd0, 0xe0, 0x49, 0x7e, 0xff, + 0x56, 0xd3, 0xd6, 0x58, 0x80, 0x62, 0x1a, 0xfc, 0xfa, 0x2d, 0x2f, 0x23, 0x78, 0x51, 0x3c, 0xc4, + 0x93, 0xd7, 0xd2, 0x90, 0x70, 0x7a, 0x5f, 0xe1, 0xe9, 0x2c, 0x5d, 0x7a, 0xba, 0x62, 0xc2, 0xd3, + 0x85, 0x40, 0x1c, 0xc5, 0xed, 0xe1, 0xa6, 0x4a, 0x83, 0xbb, 0xa9, 0x72, 0x56, 0x6e, 0x2a, 0xaa, + 0x71, 0x27, 0x8c, 0x2a, 0xe1, 0xc8, 0xa8, 0xf2, 0x0e, 0x54, 0x3c, 0xf6, 0x26, 0xf9, 0x0b, 0xaf, + 0xf4, 0xfd, 0xc2, 0xb5, 0xb0, 0x37, 0x56, 0x49, 0x29, 0x86, 0x3e, 0x7e, 0x8a, 0x85, 0x22, 0xe6, + 0xa1, 0xd8, 0x72, 0x9d, 0x6e, 0x87, 0xdf, 0x19, 0x10, 0x4a, 0xbe, 0xc2, 0x5a, 0xb0, 0x80, 0x0c, + 0xe6, 0x0c, 0xbe, 0x5f, 0x86, 0xa9, 0xd8, 0x3e, 0x63, 0x6a, 0x9e, 0x29, 0x77, 0xc6, 0x79, 0xa6, + 0xcb, 0x50, 0xf0, 0x69, 0xd0, 0x30, 0x12, 0xbd, 0x95, 0xce, 0xa2, 0x05, 0x06, 0x49, 0x16, 0xbf, + 0xc8, 0x1f, 0xbf, 0xf8, 0x05, 0xfa, 0x2f, 0x50, 0xd6, 0x9b, 0x4d, 0x97, 0x78, 0x1e, 0x09, 0xca, + 0xf2, 0x30, 0x9f, 0x5f, 0x0b, 0x1a, 0x71, 0x08, 0x67, 0x0b, 0xd5, 0xe6, 0x8e, 0x77, 0xdb, 0x13, + 0xd9, 0x23, 0x75, 0xa1, 0xba, 0x7c, 0x5d, 0xa3, 0xed, 0x58, 0x62, 0xa0, 0x26, 0x4c, 0xed, 0xb9, + 0xdb, 0x4b, 0x4b, 0xba, 0xb1, 0x4b, 0x4e, 0x92, 0x71, 0x60, 0xe5, 0x76, 0x6f, 0x46, 0x29, 0xe0, + 0x38, 0x49, 0xc1, 0xe5, 0x26, 0x39, 0xf0, 0xf5, 0xed, 0x93, 0xc4, 0x84, 0x01, 0x17, 0x95, 0x02, + 0x8e, 0x93, 0xa4, 0x11, 0xdc, 0x9e, 0xbb, 0x1d, 0xdc, 0x68, 0x17, 0xe5, 0xbd, 0x64, 0x04, 0x77, + 0x33, 0x04, 0x61, 0x15, 0x8f, 0x0e, 0xd8, 0x9e, 0xbb, 0x8d, 0x89, 0x6e, 0xb5, 0x45, 0x85, 0x42, + 0x39, 0x60, 0x37, 0x45, 0x3b, 0x96, 0x18, 0xa8, 0x03, 0x88, 0x3e, 0x1d, 0x7b, 0xef, 0xf2, 0x4a, + 0xae, 0x58, 0xf4, 0x3d, 0x97, 0xf6, 0x34, 0x12, 0x49, 0x7d, 0xa0, 0x0b, 0xd4, 0xdd, 0xdd, 0x4c, + 0xd0, 0xc1, 0x29, 0xb4, 0xd1, 0x5b, 0xf0, 0xd4, 0x9e, 0xbb, 0x2d, 0xd2, 0xfe, 0x0d, 0xd7, 0xb4, + 0x0d, 0xb3, 0xa3, 0xf3, 0x1a, 0x01, 0x95, 0x68, 0x41, 0xc5, 0x9b, 0xe9, 0x68, 0xb8, 0x57, 0xff, + 0x68, 0xd2, 0x73, 0x3c, 0x93, 0xa4, 0x67, 0xcc, 0x5c, 0x4f, 0x94, 0xf4, 0x9c, 0x78, 0x5c, 0x82, + 0x95, 0x1f, 0xe5, 0x00, 0xb1, 0x13, 0x56, 0xc1, 0x67, 0x45, 0x98, 0xf3, 0x43, 0x8b, 0x50, 0x66, + 0xde, 0x4f, 0xb9, 0xf4, 0x2a, 0xb3, 0x07, 0x2b, 0x01, 0x00, 0x87, 0x38, 0x74, 0x8d, 0xe2, 0x58, + 0x4d, 0x22, 0x2b, 0x55, 0xc8, 0x35, 0xca, 0x2d, 0xd6, 0x8a, 0x05, 0x14, 0xad, 0xc0, 0x8c, 0x4b, + 0xb6, 0x75, 0x4b, 0xb7, 0x0d, 0xa2, 0xf9, 0xae, 0xee, 0x93, 0xd6, 0x81, 0xf0, 0x24, 0xf2, 0x18, + 0x2b, 0x8e, 0x23, 0xe0, 0x64, 0x9f, 0xf9, 0xbf, 0x2b, 0xc1, 0x74, 0xfc, 0x68, 0xd8, 0xa3, 0x72, + 0xb5, 0x8b, 0x50, 0xee, 0xe8, 0xae, 0x6f, 0x2a, 0x75, 0x3c, 0xe4, 0x53, 0x35, 0x02, 0x00, 0x0e, + 0x71, 0xe8, 0xb2, 0x9f, 0xd5, 0x7b, 0x15, 0x12, 0xca, 0x65, 0x3f, 0xab, 0x07, 0x8b, 0x39, 0x2c, + 0xbd, 0x38, 0x44, 0xe1, 0xd4, 0x8a, 0x43, 0x7c, 0x22, 0x0a, 0xc8, 0x7e, 0x90, 0x4c, 0x93, 0xbd, + 0x93, 0xf1, 0xb9, 0xbf, 0xfe, 0x96, 0x5d, 0x13, 0x86, 0xaa, 0xcf, 0xa2, 0x18, 0xc6, 0x66, 0x16, + 0x22, 0x45, 0x0c, 0x85, 0xaf, 0x9e, 0x22, 0x4d, 0x38, 0xca, 0x1a, 0x35, 0xe0, 0xbc, 0x65, 0xb6, + 0x45, 0xc2, 0xcf, 0x6b, 0x10, 0x97, 0x97, 0x59, 0x66, 0x8e, 0x3a, 0x1f, 0x26, 0x42, 0xd6, 0x52, + 0x70, 0x70, 0x6a, 0x4f, 0xf4, 0x3c, 0x8c, 0xdd, 0x25, 0x2e, 0xbb, 0xbc, 0x0f, 0xd1, 0xd2, 0xef, + 0x6f, 0xf0, 0x66, 0x1c, 0xc0, 0xd1, 0x5b, 0x50, 0xf0, 0x74, 0xcf, 0x12, 0x81, 0xda, 0x09, 0x8e, + 0x32, 0xd7, 0xb4, 0x35, 0xa1, 0x1e, 0x2c, 0x45, 0x4b, 0x7f, 0x63, 0x46, 0xf2, 0x8c, 0x02, 0xb6, + 0x70, 0xbb, 0x65, 0xe2, 0xa8, 0xed, 0x96, 0xc1, 0x9c, 0xe2, 0x0f, 0x8a, 0x30, 0x15, 0x3b, 0xeb, + 0xf9, 0x28, 0xd7, 0x22, 0x3d, 0xc5, 0xc8, 0x11, 0x9e, 0xe2, 0x05, 0x28, 0x19, 0x96, 0x49, 0x6c, + 0x7f, 0xb5, 0x29, 0x3c, 0x4a, 0x78, 0xa5, 0x9c, 0xb7, 0x2f, 0x63, 0x89, 0x71, 0xd6, 0x7e, 0x45, + 0x75, 0x00, 0xa3, 0xc7, 0x2d, 0x3a, 0x53, 0x1c, 0xe6, 0x57, 0x84, 0xb2, 0xb9, 0xda, 0x1e, 0x7b, + 0xb1, 0x9f, 0xf8, 0x6a, 0xd4, 0xc1, 0x26, 0x4b, 0x39, 0xeb, 0x4d, 0x96, 0xc1, 0x6c, 0xe4, 0xaf, + 0x46, 0xa0, 0xb4, 0x51, 0xdb, 0xd2, 0x58, 0x95, 0xe6, 0xb7, 0xa3, 0x75, 0xa8, 0x07, 0x11, 0x32, + 0x59, 0x70, 0xfa, 0x3a, 0x35, 0xad, 0xbe, 0x6b, 0x4d, 0x97, 0xb9, 0xf5, 0xd1, 0x75, 0x26, 0xef, + 0x8e, 0x96, 0xa0, 0x60, 0xef, 0xf5, 0xfb, 0x31, 0x0e, 0x36, 0x66, 0x1b, 0x37, 0xc9, 0x01, 0x66, + 0x9d, 0xd1, 0x6d, 0x00, 0xc3, 0x25, 0x4d, 0x62, 0xfb, 0xa6, 0xf8, 0x16, 0x5a, 0x7f, 0xfb, 0x0b, + 0x4b, 0xb2, 0x33, 0x56, 0x08, 0xcd, 0xff, 0x41, 0x11, 0xa6, 0xe3, 0x67, 0xba, 0x1f, 0xe5, 0x72, + 0x9e, 0x87, 0x31, 0xaf, 0xcb, 0x0a, 0xdc, 0x08, 0xa7, 0x23, 0xa7, 0x01, 0x8d, 0x37, 0xe3, 0x00, + 0x9e, 0xee, 0x4a, 0xf2, 0x67, 0xe2, 0x4a, 0x0a, 0xc7, 0x75, 0x25, 0x59, 0x07, 0x34, 0x1f, 0x24, + 0xbf, 0x33, 0xf1, 0x4e, 0xc6, 0xa7, 0xf0, 0xfb, 0xf0, 0x25, 0x44, 0x58, 0xf5, 0x58, 0x26, 0xa5, + 0x61, 0x02, 0x43, 0x4c, 0xec, 0xa3, 0x9e, 0x8d, 0xcb, 0x9a, 0x83, 0x51, 0xf6, 0x5d, 0x05, 0xb1, + 0x18, 0x65, 0xa6, 0xc8, 0x8e, 0x54, 0x61, 0xde, 0x3e, 0x60, 0x19, 0xfc, 0x51, 0x98, 0x8c, 0x9e, + 0xe2, 0xa4, 0xeb, 0xe6, 0x5d, 0xc7, 0xf3, 0x45, 0x36, 0x21, 0xfe, 0xc5, 0xc4, 0x1b, 0x21, 0x08, + 0xab, 0x78, 0xc7, 0x9b, 0xb4, 0x9f, 0x87, 0x31, 0x51, 0xac, 0x4e, 0xcc, 0xd9, 0xd2, 0xcc, 0x44, + 0x41, 0x3b, 0x1c, 0xc0, 0xff, 0x63, 0xc6, 0xb6, 0x3c, 0xf4, 0xad, 0xe4, 0x8c, 0xfd, 0x76, 0xa6, + 0x47, 0x76, 0x3f, 0xe9, 0x13, 0xf6, 0x60, 0xca, 0xfd, 0x16, 0xcc, 0x24, 0x76, 0x77, 0x8e, 0x57, + 0x55, 0x7c, 0x0e, 0x46, 0x6d, 0xbd, 0x4d, 0x78, 0xbd, 0x2c, 0x61, 0x74, 0xec, 0xc3, 0x13, 0x98, + 0xb7, 0xcf, 0xff, 0xb0, 0x08, 0x33, 0x89, 0xab, 0x29, 0x6c, 0x4d, 0x2c, 0x77, 0x08, 0x62, 0x2b, + 0xfd, 0xd4, 0x7d, 0x81, 0xd7, 0x60, 0x92, 0x19, 0x46, 0x23, 0xb6, 0xaf, 0x20, 0x77, 0xb9, 0xb7, + 0x22, 0x50, 0x1c, 0xc3, 0x3e, 0xde, 0x9a, 0xfa, 0x35, 0x98, 0x54, 0xbf, 0x94, 0xb2, 0xba, 0x2c, + 0xf6, 0x8d, 0x25, 0x13, 0x2d, 0x02, 0xc5, 0x31, 0x6c, 0xf6, 0x99, 0x19, 0x39, 0xbb, 0x8a, 0x7c, + 0xdd, 0x68, 0xff, 0x9f, 0x99, 0x89, 0x91, 0xc0, 0x09, 0xa2, 0x68, 0x1b, 0x66, 0x79, 0x7e, 0x5f, + 0x15, 0x28, 0x76, 0xe6, 0x64, 0x5e, 0x08, 0x3d, 0xbb, 0xdc, 0x13, 0x13, 0x1f, 0x41, 0xa5, 0xcf, + 0xf2, 0x8f, 0x1f, 0x26, 0x3f, 0xbc, 0xf9, 0x6e, 0xd6, 0x17, 0x9a, 0x4e, 0x64, 0x83, 0xe5, 0xc7, + 0xc5, 0x06, 0x7f, 0x58, 0xa1, 0x86, 0x12, 0x3b, 0x9b, 0x8f, 0xe6, 0xa1, 0xc8, 0x74, 0x93, 0x4e, + 0x2f, 0x72, 0xab, 0x80, 0x29, 0xad, 0x87, 0x05, 0xe4, 0x18, 0x59, 0x74, 0x11, 0xd3, 0xe5, 0x7b, + 0xc4, 0x74, 0x1d, 0x38, 0xe7, 0x5b, 0xde, 0x96, 0xdb, 0xf5, 0xfc, 0x25, 0xe2, 0xfa, 0x9e, 0x50, + 0xdd, 0x42, 0xdf, 0x5f, 0xab, 0xdb, 0x5a, 0xd3, 0xe2, 0x54, 0x70, 0x1a, 0x69, 0xaa, 0xc0, 0xbe, + 0xe5, 0xd5, 0x2c, 0xcb, 0xb9, 0x17, 0x1c, 0x3d, 0x08, 0x27, 0x1b, 0x31, 0x8d, 0x48, 0x05, 0xde, + 0x5a, 0xd3, 0x7a, 0x60, 0xe2, 0x23, 0xa8, 0xa0, 0x75, 0xf6, 0x54, 0x6f, 0xe8, 0x96, 0xd9, 0xd4, + 0x7d, 0x42, 0xa7, 0x63, 0x96, 0xde, 0xe6, 0xd6, 0x21, 0xf7, 0x23, 0xb7, 0xd6, 0xb4, 0x38, 0x0a, + 0x4e, 0xeb, 0x37, 0xac, 0x2f, 0xd6, 0xa6, 0xce, 0xde, 0xa5, 0x33, 0x99, 0xbd, 0xcb, 0xfd, 0x59, + 0x39, 0x64, 0x64, 0xe5, 0x31, 0x95, 0xef, 0xc3, 0xca, 0x9b, 0x30, 0x25, 0x3f, 0xe5, 0x23, 0x74, + 0xb6, 0xd2, 0xf7, 0xf6, 0x48, 0x2d, 0x4a, 0x01, 0xc7, 0x49, 0x9e, 0x51, 0xca, 0xe9, 0x8f, 0x72, + 0x30, 0x4d, 0x25, 0xa9, 0xf9, 0xbb, 0xc4, 0x7e, 0xd0, 0xd0, 0x5d, 0xbd, 0x1d, 0x94, 0x18, 0xdb, + 0xc9, 0x7c, 0xc8, 0x6b, 0x31, 0x46, 0x7c, 0xe8, 0x65, 0xdd, 0xe7, 0x38, 0x18, 0x27, 0x24, 0xa3, + 0x53, 0x5f, 0xd8, 0x76, 0x92, 0xcf, 0xce, 0x9e, 0x8f, 0x32, 0x0a, 0xa6, 0xbe, 0x38, 0xd1, 0x81, + 0x7c, 0xec, 0xec, 0x12, 0x3c, 0x99, 0xfa, 0xa8, 0x7d, 0x39, 0xea, 0x6f, 0x16, 0xc5, 0xfd, 0x9a, + 0x0c, 0xd6, 0x02, 0x59, 0x7f, 0x17, 0x8a, 0x06, 0x56, 0xb6, 0xfc, 0x6e, 0x58, 0xec, 0x7b, 0x72, + 0xe1, 0x97, 0xc2, 0x42, 0x1c, 0x34, 0x0b, 0x23, 0xcd, 0x6d, 0xe6, 0xea, 0x47, 0xc3, 0x83, 0x7e, + 0xcb, 0x75, 0x3c, 0xd2, 0xdc, 0x46, 0xcf, 0x41, 0x49, 0x2c, 0x32, 0x82, 0x73, 0x70, 0x8c, 0xad, + 0x58, 0x81, 0x78, 0x58, 0x42, 0x87, 0x15, 0xd6, 0x0f, 0x21, 0xc1, 0x1f, 0x7f, 0x73, 0x9f, 0xf8, + 0x4c, 0x5c, 0x7f, 0x1e, 0xfa, 0x05, 0xa5, 0xaa, 0x39, 0x44, 0x93, 0xbd, 0xc9, 0x92, 0xe5, 0x83, + 0x05, 0x2c, 0x7f, 0x5a, 0x84, 0x0b, 0xe9, 0xb7, 0xbe, 0x3e, 0x31, 0xd6, 0xc0, 0x95, 0x3b, 0x9f, + 0xaa, 0xdc, 0x9f, 0x86, 0x31, 0x8f, 0x09, 0x1e, 0x1c, 0x0d, 0xe0, 0xf5, 0x66, 0x79, 0x13, 0x0e, + 0x60, 0xe8, 0x75, 0x40, 0x6d, 0xfd, 0xfe, 0xba, 0xd7, 0x5a, 0x72, 0xba, 0xac, 0x84, 0x36, 0x26, + 0x3a, 0xaf, 0xef, 0x3e, 0x1a, 0x1e, 0xc0, 0x59, 0x4f, 0x60, 0xe0, 0x94, 0x5e, 0xec, 0x30, 0x43, + 0x64, 0x83, 0x28, 0x76, 0x12, 0xe8, 0xc8, 0x1d, 0x9d, 0x21, 0xc5, 0x1f, 0x1f, 0x27, 0x03, 0x77, + 0x63, 0x28, 0x57, 0x01, 0x3f, 0xe9, 0xd1, 0xfb, 0x69, 0x9a, 0xce, 0xcf, 0x0a, 0x70, 0x2e, 0xa5, + 0x14, 0x4c, 0xd4, 0x7b, 0xe7, 0x8e, 0xe1, 0xbd, 0xf7, 0xe5, 0x48, 0x65, 0x73, 0x12, 0x3b, 0x10, + 0xea, 0x88, 0x61, 0xfa, 0x30, 0x07, 0xe7, 0xd9, 0x0e, 0x7c, 0xb0, 0xed, 0x17, 0xd4, 0x00, 0xce, + 0x0b, 0xcd, 0x3c, 0x56, 0x31, 0xee, 0x95, 0x14, 0x0a, 0xe1, 0xb6, 0x64, 0x1a, 0x14, 0xa7, 0x72, + 0x45, 0x4b, 0x00, 0xf2, 0x2e, 0x5d, 0x60, 0xc9, 0xcf, 0xb2, 0x92, 0xe2, 0xb2, 0xf5, 0xdf, 0xd8, + 0xee, 0xbe, 0x32, 0xda, 0x6c, 0x65, 0xa4, 0x74, 0x1b, 0xc6, 0x87, 0x57, 0x52, 0x5e, 0xef, 0xf1, + 0x2d, 0x60, 0x30, 0xed, 0xfa, 0xc3, 0x3c, 0x4c, 0x46, 0x5f, 0x24, 0xba, 0x02, 0xc5, 0x8e, 0x4b, + 0x76, 0xcc, 0xfb, 0xf1, 0xef, 0x6f, 0x34, 0x58, 0x2b, 0x16, 0x50, 0xe4, 0x40, 0xd1, 0xd2, 0xb7, + 0xe9, 0x7c, 0xcf, 0xeb, 0x9f, 0xaf, 0x0c, 0x5c, 0xcb, 0x3b, 0xd8, 0x86, 0x08, 0x18, 0xae, 0x31, + 0xf2, 0x58, 0xb0, 0xa1, 0x0c, 0x77, 0x4c, 0x62, 0x35, 0xf9, 0x79, 0xcf, 0x61, 0x30, 0xbc, 0xce, + 0xc8, 0x63, 0xc1, 0x06, 0xbd, 0x0d, 0x65, 0xfe, 0xd1, 0x92, 0x66, 0xfd, 0x40, 0xac, 0x70, 0xff, + 0xf3, 0xf1, 0x54, 0x76, 0xcb, 0x6c, 0x93, 0xd0, 0x1c, 0x97, 0x02, 0x22, 0x38, 0xa4, 0xc7, 0x3e, + 0x7a, 0xbf, 0xe3, 0x13, 0x57, 0xf3, 0x75, 0x37, 0xf8, 0x26, 0x7d, 0xf8, 0xd1, 0x7b, 0x09, 0xc1, + 0x0a, 0xd6, 0xfc, 0x9f, 0x8c, 0xc1, 0x54, 0xec, 0x9e, 0xed, 0xaf, 0xc6, 0x25, 0x52, 0xf5, 0x03, + 0x2b, 0xf9, 0xac, 0x3f, 0xb0, 0x52, 0xc8, 0x22, 0x3c, 0x78, 0x1b, 0xc6, 0x3d, 0x6f, 0x97, 0x61, + 0xf6, 0x9f, 0xab, 0x9b, 0x3e, 0x7c, 0x38, 0x37, 0xae, 0x69, 0x37, 0x64, 0x77, 0x1c, 0x21, 0x86, + 0xd6, 0x60, 0x4c, 0x1c, 0x2e, 0xec, 0xef, 0x64, 0x20, 0x0b, 0x43, 0x82, 0xf0, 0x28, 0x20, 0x31, + 0x8c, 0x2d, 0xe9, 0x98, 0xd2, 0x7d, 0xe2, 0x03, 0xe1, 0x06, 0x9c, 0xef, 0x38, 0x96, 0x15, 0x9c, + 0xee, 0x94, 0x9f, 0x46, 0x2a, 0x47, 0xef, 0xf6, 0x34, 0x52, 0x70, 0x70, 0x6a, 0xcf, 0xc1, 0xbc, + 0xec, 0x3f, 0x16, 0x61, 0x32, 0x5a, 0x86, 0xea, 0xec, 0x6e, 0x58, 0xb2, 0x44, 0x60, 0xcd, 0xb5, + 0xe3, 0x37, 0x2c, 0xb7, 0x44, 0x3b, 0x96, 0x18, 0x08, 0x43, 0x99, 0x9f, 0x78, 0xbf, 0xd9, 0xef, + 0xa6, 0x34, 0x3f, 0x3a, 0x1b, 0xf4, 0xc5, 0x21, 0x19, 0x4a, 0xd3, 0x0b, 0xd0, 0xfb, 0xb3, 0x4c, + 0x46, 0x53, 0x36, 0xe3, 0x90, 0x0c, 0x9d, 0xb1, 0x5c, 0xd2, 0x0a, 0xb2, 0x81, 0xca, 0x8c, 0x85, + 0x59, 0x2b, 0x16, 0x50, 0xf4, 0x3c, 0x8c, 0xb9, 0x8e, 0x45, 0x6a, 0x78, 0x43, 0x44, 0xd3, 0x72, + 0xa3, 0x0c, 0xf3, 0x66, 0x1c, 0xc0, 0x87, 0xb1, 0x49, 0x14, 0x55, 0x80, 0x3e, 0x4c, 0x68, 0x05, + 0x66, 0xee, 0x8a, 0x0c, 0xa3, 0x66, 0xb6, 0x6c, 0xdd, 0x0f, 0x2f, 0x65, 0xc9, 0x13, 0x89, 0x6f, + 0xc4, 0x11, 0x70, 0xb2, 0xcf, 0xd9, 0xc5, 0xca, 0xc4, 0x6e, 0x76, 0x1c, 0xd3, 0xf6, 0xe3, 0xb1, + 0xf2, 0x35, 0xd1, 0x8e, 0x25, 0xc6, 0x60, 0x76, 0xf6, 0x97, 0x63, 0x30, 0x19, 0x2d, 0xb3, 0x16, + 0xd5, 0xe1, 0xdc, 0x10, 0x74, 0x78, 0x24, 0x6b, 0x1d, 0xce, 0x1f, 0xa9, 0xc3, 0xcf, 0x06, 0x3b, + 0xd7, 0x85, 0xe8, 0xe6, 0x94, 0xba, 0x7b, 0x8d, 0x6a, 0x74, 0x86, 0x37, 0x7d, 0x1a, 0x85, 0xf0, + 0x13, 0x79, 0xfc, 0xb0, 0x42, 0x5e, 0x9d, 0x91, 0x23, 0x60, 0x1c, 0xc7, 0xef, 0xc7, 0x56, 0xfa, + 0xdb, 0xfd, 0x79, 0x0d, 0x26, 0x99, 0x90, 0x35, 0xc3, 0xa0, 0xeb, 0xdd, 0xd5, 0xa6, 0x38, 0x44, + 0x2e, 0x37, 0xce, 0x36, 0x55, 0xe8, 0x32, 0x8e, 0x61, 0x47, 0x2d, 0xb3, 0x9c, 0x8d, 0x65, 0x6e, + 0x9e, 0xd0, 0x32, 0x2f, 0x42, 0xbe, 0x69, 0xed, 0x33, 0xad, 0x2e, 0x85, 0x7b, 0x25, 0xcb, 0x6b, + 0x9b, 0x98, 0xb6, 0x2b, 0xf6, 0x56, 0x39, 0x23, 0x7b, 0x1b, 0x7f, 0x94, 0xbd, 0xb1, 0xb8, 0x86, + 0x7f, 0x41, 0x89, 0x5f, 0x98, 0x99, 0xe8, 0x3f, 0xae, 0x51, 0xba, 0xe3, 0x08, 0xb1, 0xc1, 0x8c, + 0xf9, 0x6b, 0x50, 0x0a, 0x18, 0xd1, 0x81, 0x96, 0xfd, 0xc2, 0x81, 0xa6, 0x26, 0xc4, 0x88, 0x2c, + 0x42, 0xd9, 0xe9, 0x90, 0xc8, 0xe7, 0x0f, 0x65, 0x0c, 0x7c, 0x2b, 0x00, 0xe0, 0x10, 0x87, 0x5a, + 0x11, 0xe7, 0x1a, 0xdb, 0xe2, 0x7d, 0x83, 0x36, 0x0a, 0x21, 0xe6, 0xbf, 0x9e, 0x83, 0xe0, 0x9b, + 0x42, 0x68, 0x19, 0x46, 0x3b, 0x8e, 0xeb, 0xf3, 0xad, 0xb5, 0xca, 0xd5, 0xb9, 0xf4, 0xf1, 0xe1, + 0xc7, 0xff, 0x1d, 0xd7, 0x0f, 0x29, 0xd2, 0x5f, 0x1e, 0xe6, 0x9d, 0xa9, 0x9c, 0x86, 0xd5, 0xf5, + 0x7c, 0xe2, 0xae, 0x36, 0xe2, 0x72, 0x2e, 0x05, 0x00, 0x1c, 0xe2, 0xcc, 0xff, 0x4b, 0x01, 0xa6, + 0xe3, 0x95, 0xf7, 0xd0, 0xbb, 0x30, 0xe1, 0x99, 0x2d, 0xdb, 0xb4, 0x5b, 0x22, 0x16, 0xcd, 0xf5, + 0x7d, 0xf7, 0x57, 0x53, 0xfb, 0xe3, 0x28, 0xb9, 0xcc, 0x8e, 0xb3, 0x9d, 0xcd, 0x07, 0xf8, 0x3f, + 0x48, 0x16, 0x99, 0x79, 0x27, 0xe3, 0xda, 0x87, 0xbf, 0xda, 0x55, 0x66, 0x7e, 0x39, 0x0a, 0x17, + 0xd2, 0x6b, 0x2b, 0x9e, 0x51, 0xd0, 0x1a, 0xde, 0xf3, 0x1c, 0xe9, 0x79, 0xcf, 0x33, 0x1c, 0xe7, + 0x7c, 0x46, 0xb5, 0x12, 0xe5, 0x00, 0x1c, 0xed, 0x6a, 0x65, 0x38, 0x5d, 0x78, 0x64, 0x38, 0x7d, + 0x05, 0x8a, 0xa2, 0xae, 0x7e, 0x2c, 0x4c, 0xad, 0xf3, 0xaa, 0xf7, 0x02, 0xaa, 0x84, 0x02, 0xc5, + 0x23, 0x43, 0x01, 0x1a, 0xda, 0x04, 0xfb, 0x8f, 0xfd, 0xdd, 0xf5, 0xe2, 0xa1, 0x4d, 0xd0, 0x17, + 0x87, 0x64, 0xd8, 0x4d, 0xfe, 0x8e, 0x79, 0x1b, 0xaf, 0x89, 0x59, 0x39, 0xbc, 0xc9, 0xdf, 0x58, + 0xbd, 0x8d, 0xd7, 0xb0, 0x80, 0x46, 0x53, 0xc1, 0xe5, 0x4c, 0x52, 0xc1, 0xe9, 0x3a, 0x77, 0x5a, + 0x89, 0x30, 0x03, 0x66, 0x12, 0xef, 0xfc, 0xd8, 0xa9, 0xb0, 0x2b, 0x50, 0xf4, 0xba, 0x3b, 0x14, + 0x2f, 0x56, 0x62, 0x49, 0x63, 0xad, 0x58, 0x40, 0xe7, 0xbf, 0x5b, 0xa0, 0x5c, 0x62, 0x55, 0x38, + 0xcf, 0xc8, 0xaa, 0x5e, 0x85, 0x09, 0x9e, 0x8c, 0x7a, 0x53, 0xa9, 0xcf, 0x51, 0x52, 0x36, 0x18, + 0x54, 0x20, 0x8e, 0xe2, 0xa2, 0x55, 0xa6, 0x26, 0x7d, 0x2f, 0x0b, 0x41, 0x68, 0x12, 0x9d, 0xb8, + 0x05, 0x01, 0xf4, 0x12, 0x54, 0xd8, 0x43, 0xf0, 0x21, 0x17, 0x59, 0x59, 0x76, 0x13, 0xf7, 0x5a, + 0xd8, 0x8c, 0x55, 0x9c, 0xe8, 0xd1, 0x82, 0xd1, 0x4c, 0x8e, 0x16, 0x24, 0xde, 0xca, 0x69, 0xe9, + 0xdd, 0xb7, 0x4b, 0x20, 0xbf, 0x94, 0x88, 0x8c, 0xc4, 0xf7, 0x2a, 0x3f, 0xd7, 0xf7, 0xe6, 0x4d, + 0x20, 0x0a, 0xcf, 0x64, 0xa5, 0x4c, 0x49, 0xaf, 0x03, 0x12, 0x1f, 0x48, 0x14, 0x41, 0xb5, 0x52, + 0x6f, 0x49, 0xee, 0x52, 0x69, 0x09, 0x0c, 0x9c, 0xd2, 0x0b, 0xbd, 0xce, 0xbe, 0xce, 0xea, 0xeb, + 0xa6, 0x2d, 0x3d, 0xef, 0xc5, 0x1e, 0x17, 0x34, 0x39, 0x92, 0xfc, 0xce, 0x2a, 0xff, 0x89, 0xc3, + 0xee, 0xe8, 0x1a, 0x8c, 0xdd, 0x75, 0xac, 0x6e, 0x5b, 0xa4, 0xe6, 0x2b, 0x57, 0x67, 0xd3, 0x28, + 0xbd, 0xc1, 0x50, 0x94, 0x0b, 0x45, 0xbc, 0x0b, 0x0e, 0xfa, 0x22, 0x02, 0x53, 0xec, 0x78, 0x8f, + 0xe9, 0x1f, 0x08, 0x03, 0x10, 0x53, 0xef, 0x95, 0x34, 0x72, 0x0d, 0xa7, 0xa9, 0x45, 0xb1, 0xf9, + 0x49, 0x8f, 0x58, 0x23, 0x8e, 0xd3, 0x44, 0xd7, 0xa1, 0xa4, 0xef, 0xec, 0x98, 0xb6, 0xe9, 0x1f, + 0x88, 0x9c, 0xdd, 0x33, 0x69, 0xf4, 0x6b, 0x02, 0x47, 0x14, 0x72, 0x11, 0xbf, 0xb0, 0xec, 0x8b, + 0x6e, 0x43, 0xc5, 0x77, 0x2c, 0x11, 0x97, 0x7a, 0x22, 0xd5, 0x70, 0x29, 0x8d, 0xd4, 0x96, 0x44, + 0x0b, 0xb7, 0x47, 0xc3, 0x36, 0x0f, 0xab, 0x74, 0xd0, 0xff, 0xcf, 0xc1, 0xb8, 0xed, 0x34, 0x49, + 0x60, 0x7a, 0x62, 0xbb, 0xee, 0xad, 0x8c, 0xbe, 0xf0, 0xb9, 0xb0, 0xa1, 0xd0, 0xe6, 0x16, 0x22, + 0x0b, 0x7c, 0xa8, 0x20, 0x1c, 0x11, 0x02, 0xd9, 0x30, 0x6d, 0xb6, 0xf5, 0x16, 0x69, 0x74, 0x2d, + 0x71, 0x3c, 0xd1, 0x13, 0x93, 0x47, 0xea, 0xb5, 0xde, 0x35, 0xc7, 0xd0, 0x2d, 0xfe, 0x85, 0x5c, + 0x4c, 0x76, 0x88, 0xcb, 0x3e, 0xd4, 0x2b, 0x4f, 0x9a, 0xac, 0xc6, 0x28, 0xe1, 0x04, 0x6d, 0xb4, + 0x02, 0x33, 0x1d, 0xd7, 0x74, 0xd8, 0x7b, 0xb3, 0x74, 0x8f, 0x7f, 0x21, 0x15, 0xa2, 0x77, 0x39, + 0x1b, 0x71, 0x04, 0x9c, 0xec, 0xc3, 0xeb, 0x0f, 0xf0, 0x46, 0xb6, 0x96, 0x1b, 0x0d, 0xea, 0x0f, + 0xf0, 0x36, 0x2c, 0xa1, 0xb3, 0x5f, 0x80, 0x99, 0xc4, 0xd8, 0xf4, 0xe5, 0x10, 0x7e, 0x33, 0x07, + 0xf1, 0x7c, 0x39, 0x5d, 0x37, 0x34, 0x4d, 0x97, 0x11, 0x3c, 0x88, 0xe7, 0xf8, 0x97, 0x03, 0x00, + 0x0e, 0x71, 0xd0, 0x65, 0x28, 0x74, 0x74, 0x7f, 0x37, 0x7e, 0xcc, 0x8f, 0x92, 0xc4, 0x0c, 0x82, + 0xae, 0x02, 0xd0, 0xbf, 0x98, 0xb4, 0xc8, 0xfd, 0x8e, 0x58, 0x06, 0xc9, 0xed, 0x87, 0x86, 0x84, + 0x60, 0x05, 0x6b, 0xfe, 0x6f, 0x47, 0x61, 0x32, 0x3a, 0xb7, 0x44, 0x16, 0x9b, 0xb9, 0x47, 0x2e, + 0x36, 0xaf, 0x40, 0xb1, 0x4d, 0xfc, 0x5d, 0xa7, 0x19, 0x9f, 0x27, 0xd7, 0x59, 0x2b, 0x16, 0x50, + 0x26, 0xbe, 0xe3, 0xfa, 0x42, 0xac, 0x50, 0x7c, 0xc7, 0xf5, 0x31, 0x83, 0x04, 0xa7, 0x14, 0x0b, + 0x3d, 0x4e, 0x29, 0xb6, 0x60, 0x9a, 0x57, 0x00, 0x5e, 0x22, 0xae, 0x7f, 0xe2, 0xd3, 0xb5, 0x5a, + 0x8c, 0x04, 0x4e, 0x10, 0x45, 0x4d, 0xea, 0x6d, 0x68, 0x5b, 0xb8, 0x33, 0xd0, 0xff, 0xdd, 0x7e, + 0x2d, 0x4a, 0x01, 0xc7, 0x49, 0x0e, 0x23, 0x1b, 0x19, 0x7d, 0x8f, 0x27, 0x2e, 0x9d, 0x58, 0xca, + 0xaa, 0x74, 0xe2, 0x2b, 0x30, 0xd9, 0xd6, 0xef, 0x37, 0xf4, 0x03, 0xcb, 0xd1, 0x9b, 0x9a, 0xf9, + 0x80, 0x88, 0xeb, 0xa7, 0xe8, 0xf0, 0xe1, 0xdc, 0xe4, 0x7a, 0x04, 0x82, 0x63, 0x98, 0x83, 0x4d, + 0xc0, 0xbf, 0x35, 0x02, 0x28, 0xf9, 0x65, 0x13, 0xf4, 0x51, 0x0e, 0x26, 0xef, 0x45, 0xc6, 0x68, + 0x38, 0xc1, 0x99, 0x4c, 0x7b, 0x45, 0xdb, 0x71, 0x8c, 0xb9, 0xb2, 0xc0, 0x19, 0x39, 0xbd, 0x85, + 0x64, 0xdd, 0xf8, 0xf1, 0x2f, 0x2e, 0x3d, 0xf1, 0x93, 0x5f, 0x5c, 0x7a, 0xe2, 0xa7, 0xbf, 0xb8, + 0xf4, 0xc4, 0xd7, 0x0f, 0x2f, 0xe5, 0x7e, 0x7c, 0x78, 0x29, 0xf7, 0x93, 0xc3, 0x4b, 0xb9, 0x9f, + 0x1e, 0x5e, 0xca, 0xfd, 0xfc, 0xf0, 0x52, 0xee, 0xbb, 0xff, 0x70, 0xe9, 0x89, 0x2f, 0x7e, 0x3e, + 0x14, 0x65, 0x31, 0x10, 0x85, 0xfd, 0xf3, 0x22, 0x67, 0xbd, 0xd8, 0xd9, 0x6b, 0x2d, 0x52, 0x51, + 0x16, 0x15, 0x51, 0x16, 0x03, 0x51, 0xfe, 0x3d, 0x00, 0x00, 0xff, 0xff, 0x8d, 0xbf, 0x8a, 0x35, + 0x25, 0xa6, 0x00, 0x00, } func (m *AMQPConsumeConfig) Marshal() (dAtA []byte, err error) { @@ -3220,7 +3222,9 @@ func (m *BitbucketServerEventSource) MarshalToSizedBuffer(dAtA []byte) (int, err copy(dAtA[i:], m.CheckInterval) i = encodeVarintGenerated(dAtA, i, uint64(len(m.CheckInterval))) i-- - dAtA[i] = 0x7a + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 if m.TLS != nil { { size, err := m.TLS.MarshalToSizedBuffer(dAtA[:i]) @@ -3231,7 +3235,7 @@ func (m *BitbucketServerEventSource) MarshalToSizedBuffer(dAtA []byte) (int, err i = encodeVarintGenerated(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x72 + dAtA[i] = 0x7a } if m.Filter != nil { { @@ -3243,7 +3247,7 @@ func (m *BitbucketServerEventSource) MarshalToSizedBuffer(dAtA []byte) (int, err i = encodeVarintGenerated(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x6a + dAtA[i] = 0x72 } if len(m.Metadata) > 0 { keysForMetadata := make([]string, 0, len(m.Metadata)) @@ -3266,7 +3270,7 @@ func (m *BitbucketServerEventSource) MarshalToSizedBuffer(dAtA []byte) (int, err dAtA[i] = 0xa i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) i-- - dAtA[i] = 0x62 + dAtA[i] = 0x6a } } i-- @@ -3276,12 +3280,12 @@ func (m *BitbucketServerEventSource) MarshalToSizedBuffer(dAtA []byte) (int, err dAtA[i] = 0 } i-- - dAtA[i] = 0x58 + dAtA[i] = 0x60 i -= len(m.BitbucketServerBaseURL) copy(dAtA[i:], m.BitbucketServerBaseURL) i = encodeVarintGenerated(dAtA, i, uint64(len(m.BitbucketServerBaseURL))) i-- - dAtA[i] = 0x52 + dAtA[i] = 0x5a if m.WebhookSecret != nil { { size, err := m.WebhookSecret.MarshalToSizedBuffer(dAtA[:i]) @@ -3292,7 +3296,7 @@ func (m *BitbucketServerEventSource) MarshalToSizedBuffer(dAtA []byte) (int, err i = encodeVarintGenerated(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x4a + dAtA[i] = 0x52 } if m.AccessToken != nil { { @@ -3304,9 +3308,17 @@ func (m *BitbucketServerEventSource) MarshalToSizedBuffer(dAtA []byte) (int, err i = encodeVarintGenerated(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x42 + dAtA[i] = 0x4a } i-- + if m.OneEventPerChange { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x40 + i-- if m.SkipBranchRefsChangedOnOpenPR { dAtA[i] = 1 } else { @@ -8560,6 +8572,7 @@ func (m *BitbucketServerEventSource) Size() (n int) { } } n += 2 + n += 2 if m.AccessToken != nil { l = m.AccessToken.Size() n += 1 + l + sovGenerated(uint64(l)) @@ -8588,7 +8601,7 @@ func (m *BitbucketServerEventSource) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } l = len(m.CheckInterval) - n += 1 + l + sovGenerated(uint64(l)) + n += 2 + l + sovGenerated(uint64(l)) return n } @@ -10522,6 +10535,7 @@ func (this *BitbucketServerEventSource) String() string { `Repositories:` + repeatedStringForRepositories + `,`, `Events:` + fmt.Sprintf("%v", this.Events) + `,`, `SkipBranchRefsChangedOnOpenPR:` + fmt.Sprintf("%v", this.SkipBranchRefsChangedOnOpenPR) + `,`, + `OneEventPerChange:` + fmt.Sprintf("%v", this.OneEventPerChange) + `,`, `AccessToken:` + strings.Replace(fmt.Sprintf("%v", this.AccessToken), "SecretKeySelector", "v1.SecretKeySelector", 1) + `,`, `WebhookSecret:` + strings.Replace(fmt.Sprintf("%v", this.WebhookSecret), "SecretKeySelector", "v1.SecretKeySelector", 1) + `,`, `BitbucketServerBaseURL:` + fmt.Sprintf("%v", this.BitbucketServerBaseURL) + `,`, @@ -15320,6 +15334,26 @@ func (m *BitbucketServerEventSource) Unmarshal(dAtA []byte) error { } m.SkipBranchRefsChangedOnOpenPR = bool(v != 0) case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OneEventPerChange", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.OneEventPerChange = bool(v != 0) + case 9: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field AccessToken", wireType) } @@ -15355,7 +15389,7 @@ func (m *BitbucketServerEventSource) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 9: + case 10: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field WebhookSecret", wireType) } @@ -15391,7 +15425,7 @@ func (m *BitbucketServerEventSource) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 10: + case 11: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field BitbucketServerBaseURL", wireType) } @@ -15423,7 +15457,7 @@ func (m *BitbucketServerEventSource) Unmarshal(dAtA []byte) error { } m.BitbucketServerBaseURL = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 11: + case 12: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field DeleteHookOnFinish", wireType) } @@ -15443,7 +15477,7 @@ func (m *BitbucketServerEventSource) Unmarshal(dAtA []byte) error { } } m.DeleteHookOnFinish = bool(v != 0) - case 12: + case 13: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) } @@ -15570,7 +15604,7 @@ func (m *BitbucketServerEventSource) Unmarshal(dAtA []byte) error { } m.Metadata[mapkey] = mapvalue iNdEx = postIndex - case 13: + case 14: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Filter", wireType) } @@ -15606,7 +15640,7 @@ func (m *BitbucketServerEventSource) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 14: + case 15: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field TLS", wireType) } @@ -15642,7 +15676,7 @@ func (m *BitbucketServerEventSource) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 15: + case 16: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field CheckInterval", wireType) } diff --git a/pkg/apis/eventsource/v1alpha1/generated.proto b/pkg/apis/eventsource/v1alpha1/generated.proto index 11e4ff76b2..b6fcdf0063 100644 --- a/pkg/apis/eventsource/v1alpha1/generated.proto +++ b/pkg/apis/eventsource/v1alpha1/generated.proto @@ -303,7 +303,7 @@ message BitbucketAuth { optional k8s.io.api.core.v1.SecretKeySelector oauthToken = 2; } -// BasicAuth holds the information required to authenticate user via basic auth mechanism +// BitbucketBasicAuth holds the information required to authenticate user via basic auth mechanism message BitbucketBasicAuth { // Username refers to the K8s secret that holds the username. optional k8s.io.api.core.v1.SecretKeySelector username = 1; @@ -396,34 +396,43 @@ message BitbucketServerEventSource { // +optional optional bool skipBranchRefsChangedOnOpenPR = 7; + // OneEventPerChange controls whether to process each change in a repo:refs_changed webhook event as a separate event. This setting is useful when multiple tags are + // pushed simultaneously for the same commit, and each tag needs to independently trigger an action, such as a distinct workflow in Argo Workflows. When enabled, the + // BitbucketServerEventSource publishes an individual BitbucketServerEventData for each change, ensuring independent processing of each tag or reference update in a + // single webhook event. + // +optional + optional bool oneEventPerChange = 8; + // AccessToken is reference to K8s secret which holds the bitbucket api access information. - optional k8s.io.api.core.v1.SecretKeySelector accessToken = 8; + // +optional + optional k8s.io.api.core.v1.SecretKeySelector accessToken = 9; // WebhookSecret is reference to K8s secret which holds the bitbucket webhook secret (for HMAC validation). - optional k8s.io.api.core.v1.SecretKeySelector webhookSecret = 9; + // +optional + optional k8s.io.api.core.v1.SecretKeySelector webhookSecret = 10; // BitbucketServerBaseURL is the base URL for API requests to a custom endpoint. - optional string bitbucketserverBaseURL = 10; + optional string bitbucketserverBaseURL = 11; // DeleteHookOnFinish determines whether to delete the Bitbucket Server hook for the project once the event source is stopped. // +optional - optional bool deleteHookOnFinish = 11; + optional bool deleteHookOnFinish = 12; // Metadata holds the user defined metadata which will passed along the event payload. // +optional - map metadata = 12; + map metadata = 13; // Filter // +optional - optional EventSourceFilter filter = 13; + optional EventSourceFilter filter = 14; // TLS configuration for the bitbucketserver client. // +optional - optional github.com.argoproj.argo_events.pkg.apis.common.TLSConfig tls = 14; + optional github.com.argoproj.argo_events.pkg.apis.common.TLSConfig tls = 15; // CheckInterval is a duration in which to wait before checking that the webhooks exist, e.g. 1s, 30m, 2h... (defaults to 1m) // +optional - optional string checkInterval = 15; + optional string checkInterval = 16; } message BitbucketServerRepository { diff --git a/pkg/apis/eventsource/v1alpha1/openapi_generated.go b/pkg/apis/eventsource/v1alpha1/openapi_generated.go index e130c5b545..3475f85d5c 100644 --- a/pkg/apis/eventsource/v1alpha1/openapi_generated.go +++ b/pkg/apis/eventsource/v1alpha1/openapi_generated.go @@ -650,7 +650,7 @@ func schema_pkg_apis_eventsource_v1alpha1_BitbucketBasicAuth(ref common.Referenc return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "BasicAuth holds the information required to authenticate user via basic auth mechanism", + Description: "BitbucketBasicAuth holds the information required to authenticate user via basic auth mechanism", Type: []string{"object"}, Properties: map[string]spec.Schema{ "username": { @@ -888,6 +888,13 @@ func schema_pkg_apis_eventsource_v1alpha1_BitbucketServerEventSource(ref common. Format: "", }, }, + "oneEventPerChange": { + SchemaProps: spec.SchemaProps{ + Description: "OneEventPerChange controls whether to process each change in a repo:refs_changed webhook event as a separate event. This setting is useful when multiple tags are pushed simultaneously for the same commit, and each tag needs to independently trigger an action, such as a distinct workflow in Argo Workflows. When enabled, the BitbucketServerEventSource publishes an individual BitbucketServerEventData for each change, ensuring independent processing of each tag or reference update in a single webhook event.", + Type: []string{"boolean"}, + Format: "", + }, + }, "accessToken": { SchemaProps: spec.SchemaProps{ Description: "AccessToken is reference to K8s secret which holds the bitbucket api access information.", diff --git a/pkg/apis/eventsource/v1alpha1/types.go b/pkg/apis/eventsource/v1alpha1/types.go index 099067b250..5f4b2ad952 100644 --- a/pkg/apis/eventsource/v1alpha1/types.go +++ b/pkg/apis/eventsource/v1alpha1/types.go @@ -1055,7 +1055,7 @@ type BitbucketAuth struct { OAuthToken *corev1.SecretKeySelector `json:"oauthToken,omitempty" protobuf:"bytes,2,opt,name=oauthToken"` } -// BasicAuth holds the information required to authenticate user via basic auth mechanism +// BitbucketBasicAuth holds the information required to authenticate user via basic auth mechanism type BitbucketBasicAuth struct { // Username refers to the K8s secret that holds the username. Username *corev1.SecretKeySelector `json:"username" protobuf:"bytes,1,name=username"` @@ -1089,27 +1089,35 @@ type BitbucketServerEventSource struct { // This helps in optimizing the event handling process by avoiding unnecessary triggers for branch reference changes that are already part of a pull request under review. // +optional SkipBranchRefsChangedOnOpenPR bool `json:"skipBranchRefsChangedOnOpenPR,omitempty" protobuf:"varint,7,opt,name=skipBranchRefsChangedOnOpenPR"` + // OneEventPerChange controls whether to process each change in a repo:refs_changed webhook event as a separate event. This setting is useful when multiple tags are + // pushed simultaneously for the same commit, and each tag needs to independently trigger an action, such as a distinct workflow in Argo Workflows. When enabled, the + // BitbucketServerEventSource publishes an individual BitbucketServerEventData for each change, ensuring independent processing of each tag or reference update in a + // single webhook event. + // +optional + OneEventPerChange bool `json:"oneEventPerChange,omitempty" protobuf:"varint,8,opt,name=oneEventPerChange"` // AccessToken is reference to K8s secret which holds the bitbucket api access information. - AccessToken *corev1.SecretKeySelector `json:"accessToken,omitempty" protobuf:"bytes,8,opt,name=accessToken"` + // +optional + AccessToken *corev1.SecretKeySelector `json:"accessToken,omitempty" protobuf:"bytes,9,opt,name=accessToken"` // WebhookSecret is reference to K8s secret which holds the bitbucket webhook secret (for HMAC validation). - WebhookSecret *corev1.SecretKeySelector `json:"webhookSecret,omitempty" protobuf:"bytes,9,opt,name=webhookSecret"` + // +optional + WebhookSecret *corev1.SecretKeySelector `json:"webhookSecret,omitempty" protobuf:"bytes,10,opt,name=webhookSecret"` // BitbucketServerBaseURL is the base URL for API requests to a custom endpoint. - BitbucketServerBaseURL string `json:"bitbucketserverBaseURL" protobuf:"bytes,10,opt,name=bitbucketserverBaseURL"` + BitbucketServerBaseURL string `json:"bitbucketserverBaseURL" protobuf:"bytes,11,opt,name=bitbucketserverBaseURL"` // DeleteHookOnFinish determines whether to delete the Bitbucket Server hook for the project once the event source is stopped. // +optional - DeleteHookOnFinish bool `json:"deleteHookOnFinish,omitempty" protobuf:"varint,11,opt,name=deleteHookOnFinish"` + DeleteHookOnFinish bool `json:"deleteHookOnFinish,omitempty" protobuf:"varint,12,opt,name=deleteHookOnFinish"` // Metadata holds the user defined metadata which will passed along the event payload. // +optional - Metadata map[string]string `json:"metadata,omitempty" protobuf:"bytes,12,rep,name=metadata"` + Metadata map[string]string `json:"metadata,omitempty" protobuf:"bytes,13,rep,name=metadata"` // Filter // +optional - Filter *EventSourceFilter `json:"filter,omitempty" protobuf:"bytes,13,opt,name=filter"` + Filter *EventSourceFilter `json:"filter,omitempty" protobuf:"bytes,14,opt,name=filter"` // TLS configuration for the bitbucketserver client. // +optional - TLS *apicommon.TLSConfig `json:"tls,omitempty" protobuf:"bytes,14,opt,name=tls"` + TLS *apicommon.TLSConfig `json:"tls,omitempty" protobuf:"bytes,15,opt,name=tls"` // CheckInterval is a duration in which to wait before checking that the webhooks exist, e.g. 1s, 30m, 2h... (defaults to 1m) // +optional - CheckInterval string `json:"checkInterval" protobuf:"bytes,15,opt,name=checkInterval"` + CheckInterval string `json:"checkInterval" protobuf:"bytes,16,opt,name=checkInterval"` } type BitbucketServerRepository struct { @@ -1120,7 +1128,10 @@ type BitbucketServerRepository struct { } func (b BitbucketServerEventSource) ShouldCreateWebhooks() bool { - return b.AccessToken != nil && b.Webhook != nil && b.Webhook.URL != "" + return b.AccessToken != nil && + b.Webhook != nil && + b.Webhook.URL != "" && + ((len(b.GetBitbucketServerRepositories()) > 0 && b.GetBitbucketServerRepositories() != nil) || len(b.Projects) > 0) } func (b BitbucketServerEventSource) GetBitbucketServerRepositories() []BitbucketServerRepository { diff --git a/pkg/apis/eventsource/v1alpha1/types_test.go b/pkg/apis/eventsource/v1alpha1/types_test.go index e1af8ef86a..2c4cbbce7c 100644 --- a/pkg/apis/eventsource/v1alpha1/types_test.go +++ b/pkg/apis/eventsource/v1alpha1/types_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + v1 "k8s.io/api/core/v1" ) func TestGetReplicas(t *testing.T) { @@ -41,3 +42,93 @@ func TestGithubEventSourceGetRepositories(t *testing.T) { } assert.Equal(t, len(es.GetOwnedRepositories()), 2) } + +// TestShouldCreateWebhooks tests the ShouldCreateWebhooks function on the BitbucketServerEventSource type. +func TestShouldCreateWebhooks(t *testing.T) { + // Create a dummy SecretKeySelector for testing + dummySecretKeySelector := &v1.SecretKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "dummy-secret", + }, + Key: "token", + } + + tests := []struct { + name string + b BitbucketServerEventSource + want bool + }{ + { + name: "Valid Webhooks - Both Projects and Repositories", + b: BitbucketServerEventSource{ + AccessToken: dummySecretKeySelector, + Webhook: &WebhookContext{URL: "http://example.com"}, + Projects: []string{"Project1"}, + Repositories: []BitbucketServerRepository{{ProjectKey: "Proj1", RepositorySlug: "Repo1"}}, + }, + want: true, + }, + { + name: "No AccessToken", + b: BitbucketServerEventSource{ + Webhook: &WebhookContext{URL: "http://example.com"}, + Projects: []string{"Project1"}, + Repositories: []BitbucketServerRepository{{ProjectKey: "Proj1", RepositorySlug: "Repo1"}}, + }, + want: false, + }, + { + name: "No Webhook", + b: BitbucketServerEventSource{ + AccessToken: dummySecretKeySelector, + Projects: []string{"Project1"}, + Repositories: []BitbucketServerRepository{{ProjectKey: "Proj1", RepositorySlug: "Repo1"}}, + }, + want: false, + }, + { + name: "No URL", + b: BitbucketServerEventSource{ + AccessToken: dummySecretKeySelector, + Webhook: &WebhookContext{}, + Projects: []string{"Project1"}, + Repositories: []BitbucketServerRepository{{ProjectKey: "Proj1", RepositorySlug: "Repo1"}}, + }, + want: false, + }, + { + name: "No Projects or Repositories", + b: BitbucketServerEventSource{ + AccessToken: dummySecretKeySelector, + Webhook: &WebhookContext{URL: "http://example.com"}, + }, + want: false, + }, + { + name: "Valid with Only Repositories", + b: BitbucketServerEventSource{ + AccessToken: dummySecretKeySelector, + Webhook: &WebhookContext{URL: "http://example.com"}, + Repositories: []BitbucketServerRepository{{ProjectKey: "Proj1", RepositorySlug: "Repo1"}}, + }, + want: true, + }, + { + name: "Valid with Only Projects", + b: BitbucketServerEventSource{ + AccessToken: dummySecretKeySelector, + Webhook: &WebhookContext{URL: "http://example.com"}, + Projects: []string{"Project1"}, + }, + want: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.b.ShouldCreateWebhooks(); got != tt.want { + t.Errorf("%s: ShouldCreateWebhooks() = %v, want %v", tt.name, got, tt.want) + } + }) + } +}