From b9c938594cd10d744d18586ffaad79104cdada93 Mon Sep 17 00:00:00 2001 From: Michael Waeger <49439088+michaelulrichwaeger@users.noreply.github.com> Date: Thu, 14 May 2020 11:48:57 +0200 Subject: [PATCH] feat: Policy (#79) * policy added * Make it executable * Make it executable, corrections * password age policy added * password lockout policy added * corrections * policy added * Make it executable * Make it executable, corrections * password age policy added * password lockout policy added * corrections * fix(repository): remove second policy * complaints corrected * Init tests * add some tests * more tests added * systemfefaults added * default values load added * check for default value added * fixes * fixed * create policy if not exists * eventstore tests added Co-authored-by: adlerhurst --- cmd/zitadel/system-defaults.yaml | 19 +- .../config/systemdefaults/system_defaults.go | 12 +- .../repository/eventsourcing/policy.go | 45 + .../repository/eventsourcing/repository.go | 10 + internal/management/repository/policy.go | 19 + internal/management/repository/repository.go | 1 + internal/policy/default.go | 22 + internal/policy/model/policy_age.go | 16 + internal/policy/model/policy_complexity.go | 19 + internal/policy/model/policy_lockout.go | 16 + internal/policy/model/types.go | 30 + .../policy/repository/eventsourcing/cache.go | 34 + .../repository/eventsourcing/cache_age.go | 20 + .../eventsourcing/cache_complexity.go | 20 + .../repository/eventsourcing/cache_lockout.go | 20 + .../repository/eventsourcing/eventstore.go | 38 + .../eventsourcing/eventstore_age.go | 83 ++ .../eventsourcing/eventstore_age_mock_test.go | 63 + .../eventsourcing/eventstore_age_test.go | 192 +++ .../eventsourcing/eventstore_complexity.go | 86 ++ .../eventstore_complexity_mock_test.go | 63 + .../eventstore_complexity_test.go | 192 +++ .../eventsourcing/eventstore_lockout.go | 83 ++ .../eventstore_lockout_mock_test.go | 63 + .../eventsourcing/eventstore_lockout_test.go | 192 +++ .../repository/eventsourcing/model_age.go | 80 ++ .../eventsourcing/model_complexity.go | 98 ++ .../repository/eventsourcing/model_lockout.go | 80 ++ .../repository/eventsourcing/policy_age.go | 52 + .../eventsourcing/policy_age_test.go | 268 ++++ .../eventsourcing/policy_complexity.go | 52 + .../eventsourcing/policy_complexity_test.go | 268 ++++ .../eventsourcing/policy_lockout.go | 53 + .../eventsourcing/policy_lockout_test.go | 268 ++++ .../protoc/protoc-gen-authoption/templates.go | 2 +- pkg/management/api/grpc/generate.go | 2 +- pkg/management/api/grpc/management.pb.go | 1080 +++++++++-------- pkg/management/api/grpc/management.pb.gw.go | 243 +--- .../api/grpc/management.swagger.json | 168 ++- pkg/management/api/grpc/policy.go | 78 +- .../api/grpc/policy_age_converter.go | 66 + .../api/grpc/policy_complexity_converter.go | 78 ++ .../api/grpc/policy_lockout_converter.go | 67 + pkg/management/api/grpc/server.go | 2 + pkg/management/api/proto/management.proto | 16 +- pkg/management/management.go | 1 + 46 files changed, 3529 insertions(+), 851 deletions(-) create mode 100644 internal/management/repository/eventsourcing/policy.go create mode 100644 internal/management/repository/policy.go create mode 100644 internal/policy/default.go create mode 100644 internal/policy/model/policy_age.go create mode 100644 internal/policy/model/policy_complexity.go create mode 100644 internal/policy/model/policy_lockout.go create mode 100644 internal/policy/model/types.go create mode 100644 internal/policy/repository/eventsourcing/cache.go create mode 100644 internal/policy/repository/eventsourcing/cache_age.go create mode 100644 internal/policy/repository/eventsourcing/cache_complexity.go create mode 100644 internal/policy/repository/eventsourcing/cache_lockout.go create mode 100644 internal/policy/repository/eventsourcing/eventstore.go create mode 100644 internal/policy/repository/eventsourcing/eventstore_age.go create mode 100644 internal/policy/repository/eventsourcing/eventstore_age_mock_test.go create mode 100644 internal/policy/repository/eventsourcing/eventstore_age_test.go create mode 100644 internal/policy/repository/eventsourcing/eventstore_complexity.go create mode 100644 internal/policy/repository/eventsourcing/eventstore_complexity_mock_test.go create mode 100644 internal/policy/repository/eventsourcing/eventstore_complexity_test.go create mode 100644 internal/policy/repository/eventsourcing/eventstore_lockout.go create mode 100644 internal/policy/repository/eventsourcing/eventstore_lockout_mock_test.go create mode 100644 internal/policy/repository/eventsourcing/eventstore_lockout_test.go create mode 100644 internal/policy/repository/eventsourcing/model_age.go create mode 100644 internal/policy/repository/eventsourcing/model_complexity.go create mode 100644 internal/policy/repository/eventsourcing/model_lockout.go create mode 100644 internal/policy/repository/eventsourcing/policy_age.go create mode 100644 internal/policy/repository/eventsourcing/policy_age_test.go create mode 100644 internal/policy/repository/eventsourcing/policy_complexity.go create mode 100644 internal/policy/repository/eventsourcing/policy_complexity_test.go create mode 100644 internal/policy/repository/eventsourcing/policy_lockout.go create mode 100644 internal/policy/repository/eventsourcing/policy_lockout_test.go create mode 100644 pkg/management/api/grpc/policy_age_converter.go create mode 100644 pkg/management/api/grpc/policy_complexity_converter.go create mode 100644 pkg/management/api/grpc/policy_lockout_converter.go diff --git a/cmd/zitadel/system-defaults.yaml b/cmd/zitadel/system-defaults.yaml index 26edbad6a7..3c973971d5 100644 --- a/cmd/zitadel/system-defaults.yaml +++ b/cmd/zitadel/system-defaults.yaml @@ -41,4 +41,21 @@ SystemDefaults: OTP: Issuer: 'Zitadel' VerificationKey: - EncryptionKeyID: $ZITADEL_OTP_VERIFICATION_KEY \ No newline at end of file + EncryptionKeyID: $ZITADEL_OTP_VERIFICATION_KEY + DefaultPolicies: + Age: + Description: Standard age policy + MaxAgeDays: 365 + ExpireWarnDays: 10 + Complexity: + Description: Standard complexity policy + MinLength: 8 + HasLowercase: true + HasUppercase: false + HasNumber: true + HasSymbol: true + Lockout: + Description: Standard lockout policy + MaxAttempts: 5 + ShowLockOutFailures: true + diff --git a/internal/config/systemdefaults/system_defaults.go b/internal/config/systemdefaults/system_defaults.go index 01c5aca520..65e27d1018 100644 --- a/internal/config/systemdefaults/system_defaults.go +++ b/internal/config/systemdefaults/system_defaults.go @@ -1,11 +1,15 @@ package systemdefaults -import "github.com/caos/zitadel/internal/crypto" +import ( + "github.com/caos/zitadel/internal/crypto" + pol "github.com/caos/zitadel/internal/policy" +) type SystemDefaults struct { SecretGenerators SecretGenerators UserVerificationKey *crypto.KeyConfig Multifactors MultifactorConfig + DefaultPolicies DefaultPolicies } type SecretGenerators struct { @@ -25,3 +29,9 @@ type OTPConfig struct { Issuer string VerificationKey *crypto.KeyConfig } + +type DefaultPolicies struct { + Age pol.PasswordAgePolicyDefault + Complexity pol.PasswordComplexityPolicyDefault + Lockout pol.PasswordLockoutPolicyDefault +} diff --git a/internal/management/repository/eventsourcing/policy.go b/internal/management/repository/eventsourcing/policy.go new file mode 100644 index 0000000000..b0b9527178 --- /dev/null +++ b/internal/management/repository/eventsourcing/policy.go @@ -0,0 +1,45 @@ +package eventsourcing + +import ( + "context" + + "github.com/caos/zitadel/internal/api/auth" + pol_model "github.com/caos/zitadel/internal/policy/model" + pol_event "github.com/caos/zitadel/internal/policy/repository/eventsourcing" +) + +type PolicyRepo struct { + PolicyEvents *pol_event.PolicyEventstore + //view *view.View +} + +func (repo *PolicyRepo) CreatePasswordComplexityPolicy(ctx context.Context, policy *pol_model.PasswordComplexityPolicy) (*pol_model.PasswordComplexityPolicy, error) { + return repo.PolicyEvents.CreatePasswordComplexityPolicy(ctx, policy) +} +func (repo *PolicyRepo) GetPasswordComplexityPolicy(ctx context.Context) (*pol_model.PasswordComplexityPolicy, error) { + ctxData := auth.GetCtxData(ctx) + return repo.PolicyEvents.GetPasswordComplexityPolicy(ctx, ctxData.OrgID) +} +func (repo *PolicyRepo) UpdatePasswordComplexityPolicy(ctx context.Context, policy *pol_model.PasswordComplexityPolicy) (*pol_model.PasswordComplexityPolicy, error) { + return repo.PolicyEvents.UpdatePasswordComplexityPolicy(ctx, policy) +} +func (repo *PolicyRepo) CreatePasswordAgePolicy(ctx context.Context, policy *pol_model.PasswordAgePolicy) (*pol_model.PasswordAgePolicy, error) { + return repo.PolicyEvents.CreatePasswordAgePolicy(ctx, policy) +} +func (repo *PolicyRepo) GetPasswordAgePolicy(ctx context.Context) (*pol_model.PasswordAgePolicy, error) { + ctxData := auth.GetCtxData(ctx) + return repo.PolicyEvents.GetPasswordAgePolicy(ctx, ctxData.OrgID) +} +func (repo *PolicyRepo) UpdatePasswordAgePolicy(ctx context.Context, policy *pol_model.PasswordAgePolicy) (*pol_model.PasswordAgePolicy, error) { + return repo.PolicyEvents.UpdatePasswordAgePolicy(ctx, policy) +} +func (repo *PolicyRepo) CreatePasswordLockoutPolicy(ctx context.Context, policy *pol_model.PasswordLockoutPolicy) (*pol_model.PasswordLockoutPolicy, error) { + return repo.PolicyEvents.CreatePasswordLockoutPolicy(ctx, policy) +} +func (repo *PolicyRepo) GetPasswordLockoutPolicy(ctx context.Context) (*pol_model.PasswordLockoutPolicy, error) { + ctxData := auth.GetCtxData(ctx) + return repo.PolicyEvents.GetPasswordLockoutPolicy(ctx, ctxData.OrgID) +} +func (repo *PolicyRepo) UpdatePasswordLockoutPolicy(ctx context.Context, policy *pol_model.PasswordLockoutPolicy) (*pol_model.PasswordLockoutPolicy, error) { + return repo.PolicyEvents.UpdatePasswordLockoutPolicy(ctx, policy) +} diff --git a/internal/management/repository/eventsourcing/repository.go b/internal/management/repository/eventsourcing/repository.go index b9ba04edeb..9fa09c14cd 100644 --- a/internal/management/repository/eventsourcing/repository.go +++ b/internal/management/repository/eventsourcing/repository.go @@ -12,6 +12,7 @@ import ( "github.com/caos/zitadel/internal/management/repository/eventsourcing/spooler" mgmt_view "github.com/caos/zitadel/internal/management/repository/eventsourcing/view" es_org "github.com/caos/zitadel/internal/org/repository/eventsourcing" + es_pol "github.com/caos/zitadel/internal/policy/repository/eventsourcing" es_proj "github.com/caos/zitadel/internal/project/repository/eventsourcing" es_usr "github.com/caos/zitadel/internal/user/repository/eventsourcing" es_grant "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing" @@ -30,6 +31,7 @@ type EsRepository struct { eventstore.ProjectRepo eventstore.UserRepo eventstore.UserGrantRepo + PolicyRepo } func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) { @@ -54,6 +56,13 @@ func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) if err != nil { return nil, err } + policy, err := es_pol.StartPolicy(es_pol.PolicyConfig{ + Eventstore: es, + Cache: conf.Eventstore.Cache, + }, systemDefaults) + if err != nil { + return nil, err + } user, err := es_usr.StartUser(es_usr.UserConfig{ Eventstore: es, Cache: conf.Eventstore.Cache, @@ -79,6 +88,7 @@ func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) ProjectRepo: eventstore.ProjectRepo{conf.SearchLimit, project, view}, UserRepo: eventstore.UserRepo{conf.SearchLimit, user, view}, UserGrantRepo: eventstore.UserGrantRepo{conf.SearchLimit, usergrant, view}, + PolicyRepo: PolicyRepo{policy}, }, nil } diff --git a/internal/management/repository/policy.go b/internal/management/repository/policy.go new file mode 100644 index 0000000000..50b5c7a895 --- /dev/null +++ b/internal/management/repository/policy.go @@ -0,0 +1,19 @@ +package repository + +import ( + "context" + + "github.com/caos/zitadel/internal/policy/model" +) + +type PolicyRepository interface { + CreatePasswordComplexityPolicy(ctx context.Context, policy *model.PasswordComplexityPolicy) (*model.PasswordComplexityPolicy, error) + GetPasswordComplexityPolicy(ctx context.Context) (*model.PasswordComplexityPolicy, error) + UpdatePasswordComplexityPolicy(ctx context.Context, policy *model.PasswordComplexityPolicy) (*model.PasswordComplexityPolicy, error) + CreatePasswordAgePolicy(ctx context.Context, policy *model.PasswordAgePolicy) (*model.PasswordAgePolicy, error) + GetPasswordAgePolicy(ctx context.Context) (*model.PasswordAgePolicy, error) + UpdatePasswordAgePolicy(ctx context.Context, policy *model.PasswordAgePolicy) (*model.PasswordAgePolicy, error) + CreatePasswordLockoutPolicy(ctx context.Context, policy *model.PasswordLockoutPolicy) (*model.PasswordLockoutPolicy, error) + GetPasswordLockoutPolicy(ctx context.Context) (*model.PasswordLockoutPolicy, error) + UpdatePasswordLockoutPolicy(ctx context.Context, policy *model.PasswordLockoutPolicy) (*model.PasswordLockoutPolicy, error) +} diff --git a/internal/management/repository/repository.go b/internal/management/repository/repository.go index 7e083d25be..3a00e8d4d2 100644 --- a/internal/management/repository/repository.go +++ b/internal/management/repository/repository.go @@ -3,6 +3,7 @@ package repository type Repository interface { Health() error ProjectRepository + PolicyRepository OrgRepository OrgMemberRepository UserRepository diff --git a/internal/policy/default.go b/internal/policy/default.go new file mode 100644 index 0000000000..fb02396d74 --- /dev/null +++ b/internal/policy/default.go @@ -0,0 +1,22 @@ +package policy + +type PasswordAgePolicyDefault struct { + Description string + MaxAgeDays uint64 + ExpireWarnDays uint64 +} + +type PasswordComplexityPolicyDefault struct { + Description string + MinLength uint64 + HasLowercase bool + HasUppercase bool + HasNumber bool + HasSymbol bool +} + +type PasswordLockoutPolicyDefault struct { + Description string + MaxAttempts uint64 + ShowLockOutFailures bool +} diff --git a/internal/policy/model/policy_age.go b/internal/policy/model/policy_age.go new file mode 100644 index 0000000000..e37cdf38ea --- /dev/null +++ b/internal/policy/model/policy_age.go @@ -0,0 +1,16 @@ +package model + +import "github.com/caos/zitadel/internal/eventstore/models" + +type PasswordAgePolicy struct { + models.ObjectRoot + + Description string + State PolicyState + MaxAgeDays uint64 + ExpireWarnDays uint64 +} + +func (p *PasswordAgePolicy) IsValid() bool { + return p.Description != "" +} diff --git a/internal/policy/model/policy_complexity.go b/internal/policy/model/policy_complexity.go new file mode 100644 index 0000000000..cae1ffe2ba --- /dev/null +++ b/internal/policy/model/policy_complexity.go @@ -0,0 +1,19 @@ +package model + +import "github.com/caos/zitadel/internal/eventstore/models" + +type PasswordComplexityPolicy struct { + models.ObjectRoot + + Description string + State PolicyState + MinLength uint64 + HasLowercase bool + HasUppercase bool + HasNumber bool + HasSymbol bool +} + +func (p *PasswordComplexityPolicy) IsValid() bool { + return p.Description != "" +} diff --git a/internal/policy/model/policy_lockout.go b/internal/policy/model/policy_lockout.go new file mode 100644 index 0000000000..ff98a914a9 --- /dev/null +++ b/internal/policy/model/policy_lockout.go @@ -0,0 +1,16 @@ +package model + +import "github.com/caos/zitadel/internal/eventstore/models" + +type PasswordLockoutPolicy struct { + models.ObjectRoot + + Description string + State PolicyState + MaxAttempts uint64 + ShowLockOutFailures bool +} + +func (p *PasswordLockoutPolicy) IsValid() bool { + return p.Description != "" +} diff --git a/internal/policy/model/types.go b/internal/policy/model/types.go new file mode 100644 index 0000000000..e506394b68 --- /dev/null +++ b/internal/policy/model/types.go @@ -0,0 +1,30 @@ +package model + +import "github.com/caos/zitadel/internal/eventstore/models" + +const ( + // complexity + PasswordComplexityPolicyAggregate models.AggregateType = "policy.password.complexity" + + PasswordComplexityPolicyAdded models.EventType = "policy.password.complexity.added" + PasswordComplexityPolicyChanged models.EventType = "policy.password.complexity.changed" + + // age + PasswordAgePolicyAggregate models.AggregateType = "policy.password.age" + + PasswordAgePolicyAdded models.EventType = "policy.password.age.added" + PasswordAgePolicyChanged models.EventType = "policy.password.age.changed" + + // lockout + PasswordLockoutPolicyAggregate models.AggregateType = "policy.password.lockout" + + PasswordLockoutPolicyAdded models.EventType = "policy.password.lockout.added" + PasswordLockoutPolicyChanged models.EventType = "policy.password.lockout.changed" +) + +type PolicyState int32 + +const ( + POLICYSTATE_ACTIVE PolicyState = iota + POLICYSTATE_INACTIVE +) diff --git a/internal/policy/repository/eventsourcing/cache.go b/internal/policy/repository/eventsourcing/cache.go new file mode 100644 index 0000000000..674b2e3f61 --- /dev/null +++ b/internal/policy/repository/eventsourcing/cache.go @@ -0,0 +1,34 @@ +package eventsourcing + +import ( + "github.com/caos/logging" + "github.com/caos/zitadel/internal/cache" + "github.com/caos/zitadel/internal/cache/config" + "github.com/caos/zitadel/internal/eventstore/models" +) + +type PolicyCache struct { + policyCache cache.Cache +} + +func StartCache(conf *config.CacheConfig) (*PolicyCache, error) { + policyCache, err := conf.Config.NewCache() + logging.Log("EVENT-vDneN").OnError(err).Panic("unable to create policy cache") + + return &PolicyCache{policyCache: policyCache}, nil +} + +func (c *PolicyCache) getPolicy(id string) (policy *PasswordComplexityPolicy) { + policy = &PasswordComplexityPolicy{ObjectRoot: models.ObjectRoot{AggregateID: id}} + if err := c.policyCache.Get(id, policy); err != nil { + logging.Log("EVENT-4eTZh").WithError(err).Debug("error in getting cache") + } + return policy +} + +func (c *PolicyCache) cachePolicy(policy *PasswordComplexityPolicy) { + err := c.policyCache.Set(policy.AggregateID, policy) + if err != nil { + logging.Log("EVENT-ThnBb").WithError(err).Debug("error in setting policy cache") + } +} diff --git a/internal/policy/repository/eventsourcing/cache_age.go b/internal/policy/repository/eventsourcing/cache_age.go new file mode 100644 index 0000000000..e8e9ec6dd0 --- /dev/null +++ b/internal/policy/repository/eventsourcing/cache_age.go @@ -0,0 +1,20 @@ +package eventsourcing + +import ( + "github.com/caos/logging" +) + +func (c *PolicyCache) getAgePolicy(id string) (policy *PasswordAgePolicy) { + policy = new(PasswordAgePolicy) + if err := c.policyCache.Get(id, policy); err != nil { + logging.Log("EVENT-NqMFM").WithError(err).Debug("error in getting cache") + } + return policy +} + +func (c *PolicyCache) cacheAgePolicy(policy *PasswordAgePolicy) { + err := c.policyCache.Set(policy.AggregateID, policy) + if err != nil { + logging.Log("EVENT-6vRvM").WithError(err).Debug("error in setting policy cache") + } +} diff --git a/internal/policy/repository/eventsourcing/cache_complexity.go b/internal/policy/repository/eventsourcing/cache_complexity.go new file mode 100644 index 0000000000..7c05e5528d --- /dev/null +++ b/internal/policy/repository/eventsourcing/cache_complexity.go @@ -0,0 +1,20 @@ +package eventsourcing + +import ( + "github.com/caos/logging" +) + +func (c *PolicyCache) getComplexityPolicy(id string) (policy *PasswordComplexityPolicy) { + policy = new(PasswordComplexityPolicy) + if err := c.policyCache.Get(id, policy); err != nil { + logging.Log("EVENT-Wgrph").WithError(err).Debug("error in getting cache") + } + return policy +} + +func (c *PolicyCache) cacheComplexityPolicy(policy *PasswordComplexityPolicy) { + err := c.policyCache.Set(policy.AggregateID, policy) + if err != nil { + logging.Log("EVENT-ylGny").WithError(err).Debug("error in setting policy cache") + } +} diff --git a/internal/policy/repository/eventsourcing/cache_lockout.go b/internal/policy/repository/eventsourcing/cache_lockout.go new file mode 100644 index 0000000000..4fbb7f700e --- /dev/null +++ b/internal/policy/repository/eventsourcing/cache_lockout.go @@ -0,0 +1,20 @@ +package eventsourcing + +import ( + "github.com/caos/logging" +) + +func (c *PolicyCache) getLockoutPolicy(id string) (policy *PasswordLockoutPolicy) { + policy = new(PasswordLockoutPolicy) + if err := c.policyCache.Get(id, policy); err != nil { + logging.Log("EVENT-Zoljf").WithError(err).Debug("error in getting cache") + } + return policy +} + +func (c *PolicyCache) cacheLockoutPolicy(policy *PasswordLockoutPolicy) { + err := c.policyCache.Set(policy.AggregateID, policy) + if err != nil { + logging.Log("EVENT-6klAf").WithError(err).Debug("error in setting policy cache") + } +} diff --git a/internal/policy/repository/eventsourcing/eventstore.go b/internal/policy/repository/eventsourcing/eventstore.go new file mode 100644 index 0000000000..dfa68170fb --- /dev/null +++ b/internal/policy/repository/eventsourcing/eventstore.go @@ -0,0 +1,38 @@ +package eventsourcing + +import ( + "github.com/caos/zitadel/internal/cache/config" + sd "github.com/caos/zitadel/internal/config/systemdefaults" + es_int "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/policy" + "github.com/sony/sonyflake" +) + +var idGenerator = sonyflake.NewSonyflake(sonyflake.Settings{}) + +type PolicyEventstore struct { + es_int.Eventstore + policyCache *PolicyCache + passwordAgePolicyDefault policy.PasswordAgePolicyDefault + passwordComplexityPolicyDefault policy.PasswordComplexityPolicyDefault + passwordLockoutPolicyDefault policy.PasswordLockoutPolicyDefault +} + +type PolicyConfig struct { + es_int.Eventstore + Cache *config.CacheConfig +} + +func StartPolicy(conf PolicyConfig, systemDefaults sd.SystemDefaults) (*PolicyEventstore, error) { + policyCache, err := StartCache(conf.Cache) + if err != nil { + return nil, err + } + return &PolicyEventstore{ + Eventstore: conf.Eventstore, + policyCache: policyCache, + passwordAgePolicyDefault: systemDefaults.DefaultPolicies.Age, + passwordComplexityPolicyDefault: systemDefaults.DefaultPolicies.Complexity, + passwordLockoutPolicyDefault: systemDefaults.DefaultPolicies.Lockout, + }, nil +} diff --git a/internal/policy/repository/eventsourcing/eventstore_age.go b/internal/policy/repository/eventsourcing/eventstore_age.go new file mode 100644 index 0000000000..db9f2d40d7 --- /dev/null +++ b/internal/policy/repository/eventsourcing/eventstore_age.go @@ -0,0 +1,83 @@ +package eventsourcing + +import ( + "context" + "strconv" + + "github.com/caos/zitadel/internal/api/auth" + caos_errs "github.com/caos/zitadel/internal/errors" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + pol_model "github.com/caos/zitadel/internal/policy/model" +) + +func (es *PolicyEventstore) GetPasswordAgePolicy(ctx context.Context, id string) (*pol_model.PasswordAgePolicy, error) { + policy := es.policyCache.getAgePolicy(id) + + query := PasswordAgePolicyQuery(id, policy.Sequence) + err := es_sdk.Filter(ctx, es.FilterEvents, policy.AppendEvents, query) + if caos_errs.IsNotFound(err) && es.passwordAgePolicyDefault.Description != "" { + policy.Description = es.passwordAgePolicyDefault.Description + policy.MaxAgeDays = es.passwordAgePolicyDefault.MaxAgeDays + policy.ExpireWarnDays = es.passwordAgePolicyDefault.ExpireWarnDays + } else if err != nil { + return nil, err + } + es.policyCache.cacheAgePolicy(policy) + return PasswordAgePolicyToModel(policy), nil +} + +func (es *PolicyEventstore) CreatePasswordAgePolicy(ctx context.Context, policy *pol_model.PasswordAgePolicy) (*pol_model.PasswordAgePolicy, error) { + if !policy.IsValid() { + return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-fbX5K", "Description is required") + } + ctxData := auth.GetCtxData(ctx) + existingPolicy, err := es.GetPasswordAgePolicy(ctx, ctxData.OrgID) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } + if existingPolicy != nil && existingPolicy.Sequence > 0 { + return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-yDJ5I", "Policy allready exists") + } + + id, err := idGenerator.NextID() + if err != nil { + return nil, err + } + policy.AggregateID = strconv.FormatUint(id, 10) + + repoPolicy := PasswordAgePolicyFromModel(policy) + + createAggregate := PasswordAgePolicyCreateAggregate(es.AggregateCreator(), repoPolicy) + err = es_sdk.Push(ctx, es.PushAggregates, repoPolicy.AppendEvents, createAggregate) + if err != nil { + return nil, err + } + + es.policyCache.cacheAgePolicy(repoPolicy) + return PasswordAgePolicyToModel(repoPolicy), nil +} + +func (es *PolicyEventstore) UpdatePasswordAgePolicy(ctx context.Context, policy *pol_model.PasswordAgePolicy) (*pol_model.PasswordAgePolicy, error) { + if !policy.IsValid() { + return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-44jB3", "Description is required") + } + ctxData := auth.GetCtxData(ctx) + existingPolicy, err := es.GetPasswordAgePolicy(ctx, ctxData.OrgID) + if err != nil { + return nil, err + } + if existingPolicy.Sequence <= 0 { + return es.CreatePasswordAgePolicy(ctx, policy) + } + repoExisting := PasswordAgePolicyFromModel(existingPolicy) + repoNew := PasswordAgePolicyFromModel(policy) + + updateAggregate := PasswordAgePolicyUpdateAggregate(es.AggregateCreator(), repoExisting, repoNew) + err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, updateAggregate) + if err != nil { + return nil, err + } + + es.policyCache.cacheAgePolicy(repoExisting) + return PasswordAgePolicyToModel(repoExisting), nil +} diff --git a/internal/policy/repository/eventsourcing/eventstore_age_mock_test.go b/internal/policy/repository/eventsourcing/eventstore_age_mock_test.go new file mode 100644 index 0000000000..2edaec8eda --- /dev/null +++ b/internal/policy/repository/eventsourcing/eventstore_age_mock_test.go @@ -0,0 +1,63 @@ +package eventsourcing + +import ( + "encoding/json" + + mock_cache "github.com/caos/zitadel/internal/cache/mock" + "github.com/caos/zitadel/internal/eventstore/mock" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/policy/model" + "github.com/golang/mock/gomock" +) + +func GetMockedEventstoreAge(ctrl *gomock.Controller, mockEs *mock.MockEventstore) *PolicyEventstore { + return &PolicyEventstore{ + Eventstore: mockEs, + policyCache: GetMockCacheAge(ctrl), + } +} + +func GetMockCacheAge(ctrl *gomock.Controller) *PolicyCache { + mockCache := mock_cache.NewMockCache(ctrl) + mockCache.EXPECT().Get(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + mockCache.EXPECT().Set(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + return &PolicyCache{policyCache: mockCache} +} + +func GetMockGetPasswordAgePolicyOK(ctrl *gomock.Controller) *PolicyEventstore { + data, _ := json.Marshal(model.PasswordAgePolicy{Description: "Name"}) + events := []*es_models.Event{ + &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.PasswordAgePolicyAdded, Data: data}, + } + mockEs := mock.NewMockEventstore(ctrl) + mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) + return GetMockedEventstoreAge(ctrl, mockEs) +} + +func GetMockGetPasswordAgePolicyNoEvents(ctrl *gomock.Controller) *PolicyEventstore { + events := []*es_models.Event{} + mockEs := mock.NewMockEventstore(ctrl) + mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) + return GetMockedEventstoreAge(ctrl, mockEs) +} + +func GetMockPasswordAgePolicy(ctrl *gomock.Controller) *PolicyEventstore { + data, _ := json.Marshal(model.PasswordAgePolicy{Description: "Name"}) + events := []*es_models.Event{ + &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.PasswordAgePolicyAdded, Data: data}, + } + mockEs := mock.NewMockEventstore(ctrl) + mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) + mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST")) + mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil) + return GetMockedEventstoreAge(ctrl, mockEs) +} + +func GetMockPasswordAgePolicyNoEvents(ctrl *gomock.Controller) *PolicyEventstore { + events := []*es_models.Event{} + mockEs := mock.NewMockEventstore(ctrl) + mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) + mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST")) + mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil) + return GetMockedEventstoreAge(ctrl, mockEs) +} diff --git a/internal/policy/repository/eventsourcing/eventstore_age_test.go b/internal/policy/repository/eventsourcing/eventstore_age_test.go new file mode 100644 index 0000000000..a917d61568 --- /dev/null +++ b/internal/policy/repository/eventsourcing/eventstore_age_test.go @@ -0,0 +1,192 @@ +package eventsourcing + +import ( + "context" + "testing" + + "github.com/caos/zitadel/internal/api/auth" + caos_errs "github.com/caos/zitadel/internal/errors" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/policy/model" + "github.com/golang/mock/gomock" +) + +func TestGetPasswordAgePolicy(t *testing.T) { + ctrl := gomock.NewController(t) + type args struct { + es *PolicyEventstore + policy *model.PasswordAgePolicy + } + type res struct { + policy *model.PasswordAgePolicy + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "policy from events, ok", + args: args{ + es: GetMockGetPasswordAgePolicyOK(ctrl), + policy: &model.PasswordAgePolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}}, + }, + res: res{ + policy: &model.PasswordAgePolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}}, + }, + }, + { + name: "policy from events, no events", + args: args{ + es: GetMockGetPasswordAgePolicyNoEvents(ctrl), + policy: &model.PasswordAgePolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 2}}, + }, + res: res{ + wantErr: true, + errFunc: caos_errs.IsNotFound, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := tt.args.es.GetPasswordAgePolicy(nil, tt.args.policy.AggregateID) + + if !tt.res.wantErr && result.AggregateID != tt.res.policy.AggregateID { + t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.res.policy.AggregateID, result.AggregateID) + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + +func TestCreatePasswordAgePolicy(t *testing.T) { + ctrl := gomock.NewController(t) + type args struct { + es *PolicyEventstore + ctx context.Context + policy *model.PasswordAgePolicy + } + type res struct { + policy *model.PasswordAgePolicy + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "create policy, ok", + args: args{ + es: GetMockPasswordAgePolicyNoEvents(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &model.PasswordAgePolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID1", Sequence: 2}, Description: "Name"}, + }, + res: res{ + policy: &model.PasswordAgePolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID1", Sequence: 2}, Description: "Name"}, + }, + }, + { + name: "create policy no name", + args: args{ + es: GetMockPasswordAgePolicyNoEvents(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &model.PasswordAgePolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}}, + }, + res: res{ + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := tt.args.es.CreatePasswordAgePolicy(tt.args.ctx, tt.args.policy) + + if !tt.res.wantErr && result.AggregateID == "" { + t.Errorf("result has no id") + } + if !tt.res.wantErr && result.Description != tt.res.policy.Description { + t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.res.policy.Description, result.Description) + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + +func TestUpdatePasswordAgePolicy(t *testing.T) { + ctrl := gomock.NewController(t) + type args struct { + es *PolicyEventstore + ctx context.Context + new *model.PasswordAgePolicy + } + type res struct { + policy *model.PasswordAgePolicy + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "update policy, ok", + args: args{ + es: GetMockPasswordAgePolicy(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + new: &model.PasswordAgePolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Description: "NameNew"}, + }, + res: res{ + policy: &model.PasswordAgePolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Description: "NameNew"}, + }, + }, + { + name: "update policy no name", + args: args{ + es: GetMockPasswordAgePolicy(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + new: &model.PasswordAgePolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Description: ""}, + }, + res: res{ + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + { + name: "existing policy not found", + args: args{ + es: GetMockPasswordAgePolicyNoEvents(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + new: &model.PasswordAgePolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Description: "NameNew"}, + }, + res: res{ + wantErr: true, + errFunc: caos_errs.IsNotFound, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := tt.args.es.UpdatePasswordAgePolicy(tt.args.ctx, tt.args.new) + + if !tt.res.wantErr && result.AggregateID == "" { + t.Errorf("result has no id") + } + if !tt.res.wantErr && result.Description != tt.res.policy.Description { + t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.res.policy.Description, result.Description) + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} diff --git a/internal/policy/repository/eventsourcing/eventstore_complexity.go b/internal/policy/repository/eventsourcing/eventstore_complexity.go new file mode 100644 index 0000000000..62a8b1cda0 --- /dev/null +++ b/internal/policy/repository/eventsourcing/eventstore_complexity.go @@ -0,0 +1,86 @@ +package eventsourcing + +import ( + "context" + "strconv" + + "github.com/caos/zitadel/internal/api/auth" + caos_errs "github.com/caos/zitadel/internal/errors" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + pol_model "github.com/caos/zitadel/internal/policy/model" +) + +func (es *PolicyEventstore) GetPasswordComplexityPolicy(ctx context.Context, id string) (*pol_model.PasswordComplexityPolicy, error) { + policy := es.policyCache.getComplexityPolicy(id) + + query := PasswordComplexityPolicyQuery(id, policy.Sequence) + err := es_sdk.Filter(ctx, es.FilterEvents, policy.AppendEvents, query) + if caos_errs.IsNotFound(err) && es.passwordComplexityPolicyDefault.Description != "" { + policy.Description = es.passwordComplexityPolicyDefault.Description + policy.MinLength = es.passwordComplexityPolicyDefault.MinLength + policy.HasLowercase = es.passwordComplexityPolicyDefault.HasLowercase + policy.HasUppercase = es.passwordComplexityPolicyDefault.HasUppercase + policy.HasNumber = es.passwordComplexityPolicyDefault.HasNumber + policy.HasSymbol = es.passwordComplexityPolicyDefault.HasSymbol + } else if err != nil { + return nil, err + } + es.policyCache.cacheComplexityPolicy(policy) + return PasswordComplexityPolicyToModel(policy), nil +} + +func (es *PolicyEventstore) CreatePasswordComplexityPolicy(ctx context.Context, policy *pol_model.PasswordComplexityPolicy) (*pol_model.PasswordComplexityPolicy, error) { + if !policy.IsValid() { + return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "Description is required") + } + ctxData := auth.GetCtxData(ctx) + existingPolicy, err := es.GetPasswordComplexityPolicy(ctx, ctxData.OrgID) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } + if existingPolicy != nil && existingPolicy.Sequence > 0 { + return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-yDJ5I", "Policy allready exists") + } + + id, err := idGenerator.NextID() + if err != nil { + return nil, err + } + policy.AggregateID = strconv.FormatUint(id, 10) + + repoPolicy := PasswordComplexityPolicyFromModel(policy) + + createAggregate := PasswordComplexityPolicyCreateAggregate(es.AggregateCreator(), repoPolicy) + err = es_sdk.Push(ctx, es.PushAggregates, repoPolicy.AppendEvents, createAggregate) + if err != nil { + return nil, err + } + + es.policyCache.cacheComplexityPolicy(repoPolicy) + return PasswordComplexityPolicyToModel(repoPolicy), nil +} + +func (es *PolicyEventstore) UpdatePasswordComplexityPolicy(ctx context.Context, policy *pol_model.PasswordComplexityPolicy) (*pol_model.PasswordComplexityPolicy, error) { + if !policy.IsValid() { + return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "Description is required") + } + ctxData := auth.GetCtxData(ctx) + existingPolicy, err := es.GetPasswordComplexityPolicy(ctx, ctxData.OrgID) + if err != nil { + return nil, err + } + if existingPolicy.Sequence <= 0 { + return es.CreatePasswordComplexityPolicy(ctx, policy) + } + repoExisting := PasswordComplexityPolicyFromModel(existingPolicy) + repoNew := PasswordComplexityPolicyFromModel(policy) + + updateAggregate := PasswordComplexityPolicyUpdateAggregate(es.AggregateCreator(), repoExisting, repoNew) + err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, updateAggregate) + if err != nil { + return nil, err + } + + es.policyCache.cacheComplexityPolicy(repoExisting) + return PasswordComplexityPolicyToModel(repoExisting), nil +} diff --git a/internal/policy/repository/eventsourcing/eventstore_complexity_mock_test.go b/internal/policy/repository/eventsourcing/eventstore_complexity_mock_test.go new file mode 100644 index 0000000000..507303e801 --- /dev/null +++ b/internal/policy/repository/eventsourcing/eventstore_complexity_mock_test.go @@ -0,0 +1,63 @@ +package eventsourcing + +import ( + "encoding/json" + + mock_cache "github.com/caos/zitadel/internal/cache/mock" + "github.com/caos/zitadel/internal/eventstore/mock" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/policy/model" + "github.com/golang/mock/gomock" +) + +func GetMockedEventstoreComplexity(ctrl *gomock.Controller, mockEs *mock.MockEventstore) *PolicyEventstore { + return &PolicyEventstore{ + Eventstore: mockEs, + policyCache: GetMockCacheComplexity(ctrl), + } +} + +func GetMockCacheComplexity(ctrl *gomock.Controller) *PolicyCache { + mockCache := mock_cache.NewMockCache(ctrl) + mockCache.EXPECT().Get(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + mockCache.EXPECT().Set(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + return &PolicyCache{policyCache: mockCache} +} + +func GetMockGetPasswordComplexityPolicyOK(ctrl *gomock.Controller) *PolicyEventstore { + data, _ := json.Marshal(model.PasswordComplexityPolicy{Description: "Name"}) + events := []*es_models.Event{ + &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.PasswordComplexityPolicyAdded, Data: data}, + } + mockEs := mock.NewMockEventstore(ctrl) + mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) + return GetMockedEventstoreComplexity(ctrl, mockEs) +} + +func GetMockGetPasswordComplexityPolicyNoEvents(ctrl *gomock.Controller) *PolicyEventstore { + events := []*es_models.Event{} + mockEs := mock.NewMockEventstore(ctrl) + mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) + return GetMockedEventstoreComplexity(ctrl, mockEs) +} + +func GetMockPasswordComplexityPolicy(ctrl *gomock.Controller) *PolicyEventstore { + data, _ := json.Marshal(model.PasswordComplexityPolicy{Description: "Name"}) + events := []*es_models.Event{ + &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.PasswordComplexityPolicyAdded, Data: data}, + } + mockEs := mock.NewMockEventstore(ctrl) + mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) + mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST")) + mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil) + return GetMockedEventstoreComplexity(ctrl, mockEs) +} + +func GetMockPasswordComplexityPolicyNoEvents(ctrl *gomock.Controller) *PolicyEventstore { + events := []*es_models.Event{} + mockEs := mock.NewMockEventstore(ctrl) + mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) + mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST")) + mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil) + return GetMockedEventstoreComplexity(ctrl, mockEs) +} diff --git a/internal/policy/repository/eventsourcing/eventstore_complexity_test.go b/internal/policy/repository/eventsourcing/eventstore_complexity_test.go new file mode 100644 index 0000000000..55e87d03bc --- /dev/null +++ b/internal/policy/repository/eventsourcing/eventstore_complexity_test.go @@ -0,0 +1,192 @@ +package eventsourcing + +import ( + "context" + "testing" + + "github.com/caos/zitadel/internal/api/auth" + caos_errs "github.com/caos/zitadel/internal/errors" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/policy/model" + "github.com/golang/mock/gomock" +) + +func TestGetPasswordComplexityPolicy(t *testing.T) { + ctrl := gomock.NewController(t) + type args struct { + es *PolicyEventstore + policy *model.PasswordComplexityPolicy + } + type res struct { + policy *model.PasswordComplexityPolicy + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "policy from events, ok", + args: args{ + es: GetMockGetPasswordComplexityPolicyOK(ctrl), + policy: &model.PasswordComplexityPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}}, + }, + res: res{ + policy: &model.PasswordComplexityPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}}, + }, + }, + { + name: "policy from events, no events", + args: args{ + es: GetMockGetPasswordComplexityPolicyNoEvents(ctrl), + policy: &model.PasswordComplexityPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 2}}, + }, + res: res{ + wantErr: true, + errFunc: caos_errs.IsNotFound, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := tt.args.es.GetPasswordComplexityPolicy(nil, tt.args.policy.AggregateID) + + if !tt.res.wantErr && result.AggregateID != tt.res.policy.AggregateID { + t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.res.policy.AggregateID, result.AggregateID) + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + +func TestCreatePasswordComplexityPolicy(t *testing.T) { + ctrl := gomock.NewController(t) + type args struct { + es *PolicyEventstore + ctx context.Context + policy *model.PasswordComplexityPolicy + } + type res struct { + policy *model.PasswordComplexityPolicy + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "create policy, ok", + args: args{ + es: GetMockPasswordComplexityPolicyNoEvents(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &model.PasswordComplexityPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID1", Sequence: 2}, Description: "Name"}, + }, + res: res{ + policy: &model.PasswordComplexityPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID1", Sequence: 2}, Description: "Name"}, + }, + }, + { + name: "create policy no name", + args: args{ + es: GetMockPasswordComplexityPolicyNoEvents(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &model.PasswordComplexityPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}}, + }, + res: res{ + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := tt.args.es.CreatePasswordComplexityPolicy(tt.args.ctx, tt.args.policy) + + if !tt.res.wantErr && result.AggregateID == "" { + t.Errorf("result has no id") + } + if !tt.res.wantErr && result.Description != tt.res.policy.Description { + t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.res.policy.Description, result.Description) + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + +func TestUpdatePasswordComplexityPolicy(t *testing.T) { + ctrl := gomock.NewController(t) + type args struct { + es *PolicyEventstore + ctx context.Context + new *model.PasswordComplexityPolicy + } + type res struct { + policy *model.PasswordComplexityPolicy + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "update policy, ok", + args: args{ + es: GetMockPasswordComplexityPolicy(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + new: &model.PasswordComplexityPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Description: "NameNew"}, + }, + res: res{ + policy: &model.PasswordComplexityPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Description: "NameNew"}, + }, + }, + { + name: "update policy no name", + args: args{ + es: GetMockPasswordComplexityPolicy(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + new: &model.PasswordComplexityPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Description: ""}, + }, + res: res{ + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + { + name: "existing policy not found", + args: args{ + es: GetMockPasswordComplexityPolicyNoEvents(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + new: &model.PasswordComplexityPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Description: "NameNew"}, + }, + res: res{ + wantErr: true, + errFunc: caos_errs.IsNotFound, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := tt.args.es.UpdatePasswordComplexityPolicy(tt.args.ctx, tt.args.new) + + if !tt.res.wantErr && result.AggregateID == "" { + t.Errorf("result has no id") + } + if !tt.res.wantErr && result.Description != tt.res.policy.Description { + t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.res.policy.Description, result.Description) + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} diff --git a/internal/policy/repository/eventsourcing/eventstore_lockout.go b/internal/policy/repository/eventsourcing/eventstore_lockout.go new file mode 100644 index 0000000000..486ce65d0e --- /dev/null +++ b/internal/policy/repository/eventsourcing/eventstore_lockout.go @@ -0,0 +1,83 @@ +package eventsourcing + +import ( + "context" + "strconv" + + "github.com/caos/zitadel/internal/api/auth" + caos_errs "github.com/caos/zitadel/internal/errors" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + pol_model "github.com/caos/zitadel/internal/policy/model" +) + +func (es *PolicyEventstore) GetPasswordLockoutPolicy(ctx context.Context, id string) (*pol_model.PasswordLockoutPolicy, error) { + policy := es.policyCache.getLockoutPolicy(id) + + query := PasswordLockoutPolicyQuery(id, policy.Sequence) + err := es_sdk.Filter(ctx, es.FilterEvents, policy.AppendEvents, query) + if caos_errs.IsNotFound(err) && es.passwordLockoutPolicyDefault.Description != "" { + policy.Description = es.passwordLockoutPolicyDefault.Description + policy.MaxAttempts = es.passwordLockoutPolicyDefault.MaxAttempts + policy.ShowLockOutFailures = es.passwordLockoutPolicyDefault.ShowLockOutFailures + } else if err != nil { + return nil, err + } + es.policyCache.cacheLockoutPolicy(policy) + return PasswordLockoutPolicyToModel(policy), nil +} + +func (es *PolicyEventstore) CreatePasswordLockoutPolicy(ctx context.Context, policy *pol_model.PasswordLockoutPolicy) (*pol_model.PasswordLockoutPolicy, error) { + if !policy.IsValid() { + return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "Description is required") + } + ctxData := auth.GetCtxData(ctx) + existingPolicy, err := es.GetPasswordLockoutPolicy(ctx, ctxData.OrgID) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } + if existingPolicy != nil && existingPolicy.Sequence > 0 { + return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-yDJ5I", "Policy allready exists") + } + + id, err := idGenerator.NextID() + if err != nil { + return nil, err + } + policy.AggregateID = strconv.FormatUint(id, 10) + + repoPolicy := PasswordLockoutPolicyFromModel(policy) + + createAggregate := PasswordLockoutPolicyCreateAggregate(es.AggregateCreator(), repoPolicy) + err = es_sdk.Push(ctx, es.PushAggregates, repoPolicy.AppendEvents, createAggregate) + if err != nil { + return nil, err + } + + es.policyCache.cacheLockoutPolicy(repoPolicy) + return PasswordLockoutPolicyToModel(repoPolicy), nil +} + +func (es *PolicyEventstore) UpdatePasswordLockoutPolicy(ctx context.Context, policy *pol_model.PasswordLockoutPolicy) (*pol_model.PasswordLockoutPolicy, error) { + if !policy.IsValid() { + return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "Description is required") + } + ctxData := auth.GetCtxData(ctx) + existingPolicy, err := es.GetPasswordLockoutPolicy(ctx, ctxData.OrgID) + if err != nil { + return nil, err + } + if existingPolicy.Sequence <= 0 { + return es.CreatePasswordLockoutPolicy(ctx, policy) + } + repoExisting := PasswordLockoutPolicyFromModel(existingPolicy) + repoNew := PasswordLockoutPolicyFromModel(policy) + + updateAggregate := PasswordLockoutPolicyUpdateAggregate(es.AggregateCreator(), repoExisting, repoNew) + err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, updateAggregate) + if err != nil { + return nil, err + } + + es.policyCache.cacheLockoutPolicy(repoExisting) + return PasswordLockoutPolicyToModel(repoExisting), nil +} diff --git a/internal/policy/repository/eventsourcing/eventstore_lockout_mock_test.go b/internal/policy/repository/eventsourcing/eventstore_lockout_mock_test.go new file mode 100644 index 0000000000..830ca4cfcb --- /dev/null +++ b/internal/policy/repository/eventsourcing/eventstore_lockout_mock_test.go @@ -0,0 +1,63 @@ +package eventsourcing + +import ( + "encoding/json" + + mock_cache "github.com/caos/zitadel/internal/cache/mock" + "github.com/caos/zitadel/internal/eventstore/mock" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/policy/model" + "github.com/golang/mock/gomock" +) + +func GetMockedEventstoreLockout(ctrl *gomock.Controller, mockEs *mock.MockEventstore) *PolicyEventstore { + return &PolicyEventstore{ + Eventstore: mockEs, + policyCache: GetMockCacheLockout(ctrl), + } +} + +func GetMockCacheLockout(ctrl *gomock.Controller) *PolicyCache { + mockCache := mock_cache.NewMockCache(ctrl) + mockCache.EXPECT().Get(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + mockCache.EXPECT().Set(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + return &PolicyCache{policyCache: mockCache} +} + +func GetMockGetPasswordLockoutPolicyOK(ctrl *gomock.Controller) *PolicyEventstore { + data, _ := json.Marshal(model.PasswordLockoutPolicy{Description: "Name"}) + events := []*es_models.Event{ + &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.PasswordLockoutPolicyAdded, Data: data}, + } + mockEs := mock.NewMockEventstore(ctrl) + mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) + return GetMockedEventstoreLockout(ctrl, mockEs) +} + +func GetMockGetPasswordLockoutPolicyNoEvents(ctrl *gomock.Controller) *PolicyEventstore { + events := []*es_models.Event{} + mockEs := mock.NewMockEventstore(ctrl) + mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) + return GetMockedEventstoreLockout(ctrl, mockEs) +} + +func GetMockPasswordLockoutPolicy(ctrl *gomock.Controller) *PolicyEventstore { + data, _ := json.Marshal(model.PasswordLockoutPolicy{Description: "Name"}) + events := []*es_models.Event{ + &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.PasswordLockoutPolicyAdded, Data: data}, + } + mockEs := mock.NewMockEventstore(ctrl) + mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) + mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST")) + mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil) + return GetMockedEventstoreLockout(ctrl, mockEs) +} + +func GetMockPasswordLockoutPolicyNoEvents(ctrl *gomock.Controller) *PolicyEventstore { + events := []*es_models.Event{} + mockEs := mock.NewMockEventstore(ctrl) + mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) + mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST")) + mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil) + return GetMockedEventstoreLockout(ctrl, mockEs) +} diff --git a/internal/policy/repository/eventsourcing/eventstore_lockout_test.go b/internal/policy/repository/eventsourcing/eventstore_lockout_test.go new file mode 100644 index 0000000000..e43456735c --- /dev/null +++ b/internal/policy/repository/eventsourcing/eventstore_lockout_test.go @@ -0,0 +1,192 @@ +package eventsourcing + +import ( + "context" + "testing" + + "github.com/caos/zitadel/internal/api/auth" + caos_errs "github.com/caos/zitadel/internal/errors" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/policy/model" + "github.com/golang/mock/gomock" +) + +func TestGetPasswordLockoutPolicy(t *testing.T) { + ctrl := gomock.NewController(t) + type args struct { + es *PolicyEventstore + policy *model.PasswordLockoutPolicy + } + type res struct { + policy *model.PasswordLockoutPolicy + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "policy from events, ok", + args: args{ + es: GetMockGetPasswordLockoutPolicyOK(ctrl), + policy: &model.PasswordLockoutPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}}, + }, + res: res{ + policy: &model.PasswordLockoutPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}}, + }, + }, + { + name: "policy from events, no events", + args: args{ + es: GetMockGetPasswordLockoutPolicyNoEvents(ctrl), + policy: &model.PasswordLockoutPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 2}}, + }, + res: res{ + wantErr: true, + errFunc: caos_errs.IsNotFound, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := tt.args.es.GetPasswordLockoutPolicy(nil, tt.args.policy.AggregateID) + + if !tt.res.wantErr && result.AggregateID != tt.res.policy.AggregateID { + t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.res.policy.AggregateID, result.AggregateID) + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + +func TestCreatePasswordLockoutPolicy(t *testing.T) { + ctrl := gomock.NewController(t) + type args struct { + es *PolicyEventstore + ctx context.Context + policy *model.PasswordLockoutPolicy + } + type res struct { + policy *model.PasswordLockoutPolicy + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "create policy, ok", + args: args{ + es: GetMockPasswordLockoutPolicyNoEvents(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &model.PasswordLockoutPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID1", Sequence: 2}, Description: "Name"}, + }, + res: res{ + policy: &model.PasswordLockoutPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID1", Sequence: 2}, Description: "Name"}, + }, + }, + { + name: "create policy no name", + args: args{ + es: GetMockPasswordLockoutPolicyNoEvents(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &model.PasswordLockoutPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}}, + }, + res: res{ + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := tt.args.es.CreatePasswordLockoutPolicy(tt.args.ctx, tt.args.policy) + + if !tt.res.wantErr && result.AggregateID == "" { + t.Errorf("result has no id") + } + if !tt.res.wantErr && result.Description != tt.res.policy.Description { + t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.res.policy.Description, result.Description) + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + +func TestUpdatePasswordLockoutPolicy(t *testing.T) { + ctrl := gomock.NewController(t) + type args struct { + es *PolicyEventstore + ctx context.Context + new *model.PasswordLockoutPolicy + } + type res struct { + policy *model.PasswordLockoutPolicy + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "update policy, ok", + args: args{ + es: GetMockPasswordLockoutPolicy(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + new: &model.PasswordLockoutPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Description: "NameNew"}, + }, + res: res{ + policy: &model.PasswordLockoutPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Description: "NameNew"}, + }, + }, + { + name: "update policy no name", + args: args{ + es: GetMockPasswordLockoutPolicy(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + new: &model.PasswordLockoutPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Description: ""}, + }, + res: res{ + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + { + name: "existing policy not found", + args: args{ + es: GetMockPasswordLockoutPolicyNoEvents(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + new: &model.PasswordLockoutPolicy{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Description: "NameNew"}, + }, + res: res{ + wantErr: true, + errFunc: caos_errs.IsNotFound, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := tt.args.es.UpdatePasswordLockoutPolicy(tt.args.ctx, tt.args.new) + + if !tt.res.wantErr && result.AggregateID == "" { + t.Errorf("result has no id") + } + if !tt.res.wantErr && result.Description != tt.res.policy.Description { + t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.res.policy.Description, result.Description) + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} diff --git a/internal/policy/repository/eventsourcing/model_age.go b/internal/policy/repository/eventsourcing/model_age.go new file mode 100644 index 0000000000..b2d06b0682 --- /dev/null +++ b/internal/policy/repository/eventsourcing/model_age.go @@ -0,0 +1,80 @@ +package eventsourcing + +import ( + "encoding/json" + + "github.com/caos/logging" + "github.com/caos/zitadel/internal/eventstore/models" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/policy/model" +) + +const ( + policyAgeVersion = "v1" +) + +type PasswordAgePolicy struct { + models.ObjectRoot + + Description string `json:"description,omitempty"` + State int32 `json:"-"` + MaxAgeDays uint64 `json:"maxAgeDays"` + ExpireWarnDays uint64 `json:"expireWarnDays"` +} + +func (p *PasswordAgePolicy) AgeChanges(changed *PasswordAgePolicy) map[string]interface{} { + changes := make(map[string]interface{}, 1) + if changed.Description != "" && p.Description != changed.Description { + changes["description"] = changed.Description + } + if p.MaxAgeDays != changed.MaxAgeDays { + changes["maxAgeDays"] = changed.MaxAgeDays + } + if p.ExpireWarnDays != changed.ExpireWarnDays { + changes["expireWarnDays"] = changed.ExpireWarnDays + } + return changes +} + +func PasswordAgePolicyFromModel(policy *model.PasswordAgePolicy) *PasswordAgePolicy { + return &PasswordAgePolicy{ + ObjectRoot: policy.ObjectRoot, + Description: policy.Description, + State: int32(policy.State), + MaxAgeDays: policy.MaxAgeDays, + ExpireWarnDays: policy.ExpireWarnDays, + } +} + +func PasswordAgePolicyToModel(policy *PasswordAgePolicy) *model.PasswordAgePolicy { + return &model.PasswordAgePolicy{ + ObjectRoot: policy.ObjectRoot, + Description: policy.Description, + State: model.PolicyState(policy.State), + MaxAgeDays: policy.MaxAgeDays, + ExpireWarnDays: policy.ExpireWarnDays, + } +} + +func (p *PasswordAgePolicy) AppendEvents(events ...*es_models.Event) error { + for _, event := range events { + if err := p.AppendEvent(event); err != nil { + return err + } + } + return nil +} + +func (p *PasswordAgePolicy) AppendEvent(event *es_models.Event) error { + p.ObjectRoot.AppendEvent(event) + + switch event.Type { + case model.PasswordAgePolicyAdded, model.PasswordAgePolicyChanged: + if err := json.Unmarshal(event.Data, p); err != nil { + logging.Log("EVEN-idl93").WithError(err).Error("could not unmarshal event data") + return err + } + return nil + } + return nil +} diff --git a/internal/policy/repository/eventsourcing/model_complexity.go b/internal/policy/repository/eventsourcing/model_complexity.go new file mode 100644 index 0000000000..0c49a1c8e8 --- /dev/null +++ b/internal/policy/repository/eventsourcing/model_complexity.go @@ -0,0 +1,98 @@ +package eventsourcing + +import ( + "encoding/json" + + "github.com/caos/logging" + "github.com/caos/zitadel/internal/eventstore/models" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/policy/model" +) + +const ( + policyComplexityVersion = "v1" +) + +type PasswordComplexityPolicy struct { + models.ObjectRoot + + Description string `json:"description,omitempty"` + State int32 `json:"-"` + MinLength uint64 `json:"minLength"` + HasLowercase bool `json:"hasLowercase"` + HasUppercase bool `json:"hasUppercase"` + HasNumber bool `json:"hasNumber"` + HasSymbol bool `json:"hasSymbol"` +} + +func (p *PasswordComplexityPolicy) ComplexityChanges(changed *PasswordComplexityPolicy) map[string]interface{} { + changes := make(map[string]interface{}, 1) + if changed.Description != "" && p.Description != changed.Description { + changes["description"] = changed.Description + } + if p.MinLength != changed.MinLength { + changes["minLength"] = changed.MinLength + } + if p.HasLowercase != changed.HasLowercase { + changes["hasLowercase"] = changed.HasLowercase + } + if p.HasUppercase != changed.HasUppercase { + changes["hasUppercase"] = changed.HasUppercase + } + if p.HasNumber != changed.HasNumber { + changes["hasNumber"] = changed.HasNumber + } + if p.HasSymbol != changed.HasSymbol { + changes["hasSymbol"] = changed.HasSymbol + } + return changes +} + +func PasswordComplexityPolicyFromModel(policy *model.PasswordComplexityPolicy) *PasswordComplexityPolicy { + return &PasswordComplexityPolicy{ + ObjectRoot: policy.ObjectRoot, + Description: policy.Description, + State: int32(policy.State), + MinLength: policy.MinLength, + HasLowercase: policy.HasLowercase, + HasUppercase: policy.HasUppercase, + HasNumber: policy.HasNumber, + HasSymbol: policy.HasSymbol, + } +} + +func PasswordComplexityPolicyToModel(policy *PasswordComplexityPolicy) *model.PasswordComplexityPolicy { + return &model.PasswordComplexityPolicy{ + ObjectRoot: policy.ObjectRoot, + Description: policy.Description, + State: model.PolicyState(policy.State), + MinLength: policy.MinLength, + HasLowercase: policy.HasLowercase, + HasUppercase: policy.HasUppercase, + HasNumber: policy.HasNumber, + HasSymbol: policy.HasSymbol, + } +} + +func (p *PasswordComplexityPolicy) AppendEvents(events ...*es_models.Event) error { + for _, event := range events { + if err := p.AppendEvent(event); err != nil { + return err + } + } + return nil +} + +func (p *PasswordComplexityPolicy) AppendEvent(event *es_models.Event) error { + p.ObjectRoot.AppendEvent(event) + + switch event.Type { + case model.PasswordComplexityPolicyAdded, model.PasswordComplexityPolicyChanged: + if err := json.Unmarshal(event.Data, p); err != nil { + logging.Log("EVEN-idl93").WithError(err).Error("could not unmarshal event data") + return err + } + return nil + } + return nil +} diff --git a/internal/policy/repository/eventsourcing/model_lockout.go b/internal/policy/repository/eventsourcing/model_lockout.go new file mode 100644 index 0000000000..5d28d6124b --- /dev/null +++ b/internal/policy/repository/eventsourcing/model_lockout.go @@ -0,0 +1,80 @@ +package eventsourcing + +import ( + "encoding/json" + + "github.com/caos/logging" + "github.com/caos/zitadel/internal/eventstore/models" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/policy/model" +) + +const ( + policyLockoutVersion = "v1" +) + +type PasswordLockoutPolicy struct { + models.ObjectRoot + + Description string `json:"description,omitempty"` + State int32 `json:"-"` + MaxAttempts uint64 `json:"maxAttempts"` + ShowLockOutFailures bool `json:"showLockOutFailures"` +} + +func (p *PasswordLockoutPolicy) LockoutChanges(changed *PasswordLockoutPolicy) map[string]interface{} { + changes := make(map[string]interface{}, 1) + if changed.Description != "" && p.Description != changed.Description { + changes["description"] = changed.Description + } + if p.MaxAttempts != changed.MaxAttempts { + changes["maxAttempts"] = changed.MaxAttempts + } + if p.ShowLockOutFailures != changed.ShowLockOutFailures { + changes["showLockOutFailures"] = changed.ShowLockOutFailures + } + return changes +} + +func PasswordLockoutPolicyFromModel(policy *model.PasswordLockoutPolicy) *PasswordLockoutPolicy { + return &PasswordLockoutPolicy{ + ObjectRoot: policy.ObjectRoot, + Description: policy.Description, + State: int32(policy.State), + MaxAttempts: policy.MaxAttempts, + ShowLockOutFailures: policy.ShowLockOutFailures, + } +} + +func PasswordLockoutPolicyToModel(policy *PasswordLockoutPolicy) *model.PasswordLockoutPolicy { + return &model.PasswordLockoutPolicy{ + ObjectRoot: policy.ObjectRoot, + Description: policy.Description, + State: model.PolicyState(policy.State), + MaxAttempts: policy.MaxAttempts, + ShowLockOutFailures: policy.ShowLockOutFailures, + } +} + +func (p *PasswordLockoutPolicy) AppendEvents(events ...*es_models.Event) error { + for _, event := range events { + if err := p.AppendEvent(event); err != nil { + return err + } + } + return nil +} + +func (p *PasswordLockoutPolicy) AppendEvent(event *es_models.Event) error { + p.ObjectRoot.AppendEvent(event) + + switch event.Type { + case model.PasswordLockoutPolicyAdded, model.PasswordLockoutPolicyChanged: + if err := json.Unmarshal(event.Data, p); err != nil { + logging.Log("EVEN-idl93").WithError(err).Error("could not unmarshal event data") + return err + } + return nil + } + return nil +} diff --git a/internal/policy/repository/eventsourcing/policy_age.go b/internal/policy/repository/eventsourcing/policy_age.go new file mode 100644 index 0000000000..199e343a20 --- /dev/null +++ b/internal/policy/repository/eventsourcing/policy_age.go @@ -0,0 +1,52 @@ +package eventsourcing + +import ( + "context" + + "github.com/caos/zitadel/internal/errors" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/policy/model" +) + +func PasswordAgePolicyQuery(recourceOwner string, latestSequence uint64) *es_models.SearchQuery { + return es_models.NewSearchQuery(). + AggregateTypeFilter(model.PasswordAgePolicyAggregate). + LatestSequenceFilter(latestSequence). + ResourceOwnerFilter(recourceOwner) + +} + +func PasswordAgePolicyAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, policy *PasswordAgePolicy) (*es_models.Aggregate, error) { + if policy == nil { + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-1T05i", "existing policy should not be nil") + } + return aggCreator.NewAggregate(ctx, policy.AggregateID, model.PasswordAgePolicyAggregate, policyAgeVersion, policy.Sequence) +} + +func PasswordAgePolicyCreateAggregate(aggCreator *es_models.AggregateCreator, policy *PasswordAgePolicy) func(ctx context.Context) (*es_models.Aggregate, error) { + return func(ctx context.Context) (*es_models.Aggregate, error) { + if policy == nil { + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-kdie6", "policy should not be nil") + } + agg, err := PasswordAgePolicyAggregate(ctx, aggCreator, policy) + if err != nil { + return nil, err + } + + return agg.AppendEvent(model.PasswordAgePolicyAdded, policy) + } +} + +func PasswordAgePolicyUpdateAggregate(aggCreator *es_models.AggregateCreator, existing *PasswordAgePolicy, new *PasswordAgePolicy) func(ctx context.Context) (*es_models.Aggregate, error) { + return func(ctx context.Context) (*es_models.Aggregate, error) { + if new == nil { + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dhr74", "new policy should not be nil") + } + agg, err := PasswordAgePolicyAggregate(ctx, aggCreator, existing) + if err != nil { + return nil, err + } + changes := existing.AgeChanges(new) + return agg.AppendEvent(model.PasswordAgePolicyChanged, changes) + } +} diff --git a/internal/policy/repository/eventsourcing/policy_age_test.go b/internal/policy/repository/eventsourcing/policy_age_test.go new file mode 100644 index 0000000000..6357e2347e --- /dev/null +++ b/internal/policy/repository/eventsourcing/policy_age_test.go @@ -0,0 +1,268 @@ +package eventsourcing + +import ( + "context" + "testing" + + "github.com/caos/zitadel/internal/api/auth" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/models" + policy_model "github.com/caos/zitadel/internal/policy/model" +) + +func TestGetPasswordAgePolicyQuery(t *testing.T) { + type args struct { + recourceOwner string + sequence uint64 + } + type res struct { + filterLen int + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "Get password age policy query ok", + args: args{ + recourceOwner: "org", + sequence: 14, + }, + res: res{ + filterLen: 3, + }, + }, + { + name: "Get password age policy query, no org", + args: args{ + sequence: 1, + }, + res: res{ + filterLen: 3, + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + query := PasswordAgePolicyQuery(tt.args.recourceOwner, tt.args.sequence) + if !tt.res.wantErr && query == nil { + t.Errorf("query should not be nil") + } + if !tt.res.wantErr && len(query.Filters) != tt.res.filterLen { + t.Errorf("got wrong filter len: expected: %v, actual: %v ", tt.res.filterLen, len(query.Filters)) + } + }) + } +} + +func TestPasswordAgePolicyAggregate(t *testing.T) { + + type args struct { + ctx context.Context + aggCreator *models.AggregateCreator + policy *PasswordAgePolicy + } + type res struct { + eventLen int + aggType models.AggregateType + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "create aggregate", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + aggCreator: models.NewAggregateCreator("Test"), + policy: &PasswordAgePolicy{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Description: "Test"}, + }, + res: res{ + eventLen: 0, + aggType: policy_model.PasswordAgePolicyAggregate, + }, + }, + { + name: "policy nil", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 0, + aggType: policy_model.PasswordAgePolicyAggregate, + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := PasswordAgePolicyAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.policy) + + if !tt.res.wantErr && agg == nil { + t.Errorf("agg should not be nil") + } + if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + +func TestPasswordAgePolicyCreateAggregate(t *testing.T) { + type args struct { + ctx context.Context + new *PasswordAgePolicy + aggCreator *models.AggregateCreator + } + type res struct { + eventLen int + eventType models.EventType + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "policy update aggregate ok", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + new: &PasswordAgePolicy{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Description: "PolicyName", State: int32(policy_model.POLICYSTATE_ACTIVE)}, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: policy_model.PasswordAgePolicyAdded, + }, + }, + { + name: "new policy nil", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + new: nil, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: policy_model.PasswordAgePolicyAdded, + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := PasswordAgePolicyCreateAggregate(tt.args.aggCreator, tt.args.new)(tt.args.ctx) + + if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + if !tt.res.wantErr && agg.Events[0].Type != tt.res.eventType { + t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String()) + } + if !tt.res.wantErr && agg.Events[0].Data == nil { + t.Errorf("should have data in event") + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + +func TestPasswordAgePolicyUpdateAggregate(t *testing.T) { + type args struct { + ctx context.Context + existing *PasswordAgePolicy + new *PasswordAgePolicy + aggCreator *models.AggregateCreator + } + type res struct { + eventLen int + eventType models.EventType + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "policy update aggregate ok", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &PasswordAgePolicy{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Description: "PolicyName", State: int32(policy_model.POLICYSTATE_ACTIVE)}, + new: &PasswordAgePolicy{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Description: "PolicyName_Changed", State: int32(policy_model.POLICYSTATE_ACTIVE)}, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: policy_model.PasswordAgePolicyChanged, + }, + }, + { + name: "existing policy nil", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: nil, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: policy_model.PasswordAgePolicyChanged, + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + { + name: "new policy nil", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &PasswordAgePolicy{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Description: "ProjectName", State: int32(policy_model.POLICYSTATE_ACTIVE)}, + new: nil, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: policy_model.PasswordAgePolicyChanged, + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := PasswordAgePolicyUpdateAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx) + + if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + if !tt.res.wantErr && agg.Events[0].Type != tt.res.eventType { + t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String()) + } + if !tt.res.wantErr && agg.Events[0].Data == nil { + t.Errorf("should have data in event") + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} diff --git a/internal/policy/repository/eventsourcing/policy_complexity.go b/internal/policy/repository/eventsourcing/policy_complexity.go new file mode 100644 index 0000000000..6d14cb747f --- /dev/null +++ b/internal/policy/repository/eventsourcing/policy_complexity.go @@ -0,0 +1,52 @@ +package eventsourcing + +import ( + "context" + + "github.com/caos/zitadel/internal/errors" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/policy/model" +) + +func PasswordComplexityPolicyQuery(recourceOwner string, latestSequence uint64) *es_models.SearchQuery { + return es_models.NewSearchQuery(). + AggregateTypeFilter(model.PasswordComplexityPolicyAggregate). + LatestSequenceFilter(latestSequence). + ResourceOwnerFilter(recourceOwner) + +} + +func PasswordComplexityPolicyAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, policy *PasswordComplexityPolicy) (*es_models.Aggregate, error) { + if policy == nil { + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-fRVr9", "existing policy should not be nil") + } + return aggCreator.NewAggregate(ctx, policy.AggregateID, model.PasswordComplexityPolicyAggregate, policyComplexityVersion, policy.Sequence) +} + +func PasswordComplexityPolicyCreateAggregate(aggCreator *es_models.AggregateCreator, policy *PasswordComplexityPolicy) func(ctx context.Context) (*es_models.Aggregate, error) { + return func(ctx context.Context) (*es_models.Aggregate, error) { + if policy == nil { + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-kdie6", "policy should not be nil") + } + agg, err := PasswordComplexityPolicyAggregate(ctx, aggCreator, policy) + if err != nil { + return nil, err + } + + return agg.AppendEvent(model.PasswordComplexityPolicyAdded, policy) + } +} + +func PasswordComplexityPolicyUpdateAggregate(aggCreator *es_models.AggregateCreator, existing *PasswordComplexityPolicy, new *PasswordComplexityPolicy) func(ctx context.Context) (*es_models.Aggregate, error) { + return func(ctx context.Context) (*es_models.Aggregate, error) { + if new == nil { + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dhr74", "new policy should not be nil") + } + agg, err := PasswordComplexityPolicyAggregate(ctx, aggCreator, existing) + if err != nil { + return nil, err + } + changes := existing.ComplexityChanges(new) + return agg.AppendEvent(model.PasswordComplexityPolicyChanged, changes) + } +} diff --git a/internal/policy/repository/eventsourcing/policy_complexity_test.go b/internal/policy/repository/eventsourcing/policy_complexity_test.go new file mode 100644 index 0000000000..369b90d75f --- /dev/null +++ b/internal/policy/repository/eventsourcing/policy_complexity_test.go @@ -0,0 +1,268 @@ +package eventsourcing + +import ( + "context" + "testing" + + "github.com/caos/zitadel/internal/api/auth" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/models" + policy_model "github.com/caos/zitadel/internal/policy/model" +) + +func TestPasswordComplexityPolicyQuery(t *testing.T) { + type args struct { + recourceOwner string + sequence uint64 + } + type res struct { + filterLen int + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "Get password complexity policy query ok", + args: args{ + recourceOwner: "org", + sequence: 0, + }, + res: res{ + filterLen: 3, + }, + }, + { + name: "Get password complexity policy query, no org", + args: args{ + sequence: 1, + }, + res: res{ + filterLen: 3, + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + query := PasswordComplexityPolicyQuery(tt.args.recourceOwner, tt.args.sequence) + if !tt.res.wantErr && query == nil { + t.Errorf("query should not be nil") + } + if !tt.res.wantErr && len(query.Filters) != tt.res.filterLen { + t.Errorf("got wrong filter len: expected: %v, actual: %v ", tt.res.filterLen, len(query.Filters)) + } + }) + } +} + +func TestPasswordComplexityPolicyAggregate(t *testing.T) { + + type args struct { + ctx context.Context + aggCreator *models.AggregateCreator + policy *PasswordComplexityPolicy + } + type res struct { + eventLen int + aggType models.AggregateType + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "create aggregate", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + aggCreator: models.NewAggregateCreator("Test"), + policy: &PasswordComplexityPolicy{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Description: "Test"}, + }, + res: res{ + eventLen: 0, + aggType: policy_model.PasswordComplexityPolicyAggregate, + }, + }, + { + name: "policy nil", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 0, + aggType: policy_model.PasswordComplexityPolicyAggregate, + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := PasswordComplexityPolicyAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.policy) + + if !tt.res.wantErr && agg == nil { + t.Errorf("agg should not be nil") + } + if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + +func TestPasswordComplexityPolicyCreateAggregate(t *testing.T) { + type args struct { + ctx context.Context + new *PasswordComplexityPolicy + aggCreator *models.AggregateCreator + } + type res struct { + eventLen int + eventType models.EventType + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "policy update aggregate ok", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + new: &PasswordComplexityPolicy{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Description: "PolicyName", State: int32(policy_model.POLICYSTATE_ACTIVE)}, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: policy_model.PasswordComplexityPolicyAdded, + }, + }, + { + name: "new policy nil", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + new: nil, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: policy_model.PasswordComplexityPolicyAdded, + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := PasswordComplexityPolicyCreateAggregate(tt.args.aggCreator, tt.args.new)(tt.args.ctx) + + if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + if !tt.res.wantErr && agg.Events[0].Type != tt.res.eventType { + t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String()) + } + if !tt.res.wantErr && agg.Events[0].Data == nil { + t.Errorf("should have data in event") + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + +func TestPasswordComplexityPolicyUpdateAggregate(t *testing.T) { + type args struct { + ctx context.Context + existing *PasswordComplexityPolicy + new *PasswordComplexityPolicy + aggCreator *models.AggregateCreator + } + type res struct { + eventLen int + eventType models.EventType + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "policy update aggregate ok", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &PasswordComplexityPolicy{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Description: "PolicyName", State: int32(policy_model.POLICYSTATE_ACTIVE)}, + new: &PasswordComplexityPolicy{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Description: "PolicyName_Changed", State: int32(policy_model.POLICYSTATE_ACTIVE)}, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: policy_model.PasswordComplexityPolicyChanged, + }, + }, + { + name: "existing policy nil", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: nil, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: policy_model.PasswordComplexityPolicyChanged, + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + { + name: "new policy nil", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &PasswordComplexityPolicy{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Description: "ProjectName", State: int32(policy_model.POLICYSTATE_ACTIVE)}, + new: nil, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: policy_model.PasswordComplexityPolicyChanged, + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := PasswordComplexityPolicyUpdateAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx) + + if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + if !tt.res.wantErr && agg.Events[0].Type != tt.res.eventType { + t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String()) + } + if !tt.res.wantErr && agg.Events[0].Data == nil { + t.Errorf("should have data in event") + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} diff --git a/internal/policy/repository/eventsourcing/policy_lockout.go b/internal/policy/repository/eventsourcing/policy_lockout.go new file mode 100644 index 0000000000..7947dacd11 --- /dev/null +++ b/internal/policy/repository/eventsourcing/policy_lockout.go @@ -0,0 +1,53 @@ +package eventsourcing + +import ( + "context" + + "github.com/caos/zitadel/internal/errors" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/policy/model" +) + +func PasswordLockoutPolicyQuery(recourceOwner string, latestSequence uint64) *es_models.SearchQuery { + return es_models.NewSearchQuery(). + AggregateTypeFilter(model.PasswordLockoutPolicyAggregate). + LatestSequenceFilter(latestSequence). + ResourceOwnerFilter(recourceOwner) + +} + +func PasswordLockoutPolicyAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, policy *PasswordLockoutPolicy) (*es_models.Aggregate, error) { + if policy == nil { + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-aTRlj", "existing policy should not be nil") + } + return aggCreator.NewAggregate(ctx, policy.AggregateID, model.PasswordLockoutPolicyAggregate, policyLockoutVersion, policy.Sequence) +} + +func PasswordLockoutPolicyCreateAggregate(aggCreator *es_models.AggregateCreator, policy *PasswordLockoutPolicy) func(ctx context.Context) (*es_models.Aggregate, error) { + return func(ctx context.Context) (*es_models.Aggregate, error) { + if policy == nil { + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-kdie6", "policy should not be nil") + } + + agg, err := PasswordLockoutPolicyAggregate(ctx, aggCreator, policy) + if err != nil { + return nil, err + } + + return agg.AppendEvent(model.PasswordLockoutPolicyAdded, policy) + } +} + +func PasswordLockoutPolicyUpdateAggregate(aggCreator *es_models.AggregateCreator, existing *PasswordLockoutPolicy, new *PasswordLockoutPolicy) func(ctx context.Context) (*es_models.Aggregate, error) { + return func(ctx context.Context) (*es_models.Aggregate, error) { + if new == nil { + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dhr74", "new policy should not be nil") + } + agg, err := PasswordLockoutPolicyAggregate(ctx, aggCreator, existing) + if err != nil { + return nil, err + } + changes := existing.LockoutChanges(new) + return agg.AppendEvent(model.PasswordLockoutPolicyChanged, changes) + } +} diff --git a/internal/policy/repository/eventsourcing/policy_lockout_test.go b/internal/policy/repository/eventsourcing/policy_lockout_test.go new file mode 100644 index 0000000000..9d9d19d8f8 --- /dev/null +++ b/internal/policy/repository/eventsourcing/policy_lockout_test.go @@ -0,0 +1,268 @@ +package eventsourcing + +import ( + "context" + "testing" + + "github.com/caos/zitadel/internal/api/auth" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/models" + policy_model "github.com/caos/zitadel/internal/policy/model" +) + +func TestGetPasswordLockoutPolicyQuery(t *testing.T) { + type args struct { + recourceOwner string + sequence uint64 + } + type res struct { + filterLen int + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "Get password lockout policy query ok", + args: args{ + recourceOwner: "org", + sequence: 14, + }, + res: res{ + filterLen: 3, + }, + }, + { + name: "Get password lockout policy query, no org", + args: args{ + sequence: 1, + }, + res: res{ + filterLen: 3, + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + query := PasswordLockoutPolicyQuery(tt.args.recourceOwner, tt.args.sequence) + if !tt.res.wantErr && query == nil { + t.Errorf("query should not be nil") + } + if !tt.res.wantErr && len(query.Filters) != tt.res.filterLen { + t.Errorf("got wrong filter len: expected: %v, actual: %v ", tt.res.filterLen, len(query.Filters)) + } + }) + } +} + +func TestPasswordLockoutPolicyAggregate(t *testing.T) { + + type args struct { + ctx context.Context + aggCreator *models.AggregateCreator + policy *PasswordLockoutPolicy + } + type res struct { + eventLen int + aggType models.AggregateType + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "create aggregate", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + aggCreator: models.NewAggregateCreator("Test"), + policy: &PasswordLockoutPolicy{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Description: "Test"}, + }, + res: res{ + eventLen: 0, + aggType: policy_model.PasswordLockoutPolicyAggregate, + }, + }, + { + name: "policy nil", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 0, + aggType: policy_model.PasswordLockoutPolicyAggregate, + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := PasswordLockoutPolicyAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.policy) + + if !tt.res.wantErr && agg == nil { + t.Errorf("agg should not be nil") + } + if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + +func TestPasswordLockoutPolicyCreateAggregate(t *testing.T) { + type args struct { + ctx context.Context + new *PasswordLockoutPolicy + aggCreator *models.AggregateCreator + } + type res struct { + eventLen int + eventType models.EventType + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "policy update aggregate ok", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + new: &PasswordLockoutPolicy{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Description: "PolicyName", State: int32(policy_model.POLICYSTATE_ACTIVE)}, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: policy_model.PasswordLockoutPolicyAdded, + }, + }, + { + name: "new policy nil", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + new: nil, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: policy_model.PasswordLockoutPolicyAdded, + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := PasswordLockoutPolicyCreateAggregate(tt.args.aggCreator, tt.args.new)(tt.args.ctx) + + if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + if !tt.res.wantErr && agg.Events[0].Type != tt.res.eventType { + t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String()) + } + if !tt.res.wantErr && agg.Events[0].Data == nil { + t.Errorf("should have data in event") + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + +func TestPasswordLockoutPolicyUpdateAggregate(t *testing.T) { + type args struct { + ctx context.Context + existing *PasswordLockoutPolicy + new *PasswordLockoutPolicy + aggCreator *models.AggregateCreator + } + type res struct { + eventLen int + eventType models.EventType + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "policy update aggregate ok", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &PasswordLockoutPolicy{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Description: "PolicyName", State: int32(policy_model.POLICYSTATE_ACTIVE)}, + new: &PasswordLockoutPolicy{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Description: "PolicyName_Changed", State: int32(policy_model.POLICYSTATE_ACTIVE)}, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: policy_model.PasswordLockoutPolicyChanged, + }, + }, + { + name: "existing policy nil", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: nil, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: policy_model.PasswordLockoutPolicyChanged, + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + { + name: "new policy nil", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &PasswordLockoutPolicy{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Description: "ProjectName", State: int32(policy_model.POLICYSTATE_ACTIVE)}, + new: nil, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: policy_model.PasswordLockoutPolicyChanged, + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := PasswordLockoutPolicyUpdateAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx) + + if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + if !tt.res.wantErr && agg.Events[0].Type != tt.res.eventType { + t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String()) + } + if !tt.res.wantErr && agg.Events[0].Data == nil { + t.Errorf("should have data in event") + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} diff --git a/internal/protoc/protoc-gen-authoption/templates.go b/internal/protoc/protoc-gen-authoption/templates.go index 3aa6428c32..e7b7e1f09d 100644 --- a/internal/protoc/protoc-gen-authoption/templates.go +++ b/internal/protoc/protoc-gen-authoption/templates.go @@ -83,7 +83,7 @@ func templatesAuth_method_mappingGoTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/auth_method_mapping.go.tmpl", size: 1013, mode: os.FileMode(420), modTime: time.Unix(1586159062, 0)} + info := bindataFileInfo{name: "templates/auth_method_mapping.go.tmpl", size: 1013, mode: os.FileMode(420), modTime: time.Unix(1586333177, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/pkg/management/api/grpc/generate.go b/pkg/management/api/grpc/generate.go index bd7c2b5b89..9fbf77c29f 100644 --- a/pkg/management/api/grpc/generate.go +++ b/pkg/management/api/grpc/generate.go @@ -1,4 +1,4 @@ package grpc //go:generate protoc -I$GOPATH/src -I../proto -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis -I${GOPATH}/src/github.com/envoyproxy/protoc-gen-validate -I${GOPATH}/src/github.com/caos/zitadel/internal/protoc/protoc-gen-authoption --go_out=plugins=grpc:$GOPATH/src --grpc-gateway_out=logtostderr=true:$GOPATH/src --swagger_out=logtostderr=true:. --authoption_out=. ../proto/management.proto -//go:generate mockgen -package api -destination ./mock/management.proto.mock.go github.com/caos/zitadel/pkg/management/api/grpc ManagementServiceClient \ No newline at end of file +//go:generate mockgen -package api -destination ./mock/management.proto.mock.go github.com/caos/zitadel/pkg/management/api/grpc ManagementServiceClient diff --git a/pkg/management/api/grpc/management.pb.go b/pkg/management/api/grpc/management.pb.go index e4a1dda9a6..9b722d0f97 100644 --- a/pkg/management/api/grpc/management.pb.go +++ b/pkg/management/api/grpc/management.pb.go @@ -3000,6 +3000,7 @@ type PasswordComplexityPolicy struct { HasNumber bool `protobuf:"varint,9,opt,name=has_number,json=hasNumber,proto3" json:"has_number,omitempty"` HasSymbol bool `protobuf:"varint,10,opt,name=has_symbol,json=hasSymbol,proto3" json:"has_symbol,omitempty"` Sequence uint64 `protobuf:"varint,11,opt,name=sequence,proto3" json:"sequence,omitempty"` + IsDefault bool `protobuf:"varint,12,opt,name=is_default,json=isDefault,proto3" json:"is_default,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -3107,6 +3108,13 @@ func (m *PasswordComplexityPolicy) GetSequence() uint64 { return 0 } +func (m *PasswordComplexityPolicy) GetIsDefault() bool { + if m != nil { + return m.IsDefault + } + return false +} + type PasswordComplexityPolicyCreate struct { Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` MinLength uint64 `protobuf:"varint,2,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"` @@ -3321,6 +3329,7 @@ type PasswordAgePolicy struct { MaxAgeDays uint64 `protobuf:"varint,6,opt,name=max_age_days,json=maxAgeDays,proto3" json:"max_age_days,omitempty"` ExpireWarnDays uint64 `protobuf:"varint,7,opt,name=expire_warn_days,json=expireWarnDays,proto3" json:"expire_warn_days,omitempty"` Sequence uint64 `protobuf:"varint,8,opt,name=sequence,proto3" json:"sequence,omitempty"` + IsDefault bool `protobuf:"varint,9,opt,name=is_default,json=isDefault,proto3" json:"is_default,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -3407,6 +3416,13 @@ func (m *PasswordAgePolicy) GetSequence() uint64 { return 0 } +func (m *PasswordAgePolicy) GetIsDefault() bool { + if m != nil { + return m.IsDefault + } + return false +} + type PasswordAgePolicyCreate struct { Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` MaxAgeDays uint64 `protobuf:"varint,2,opt,name=max_age_days,json=maxAgeDays,proto3" json:"max_age_days,omitempty"` @@ -3573,6 +3589,7 @@ type PasswordLockoutPolicy struct { MaxAttempts uint64 `protobuf:"varint,6,opt,name=max_attempts,json=maxAttempts,proto3" json:"max_attempts,omitempty"` ShowLockOutFailures bool `protobuf:"varint,7,opt,name=show_lock_out_failures,json=showLockOutFailures,proto3" json:"show_lock_out_failures,omitempty"` Sequence uint64 `protobuf:"varint,8,opt,name=sequence,proto3" json:"sequence,omitempty"` + IsDefault bool `protobuf:"varint,9,opt,name=is_default,json=isDefault,proto3" json:"is_default,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -3659,6 +3676,13 @@ func (m *PasswordLockoutPolicy) GetSequence() uint64 { return 0 } +func (m *PasswordLockoutPolicy) GetIsDefault() bool { + if m != nil { + return m.IsDefault + } + return false +} + type PasswordLockoutPolicyCreate struct { Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` MaxAttempts uint64 `protobuf:"varint,2,opt,name=max_attempts,json=maxAttempts,proto3" json:"max_attempts,omitempty"` @@ -9262,534 +9286,534 @@ func init() { func init() { proto.RegisterFile("management.proto", fileDescriptor_edc174f991dc0a25) } var fileDescriptor_edc174f991dc0a25 = []byte{ - // 8430 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x7d, 0x6c, 0x5c, 0xd9, - 0x75, 0xdf, 0xbe, 0x99, 0xe1, 0xd7, 0xe1, 0xd7, 0xf0, 0xf2, 0x6b, 0x34, 0xa4, 0x28, 0xea, 0x49, - 0x5a, 0x49, 0xa3, 0x15, 0x47, 0xcb, 0xdd, 0x95, 0x76, 0x57, 0x5e, 0x69, 0x87, 0xe4, 0x88, 0x9a, - 0x2e, 0xc9, 0xa1, 0x87, 0xd4, 0xaa, 0xeb, 0x04, 0x3b, 0x1e, 0xcd, 0x3c, 0x0d, 0x27, 0x1a, 0xce, - 0x8c, 0xdf, 0x7b, 0x94, 0x96, 0xde, 0x2e, 0xda, 0xd2, 0x40, 0x11, 0x24, 0x75, 0xdb, 0x8d, 0x9b, - 0x16, 0x70, 0x9b, 0x3a, 0x36, 0xd0, 0xba, 0x48, 0xea, 0x06, 0x01, 0xcc, 0xc6, 0x6e, 0xd2, 0xc6, - 0x68, 0xda, 0xa2, 0x89, 0x5b, 0xc0, 0x41, 0x83, 0x24, 0x05, 0xd2, 0x16, 0x75, 0xda, 0xb4, 0x05, - 0x8a, 0x16, 0xfd, 0x42, 0xe1, 0xfd, 0xc3, 0x28, 0xee, 0xc7, 0x7b, 0xef, 0xde, 0xf7, 0xfd, 0x86, - 0xa4, 0xbc, 0xde, 0xdd, 0xbf, 0xc8, 0xb9, 0x9f, 0xbf, 0x73, 0xee, 0x39, 0xe7, 0x9e, 0x7b, 0xee, - 0x7d, 0xf7, 0x42, 0x72, 0xb7, 0xd2, 0xaa, 0xd4, 0x95, 0x5d, 0xa5, 0xa5, 0x2f, 0x74, 0xd4, 0xb6, - 0xde, 0x46, 0x73, 0xd5, 0x4a, 0x5b, 0x5b, 0xf8, 0x7c, 0x43, 0xaf, 0xd4, 0x94, 0xe6, 0x02, 0x97, - 0x5d, 0xe9, 0x34, 0x16, 0x1e, 0x3f, 0x9f, 0x9e, 0xad, 0xb7, 0xdb, 0xf5, 0xa6, 0x92, 0xad, 0x74, - 0x1a, 0xd9, 0x4a, 0xab, 0xd5, 0xd6, 0x2b, 0x7a, 0xa3, 0xdd, 0xd2, 0x68, 0xed, 0xf4, 0x0c, 0xcb, - 0x25, 0xbf, 0x1e, 0xec, 0x3d, 0xcc, 0x2a, 0xbb, 0x1d, 0x7d, 0x9f, 0x65, 0xce, 0xda, 0x33, 0x35, - 0x5d, 0xdd, 0xab, 0xb2, 0x8e, 0xd3, 0x67, 0xec, 0xb9, 0x7a, 0x63, 0x57, 0xd1, 0xf4, 0xca, 0x6e, - 0x87, 0x15, 0x78, 0x8e, 0xfc, 0xa9, 0x5e, 0xad, 0x2b, 0xad, 0xab, 0xda, 0x93, 0x4a, 0xbd, 0xae, - 0xa8, 0xd9, 0x76, 0x87, 0xf4, 0xee, 0x82, 0x64, 0xfa, 0x71, 0xa5, 0xd9, 0xa8, 0x55, 0x74, 0x25, - 0x6b, 0xfc, 0xc3, 0x32, 0xe6, 0xed, 0xfd, 0xd4, 0x14, 0xad, 0xaa, 0x36, 0x3a, 0x7a, 0x5b, 0x65, - 0x25, 0x52, 0x95, 0x3d, 0x7d, 0x87, 0xb6, 0x6c, 0x74, 0x40, 0x73, 0xe4, 0xb7, 0x61, 0x78, 0x79, - 0xa7, 0xd2, 0xaa, 0x2b, 0x25, 0xe5, 0x73, 0x7b, 0x8a, 0xa6, 0xa3, 0x11, 0x88, 0x35, 0x6a, 0x29, - 0x69, 0x5e, 0xba, 0x34, 0x50, 0x8a, 0x35, 0x6a, 0x68, 0x02, 0x7a, 0x9a, 0x8d, 0xdd, 0x86, 0x9e, - 0x8a, 0xcd, 0x4b, 0x97, 0x12, 0x25, 0xfa, 0x03, 0x5d, 0x84, 0x51, 0x0d, 0x57, 0x68, 0x55, 0x95, - 0x72, 0xfb, 0xe1, 0x43, 0x4d, 0xd1, 0x53, 0x71, 0x92, 0x3f, 0x62, 0x24, 0x17, 0x49, 0xaa, 0xbc, - 0x0f, 0x7d, 0xb4, 0x7d, 0x0d, 0xbd, 0x0e, 0x7d, 0x55, 0xfa, 0x6f, 0x4a, 0x9a, 0x8f, 0x5f, 0x1a, - 0x5c, 0x7c, 0x76, 0xc1, 0x7f, 0x64, 0x16, 0x18, 0x32, 0xa3, 0x1a, 0x9a, 0x82, 0x5e, 0xd6, 0x19, - 0x05, 0xc3, 0x7e, 0x59, 0x18, 0xe3, 0x1c, 0x46, 0xf9, 0x9f, 0x49, 0xd0, 0x4b, 0x5b, 0x40, 0x37, - 0x61, 0x90, 0xb6, 0x51, 0xc6, 0x6c, 0x23, 0xd4, 0x0d, 0x2e, 0xa6, 0x17, 0x28, 0xdf, 0x16, 0x0c, - 0xbe, 0x2d, 0x6c, 0x1b, 0xe3, 0x53, 0x02, 0x5a, 0x7c, 0xa5, 0xa2, 0x2b, 0xe8, 0x34, 0x80, 0xf2, - 0x58, 0x69, 0xe9, 0x65, 0x7d, 0xbf, 0xa3, 0x90, 0x9e, 0x07, 0x4a, 0x03, 0x24, 0x65, 0x7b, 0xbf, - 0xa3, 0xa0, 0x34, 0xf4, 0x1b, 0x34, 0xb3, 0xfe, 0xcd, 0xdf, 0x18, 0xb0, 0x52, 0x6b, 0xe8, 0x6d, - 0x35, 0x95, 0x20, 0xd5, 0xd8, 0x2f, 0x74, 0x05, 0x12, 0xb5, 0x8a, 0x5e, 0x49, 0xf5, 0x10, 0x20, - 0xd3, 0x0e, 0x20, 0x5b, 0x44, 0x8c, 0x4a, 0xa4, 0x90, 0x7c, 0x0b, 0x86, 0x73, 0x9d, 0x4e, 0xb3, - 0x51, 0x25, 0xd2, 0x50, 0x58, 0x71, 0x0c, 0xd1, 0x69, 0x80, 0x8e, 0xda, 0xfe, 0x29, 0xa5, 0xaa, - 0x97, 0x1b, 0x35, 0x03, 0x20, 0x4b, 0x29, 0xd4, 0xe4, 0x19, 0x18, 0xd8, 0x64, 0x3f, 0x1c, 0x75, - 0xe5, 0x14, 0xf4, 0xde, 0xd3, 0x14, 0xd5, 0x25, 0xe7, 0x1c, 0x0c, 0xe2, 0x9c, 0xfc, 0x6e, 0xa5, - 0xd1, 0x2c, 0xac, 0x60, 0x1e, 0x2b, 0xf8, 0x5f, 0x56, 0x82, 0xfe, 0x90, 0xdf, 0x86, 0xb1, 0x7b, - 0xad, 0xc6, 0xe7, 0xf6, 0x14, 0x5c, 0xd4, 0x10, 0xa1, 0x8b, 0x30, 0xb0, 0xa7, 0x29, 0x6a, 0xb9, - 0x55, 0xd9, 0xa5, 0xbc, 0x1e, 0x58, 0x82, 0x0f, 0x96, 0xfa, 0xd4, 0x9e, 0xa4, 0x94, 0xfa, 0x17, - 0x52, 0xa9, 0x1f, 0x67, 0x6e, 0x54, 0x76, 0x15, 0x34, 0x6f, 0xb4, 0x19, 0x73, 0x14, 0x62, 0xed, - 0x3f, 0x0f, 0x88, 0x6f, 0x5f, 0xeb, 0xb4, 0x5b, 0x9a, 0x82, 0x66, 0x60, 0xa0, 0xa1, 0x95, 0xf7, - 0x48, 0x06, 0xe9, 0xa0, 0xbf, 0xd4, 0xdf, 0xd0, 0x68, 0x41, 0xf9, 0x3f, 0xf5, 0xc0, 0xd8, 0xb2, - 0xaa, 0x54, 0xf4, 0xee, 0x30, 0x5d, 0x06, 0x78, 0xd8, 0x50, 0x35, 0x9d, 0x96, 0x74, 0x02, 0x1b, - 0x20, 0xb9, 0xa4, 0xe8, 0x45, 0x18, 0x68, 0x56, 0x8c, 0x92, 0x71, 0x67, 0x9b, 0x38, 0x93, 0x14, - 0xbc, 0x00, 0x03, 0xad, 0x46, 0xf5, 0x11, 0x2d, 0x48, 0x24, 0x61, 0xa9, 0xff, 0x83, 0xa5, 0x1e, - 0x35, 0x4e, 0x8a, 0xe1, 0x2c, 0x52, 0xec, 0x0a, 0x0c, 0xd5, 0x1a, 0x5a, 0xa7, 0x59, 0xd9, 0xa7, - 0x25, 0x7b, 0x6c, 0x25, 0x07, 0x59, 0x2e, 0x29, 0x7c, 0x03, 0x50, 0x47, 0x55, 0x1e, 0x2a, 0xaa, - 0xaa, 0xd4, 0xca, 0xcd, 0x4a, 0xab, 0xbe, 0x57, 0xa9, 0x2b, 0xa9, 0x5e, 0x5b, 0x95, 0x31, 0xb3, - 0xcc, 0x1a, 0x2b, 0x82, 0x6e, 0x41, 0x6f, 0x5d, 0x69, 0xd5, 0x14, 0x35, 0xd5, 0x37, 0x2f, 0x5d, - 0x1a, 0x09, 0xd6, 0xc2, 0x55, 0x52, 0xba, 0xc4, 0x6a, 0x21, 0xd9, 0x18, 0xb4, 0x7e, 0xd2, 0xd7, - 0xd0, 0x07, 0x4b, 0x03, 0x6a, 0x1f, 0xa1, 0xf8, 0xb3, 0xc6, 0xb0, 0xa1, 0x0c, 0x8c, 0x35, 0xb4, - 0x32, 0xf9, 0xbf, 0xfc, 0x58, 0x51, 0x1b, 0x0f, 0x1b, 0x4a, 0x2d, 0x35, 0x40, 0x06, 0x6a, 0xb4, - 0xa1, 0x11, 0x91, 0x7a, 0x93, 0x25, 0xa3, 0xd3, 0xd0, 0xd3, 0xd9, 0x69, 0xb7, 0x94, 0xd4, 0x20, - 0x69, 0xaf, 0xef, 0x83, 0xa5, 0x84, 0x1a, 0x4b, 0x4d, 0x94, 0x68, 0x2a, 0x6b, 0x8a, 0xfc, 0x6f, - 0x35, 0x35, 0x64, 0x34, 0xb5, 0x89, 0xd3, 0xcd, 0xa6, 0x64, 0xe8, 0xab, 0xb6, 0xf7, 0x5a, 0xba, - 0xba, 0x9f, 0x1a, 0xb6, 0x31, 0xc2, 0xc8, 0x40, 0xe7, 0xa1, 0xbf, 0xd9, 0xae, 0x56, 0x9a, 0x0d, - 0x7d, 0x3f, 0x35, 0x62, 0x1f, 0x0a, 0x23, 0x07, 0x5d, 0x86, 0xc1, 0x4e, 0x5b, 0xd3, 0x2b, 0xcd, - 0x72, 0xb5, 0x5d, 0x53, 0x52, 0xa3, 0xb6, 0x82, 0x40, 0x33, 0x97, 0xdb, 0x35, 0x2c, 0xc4, 0xbd, - 0xaa, 0x52, 0x6f, 0xb4, 0x5b, 0xa9, 0xa4, 0xad, 0x14, 0x4b, 0x47, 0x59, 0x18, 0xd1, 0x74, 0x55, - 0x51, 0xf4, 0x72, 0xa5, 0x56, 0x53, 0x15, 0x4d, 0x4b, 0x8d, 0xd9, 0x4a, 0x0e, 0xd3, 0xfc, 0x1c, - 0xcd, 0x46, 0xe7, 0xa0, 0xbf, 0x53, 0xd1, 0xb4, 0x27, 0x6d, 0xb5, 0x96, 0x42, 0x3c, 0x57, 0xee, - 0x96, 0xcc, 0x0c, 0xf9, 0x4b, 0xbd, 0x90, 0xc0, 0x12, 0xee, 0x30, 0x07, 0xb7, 0xa1, 0x47, 0xd3, - 0xb1, 0x99, 0x8b, 0x91, 0xf1, 0xbd, 0x1c, 0x34, 0xbe, 0xb8, 0x91, 0x2d, 0x5c, 0xa1, 0x44, 0xeb, - 0xa1, 0xdb, 0x30, 0x5c, 0xc5, 0x0a, 0xd4, 0x68, 0xb7, 0xa8, 0xbd, 0x8c, 0x07, 0xda, 0xcb, 0x21, - 0xa3, 0x02, 0xb1, 0x98, 0x36, 0x73, 0x9b, 0x88, 0x64, 0x6e, 0x67, 0x78, 0x4d, 0x25, 0x2a, 0xc0, - 0x69, 0xe7, 0x69, 0x41, 0x3b, 0x7b, 0xa9, 0xa9, 0xb3, 0x34, 0x72, 0x86, 0xd7, 0xc8, 0x3e, 0x5a, - 0xd7, 0xd4, 0xc2, 0xb3, 0x36, 0xf5, 0x22, 0xf2, 0x2b, 0x2a, 0xd5, 0x0c, 0xaf, 0xa8, 0x03, 0xb4, - 0xbe, 0xa9, 0x9e, 0x57, 0x5d, 0x35, 0x0e, 0x48, 0x29, 0x5f, 0x3d, 0x1b, 0xec, 0x4a, 0xcf, 0x4c, - 0x83, 0x3b, 0xc4, 0x19, 0x5c, 0x77, 0xcd, 0x1a, 0x76, 0xd7, 0xac, 0x09, 0x43, 0xb3, 0x46, 0x68, - 0x0b, 0x3e, 0x0a, 0x35, 0xea, 0xae, 0x50, 0x29, 0x4b, 0xa1, 0x88, 0x70, 0x5b, 0x6a, 0x94, 0xe6, - 0xd4, 0x68, 0x8c, 0x31, 0xda, 0x50, 0x9e, 0x33, 0xa2, 0xf2, 0x10, 0x09, 0x16, 0x54, 0x66, 0xca, - 0x54, 0x99, 0x71, 0x3a, 0x2d, 0x32, 0x45, 0xb9, 0xe0, 0x50, 0x94, 0x09, 0x92, 0x6f, 0x53, 0x0f, - 0x7e, 0xc6, 0x9d, 0x14, 0x67, 0x5c, 0xf9, 0x3b, 0x7d, 0xd0, 0x8f, 0x05, 0xfa, 0xcd, 0x86, 0xf2, - 0xe4, 0xa3, 0xa6, 0x19, 0xaf, 0x00, 0x10, 0xe9, 0x6e, 0xb6, 0xeb, 0x8d, 0x16, 0xf3, 0x1d, 0xfc, - 0xea, 0x12, 0x5d, 0x58, 0xc3, 0x85, 0x51, 0x1e, 0x92, 0x86, 0xe1, 0x28, 0xd3, 0x16, 0x6b, 0x44, - 0x7b, 0xfc, 0x1b, 0x18, 0x35, 0xea, 0x50, 0x37, 0xaa, 0x26, 0xea, 0x66, 0x9f, 0xaf, 0x6e, 0xf6, - 0xfb, 0xea, 0xe6, 0x40, 0x80, 0x6e, 0x42, 0x80, 0x6e, 0x0e, 0x86, 0xd2, 0xcd, 0xa1, 0x60, 0xdd, - 0x1c, 0x3e, 0x9a, 0x6e, 0x8e, 0x04, 0xea, 0xe6, 0x68, 0x80, 0x6e, 0x26, 0x03, 0x75, 0x73, 0x2c, - 0x50, 0x37, 0x91, 0xb7, 0x6e, 0x8e, 0xfb, 0xeb, 0xe6, 0x84, 0x8f, 0x6e, 0x4e, 0x06, 0xe8, 0xe6, - 0x54, 0x90, 0x6e, 0x4e, 0xdb, 0xbc, 0xe1, 0x0b, 0x30, 0xa2, 0x2a, 0x5a, 0x7b, 0x4f, 0xc5, 0x8b, - 0x86, 0x27, 0x2d, 0x45, 0x4d, 0xa5, 0x68, 0x13, 0x46, 0x6a, 0x11, 0x27, 0xca, 0x3f, 0x94, 0x60, - 0x8c, 0x68, 0x9e, 0x52, 0x51, 0xab, 0x3b, 0x86, 0x03, 0x67, 0xf9, 0xfe, 0x92, 0xbb, 0xef, 0x2f, - 0xac, 0x4f, 0xde, 0x86, 0x11, 0xad, 0xad, 0xea, 0x8d, 0x56, 0xbd, 0x5c, 0x6d, 0x37, 0xf7, 0x76, - 0x5b, 0x44, 0x53, 0x47, 0x16, 0xaf, 0x86, 0x52, 0x79, 0xd2, 0xf1, 0x1b, 0xca, 0x3e, 0x99, 0xa1, - 0x0f, 0xa4, 0xd8, 0xfc, 0x33, 0xa5, 0x61, 0xd6, 0xdc, 0x32, 0x69, 0x0d, 0x25, 0x21, 0x5e, 0xd1, - 0xaa, 0x44, 0x7f, 0xfb, 0x4b, 0xf8, 0x5f, 0x54, 0x80, 0xbe, 0xcf, 0xed, 0x29, 0x6a, 0x43, 0xd1, - 0x52, 0x3d, 0x64, 0x75, 0x93, 0x0d, 0xdf, 0xd5, 0xa7, 0xf7, 0x14, 0x75, 0xbf, 0x64, 0xd4, 0x97, - 0xbf, 0x25, 0xc1, 0xa8, 0x2d, 0x13, 0x15, 0x20, 0xfe, 0x48, 0xd9, 0x27, 0xb4, 0x1f, 0x81, 0x0a, - 0xdc, 0x06, 0x5a, 0x81, 0xde, 0x5d, 0x45, 0xdf, 0x69, 0xd7, 0x98, 0x19, 0x7c, 0x2e, 0xa8, 0x35, - 0xda, 0xd2, 0x3a, 0xa9, 0x53, 0x62, 0x75, 0x31, 0xdf, 0x1f, 0x57, 0x9a, 0x7b, 0xcc, 0xf1, 0x2d, - 0xd1, 0x1f, 0xf2, 0xd7, 0x25, 0x40, 0xfc, 0xd8, 0x31, 0x87, 0x3d, 0xda, 0xe0, 0x9d, 0x85, 0x21, - 0xbd, 0x8d, 0x45, 0x54, 0x55, 0xb4, 0xbd, 0xa6, 0xb1, 0xaa, 0x1b, 0x24, 0x69, 0x25, 0x92, 0x84, - 0x5e, 0xc7, 0x52, 0x4a, 0x32, 0x13, 0x84, 0xd9, 0x97, 0xc2, 0x70, 0x04, 0xcf, 0x09, 0x25, 0x56, - 0x4f, 0xfe, 0xcd, 0x38, 0x5d, 0xdf, 0x6c, 0xaa, 0xed, 0x87, 0x8d, 0xa6, 0xe2, 0xb6, 0xa8, 0xb2, - 0xaf, 0x03, 0x3c, 0xad, 0x59, 0xdc, 0x66, 0xcd, 0x66, 0x1c, 0xfe, 0x3e, 0x67, 0xaa, 0xce, 0xba, - 0x79, 0xf9, 0xa2, 0xa9, 0xbb, 0xea, 0xed, 0xdb, 0x9f, 0x84, 0x47, 0x2f, 0x58, 0xf5, 0x7e, 0x9b, - 0x55, 0xe7, 0x15, 0x7a, 0xc0, 0xa6, 0xd0, 0x8e, 0xe9, 0x10, 0x8e, 0x36, 0x1d, 0x0e, 0x46, 0x99, - 0x0e, 0xe5, 0xef, 0xc6, 0x20, 0x75, 0xaf, 0x53, 0x63, 0x0b, 0x3d, 0x36, 0x8e, 0x5e, 0x61, 0x8c, - 0x4f, 0x96, 0x75, 0xfe, 0x42, 0x20, 0xff, 0x3f, 0x09, 0x06, 0xcc, 0xf5, 0xbe, 0x5b, 0x14, 0x88, - 0x5b, 0xa9, 0xfb, 0x4e, 0x78, 0x71, 0xf7, 0x09, 0x8f, 0x97, 0xa3, 0x44, 0x90, 0x1c, 0xf5, 0x1c, - 0x4d, 0x8e, 0x7a, 0x23, 0xc9, 0xd1, 0x63, 0x98, 0xb2, 0xc4, 0x88, 0x80, 0xf6, 0x12, 0xa2, 0xc0, - 0x78, 0x45, 0x14, 0x8e, 0x98, 0x1c, 0x27, 0xd3, 0xba, 0x1b, 0xc7, 0xa9, 0x83, 0x10, 0x0b, 0x74, - 0x10, 0xe2, 0xee, 0x0e, 0x02, 0xcf, 0xf1, 0x9e, 0x20, 0x8e, 0xf7, 0x1e, 0x8d, 0xe3, 0x7d, 0x91, - 0x38, 0xbe, 0xc7, 0x73, 0x9c, 0x80, 0xf6, 0xe2, 0xf8, 0x19, 0x81, 0x0b, 0x4b, 0x03, 0x1f, 0x2c, - 0xf5, 0xaa, 0x89, 0xa4, 0x14, 0x10, 0x1e, 0x70, 0x67, 0x88, 0xfc, 0xaf, 0x62, 0xd4, 0xe4, 0x1b, - 0xbe, 0x8a, 0xbd, 0x33, 0xce, 0xa3, 0x8a, 0x79, 0x7b, 0x54, 0x71, 0x7f, 0x8f, 0x2a, 0xe1, 0xe3, - 0x51, 0xf5, 0x04, 0x78, 0x54, 0xbd, 0x41, 0x1e, 0x55, 0x5f, 0xd0, 0x30, 0xf6, 0x1f, 0x6d, 0x18, - 0x07, 0x22, 0x0d, 0xe3, 0xff, 0x92, 0x78, 0x03, 0xcc, 0xf0, 0x7a, 0x8d, 0xa4, 0x6c, 0x63, 0x6e, - 0x50, 0x6c, 0x26, 0x1e, 0x36, 0x36, 0x93, 0x08, 0x15, 0x9b, 0xe9, 0x09, 0x1d, 0x9b, 0xe9, 0xf5, - 0x8d, 0xcd, 0xc8, 0x45, 0x18, 0x5a, 0xdf, 0x6b, 0xea, 0x8d, 0x3b, 0x95, 0xaa, 0xde, 0x56, 0x35, - 0x74, 0x1b, 0x12, 0xbb, 0x0f, 0x2b, 0x46, 0x48, 0xfb, 0x4a, 0x90, 0xd5, 0xe5, 0xea, 0x96, 0x48, - 0x45, 0xf9, 0x67, 0x24, 0x18, 0xe4, 0x52, 0xd1, 0x4d, 0x48, 0x90, 0x40, 0x33, 0x75, 0xf5, 0x2e, - 0x06, 0x36, 0xf8, 0xb0, 0xb2, 0xbd, 0xdf, 0x51, 0x4a, 0xa4, 0x12, 0xba, 0x25, 0xae, 0x70, 0x03, - 0xdd, 0xa2, 0xf5, 0x3b, 0x39, 0x7e, 0x81, 0x2b, 0xcf, 0x02, 0x6c, 0xb2, 0x35, 0x9f, 0x4b, 0x48, - 0xf8, 0x2e, 0x8c, 0x1a, 0xb9, 0x5e, 0xc3, 0x7c, 0x81, 0x0b, 0x5d, 0xd9, 0x74, 0x96, 0x0f, 0x5e, - 0x3d, 0x0b, 0x13, 0x25, 0x45, 0x53, 0xf4, 0x80, 0xe6, 0xe4, 0xc7, 0x30, 0xb7, 0x65, 0x95, 0xda, - 0x68, 0xeb, 0x8d, 0x87, 0x2c, 0x0e, 0xee, 0x05, 0x60, 0x85, 0xb1, 0x8f, 0x32, 0xe0, 0x5a, 0x10, - 0x03, 0xf8, 0x26, 0x2d, 0x3e, 0xca, 0xcf, 0x41, 0xda, 0xe8, 0x74, 0xb9, 0xbd, 0xdb, 0x69, 0x2a, - 0xef, 0x34, 0xf4, 0xfd, 0xcd, 0x76, 0xb3, 0x51, 0xdd, 0x77, 0xe1, 0xcb, 0xf7, 0xe2, 0x90, 0xf2, - 0x2a, 0xee, 0x32, 0x89, 0x0c, 0x1a, 0xfb, 0x33, 0x58, 0x30, 0x63, 0xcc, 0xfd, 0xb3, 0x92, 0x50, - 0xce, 0x18, 0x44, 0xba, 0x66, 0x09, 0x94, 0x29, 0xda, 0x91, 0x7f, 0xa0, 0x22, 0x71, 0x34, 0xc3, - 0xd0, 0x13, 0x75, 0xc7, 0x64, 0xb7, 0xd1, 0x2a, 0x37, 0x95, 0x56, 0x5d, 0xdf, 0x21, 0x0a, 0x95, - 0x28, 0x0d, 0xec, 0x36, 0x5a, 0x6b, 0x24, 0x01, 0x9d, 0x83, 0xe1, 0x9d, 0x8a, 0x56, 0x6e, 0xb6, - 0x9f, 0x28, 0x6a, 0xb5, 0xa2, 0x51, 0xb3, 0xd6, 0x5f, 0x1a, 0xda, 0xa9, 0x68, 0x6b, 0x46, 0x9a, - 0x51, 0x68, 0xaf, 0xd3, 0x61, 0x85, 0xfa, 0xcd, 0x42, 0xf7, 0x8c, 0x34, 0xdc, 0x11, 0x2e, 0xd4, - 0xda, 0xdb, 0x7d, 0xa0, 0xa8, 0x2c, 0xc0, 0x3c, 0xb0, 0x53, 0xd1, 0x36, 0x48, 0x82, 0x91, 0xad, - 0xed, 0xef, 0x3e, 0x68, 0x37, 0x89, 0x73, 0x4a, 0xb3, 0xb7, 0x48, 0x82, 0x60, 0x59, 0x07, 0x6d, - 0x71, 0xa4, 0xff, 0x2d, 0xc1, 0x9c, 0xd7, 0x90, 0xd2, 0xdd, 0x05, 0x94, 0x11, 0x07, 0x52, 0xe2, - 0xed, 0xc6, 0xff, 0x89, 0x8b, 0x43, 0x2a, 0x72, 0x24, 0x16, 0xc8, 0x91, 0x78, 0x18, 0x8e, 0x24, - 0x02, 0x39, 0xd2, 0xe3, 0xcf, 0x91, 0x5e, 0x1b, 0x47, 0xe4, 0x2f, 0xc4, 0xbc, 0xa9, 0xa6, 0x96, - 0xde, 0x21, 0xce, 0x19, 0x17, 0x71, 0x0e, 0xc7, 0x85, 0x78, 0x20, 0x17, 0x12, 0x61, 0xb8, 0xd0, - 0x13, 0xc8, 0x85, 0x5e, 0x7f, 0x2e, 0xf4, 0xd9, 0xb9, 0x70, 0x01, 0xc6, 0x0d, 0x26, 0xe4, 0xea, - 0x8a, 0xa7, 0xd6, 0xff, 0xf7, 0x18, 0x8c, 0x39, 0xca, 0x7d, 0x1c, 0xd5, 0x7d, 0x1e, 0x86, 0x76, - 0x2b, 0xef, 0x94, 0x2b, 0xa4, 0xf6, 0xbe, 0xc6, 0x14, 0x1e, 0x76, 0x2b, 0xef, 0xe4, 0x70, 0x89, - 0x7d, 0x0d, 0x5d, 0x82, 0xa4, 0xf2, 0x4e, 0xa7, 0xa1, 0x2a, 0xe5, 0x27, 0x15, 0xb5, 0x45, 0x4b, - 0x51, 0x5f, 0x66, 0x84, 0xa6, 0xdf, 0xaf, 0xa8, 0x2d, 0x52, 0x92, 0xd7, 0xc9, 0x7e, 0x9b, 0x4e, - 0xbe, 0x2f, 0xc1, 0xb4, 0x83, 0xe1, 0x5d, 0x28, 0xa3, 0x1d, 0x6f, 0x2c, 0x14, 0xde, 0xb8, 0x1b, - 0x5e, 0xf9, 0xab, 0x6e, 0x98, 0x8e, 0x41, 0x55, 0xec, 0x18, 0xe3, 0xa1, 0x30, 0x26, 0x5c, 0x31, - 0x5e, 0xb6, 0x20, 0xae, 0xb5, 0xab, 0x8f, 0xda, 0x7b, 0xba, 0xa7, 0x4c, 0xff, 0x30, 0x06, 0x93, - 0xae, 0x65, 0x3f, 0x8e, 0x72, 0x7d, 0x96, 0x8d, 0x81, 0xae, 0x2b, 0xbb, 0x1d, 0xdd, 0x90, 0xeb, - 0x41, 0x3c, 0x06, 0x2c, 0x09, 0xbd, 0x00, 0x53, 0xda, 0x4e, 0xfb, 0x49, 0xb9, 0xd9, 0xae, 0x3e, - 0x2a, 0xb7, 0xf7, 0xf4, 0xf2, 0xc3, 0x4a, 0xa3, 0xb9, 0xa7, 0x2a, 0x1a, 0xb3, 0x2a, 0xe3, 0x38, - 0x17, 0x33, 0xb2, 0xb8, 0xa7, 0xdf, 0x61, 0x59, 0xbe, 0x32, 0xfe, 0x55, 0x09, 0x66, 0x5c, 0x07, - 0xa0, 0x0b, 0x39, 0xb7, 0xe3, 0x8f, 0x45, 0xc1, 0x1f, 0xf7, 0xc4, 0x2f, 0xff, 0xaa, 0x17, 0xc6, - 0x63, 0x90, 0x7b, 0x3b, 0xe6, 0x78, 0x14, 0xcc, 0x09, 0x6f, 0xcc, 0xd3, 0xd0, 0x53, 0x54, 0xeb, - 0xae, 0xc7, 0x1c, 0x06, 0x8a, 0x6a, 0x7d, 0xa5, 0xbd, 0x5b, 0x69, 0xb4, 0xf0, 0x52, 0xad, 0x46, - 0xfe, 0x63, 0x05, 0xd8, 0x2f, 0xf9, 0x6f, 0xc4, 0x20, 0x5e, 0x54, 0xeb, 0x0e, 0xca, 0xa2, 0xba, - 0xdb, 0x45, 0xb5, 0xfe, 0x21, 0xda, 0x4f, 0x42, 0x90, 0xe0, 0x22, 0x90, 0xe4, 0x7f, 0x8e, 0x03, - 0xbd, 0x3c, 0x07, 0xfc, 0x56, 0xa1, 0xf2, 0xb3, 0x30, 0x52, 0x54, 0xeb, 0xeb, 0x0a, 0x9e, 0x5b, - 0x4b, 0xed, 0xa6, 0xa2, 0xa1, 0x09, 0xe8, 0x51, 0xf1, 0x3f, 0x64, 0x55, 0x34, 0x50, 0xa2, 0x3f, - 0xe4, 0xdf, 0x93, 0x08, 0xaf, 0x69, 0x41, 0x34, 0x0d, 0x7d, 0x24, 0xea, 0x68, 0x32, 0xb4, 0x17, - 0xff, 0x2c, 0xd4, 0xac, 0xca, 0x31, 0xae, 0xb2, 0x9d, 0xd2, 0x78, 0x24, 0x4a, 0x8f, 0x6c, 0x47, - 0x7c, 0x62, 0x29, 0xf2, 0x4f, 0xc0, 0x78, 0xae, 0x56, 0xb3, 0x38, 0xc0, 0x16, 0x26, 0x93, 0xd0, - 0xdb, 0x56, 0xeb, 0x16, 0x79, 0x3d, 0x6d, 0xb5, 0x5e, 0xa8, 0xf1, 0x64, 0xc7, 0xdc, 0xc9, 0x8e, - 0xf3, 0x3c, 0x7b, 0x1b, 0xa6, 0xe8, 0xe6, 0xdb, 0x09, 0xb5, 0x7f, 0x17, 0xa6, 0x4a, 0xca, 0x6e, - 0xfb, 0xf1, 0x91, 0xdb, 0x97, 0xbf, 0x21, 0xc1, 0xb4, 0xd9, 0xc8, 0x49, 0xc7, 0xff, 0x73, 0xb6, - 0xf8, 0xff, 0xe5, 0x10, 0x9a, 0xc7, 0xc8, 0x33, 0x36, 0x00, 0xbe, 0x21, 0xc1, 0x94, 0x03, 0xaf, - 0x2f, 0xe9, 0x91, 0x8e, 0x9f, 0xa1, 0x0d, 0x6b, 0x43, 0x88, 0x62, 0x7c, 0x31, 0x34, 0x46, 0xd7, - 0x5d, 0xa1, 0x7f, 0x22, 0xc1, 0x84, 0x5b, 0x09, 0xb4, 0xc1, 0x6f, 0x0d, 0x2d, 0x46, 0xec, 0xe4, - 0x29, 0xef, 0x0f, 0x5d, 0x87, 0x09, 0x76, 0x16, 0x8d, 0xce, 0x67, 0x06, 0xc7, 0xe7, 0x98, 0x29, - 0x72, 0x9e, 0xcc, 0x22, 0xe9, 0xf2, 0x1d, 0xb3, 0x1e, 0x9d, 0x63, 0xbc, 0x56, 0xff, 0x46, 0x3b, - 0x31, 0x8f, 0x76, 0x8a, 0xd0, 0xcf, 0xda, 0xd1, 0xd0, 0x32, 0xf4, 0xb3, 0x43, 0x72, 0x46, 0xf4, - 0x26, 0x30, 0xd8, 0xc2, 0xea, 0x96, 0xcc, 0x8a, 0xf2, 0xcf, 0xc6, 0xa0, 0x8f, 0xa5, 0x3a, 0xc0, - 0x20, 0x1e, 0x0c, 0xb3, 0xaf, 0x4b, 0xa2, 0x53, 0xf4, 0x5c, 0xc8, 0x1e, 0x85, 0x59, 0xe3, 0x48, - 0x46, 0xff, 0xc8, 0xb1, 0x76, 0xde, 0x14, 0xf6, 0xda, 0x4c, 0xe1, 0xaf, 0x49, 0x30, 0xbb, 0xaa, - 0x56, 0x5a, 0xba, 0x52, 0x33, 0x80, 0x9f, 0xb0, 0x21, 0xb8, 0x63, 0x33, 0x04, 0x0b, 0x81, 0xdb, - 0x1e, 0x02, 0x3c, 0xd3, 0x1a, 0xfc, 0x49, 0x1c, 0x46, 0xc4, 0xac, 0x8f, 0xc9, 0x70, 0xde, 0x66, - 0xf1, 0xb2, 0xde, 0x90, 0x4e, 0x3a, 0x25, 0x80, 0x0b, 0x39, 0x3a, 0x77, 0xf5, 0xfb, 0x5c, 0x76, - 0xf5, 0x39, 0x9b, 0xda, 0xcf, 0xdb, 0xd4, 0x53, 0xd0, 0x8f, 0x93, 0xb9, 0x43, 0x21, 0x7d, 0x6d, - 0xb5, 0x6e, 0x9c, 0x27, 0xc1, 0x59, 0xcc, 0x1d, 0xa1, 0x27, 0x42, 0x06, 0xda, 0xa6, 0xaf, 0x76, - 0x0a, 0xfa, 0xeb, 0x78, 0xc0, 0x70, 0x93, 0xf4, 0x38, 0x48, 0x1f, 0xf9, 0x5d, 0x10, 0x77, 0x3e, - 0x86, 0x6c, 0x22, 0xfa, 0x8b, 0x12, 0xcc, 0xb8, 0x8b, 0x68, 0x37, 0xe7, 0x0c, 0xb6, 0x2c, 0x23, - 0x1f, 0x27, 0xf2, 0xf7, 0x4a, 0x34, 0xf9, 0x73, 0xb5, 0xf4, 0xff, 0x52, 0x82, 0x53, 0x9e, 0xc5, - 0xd0, 0x16, 0x6f, 0xee, 0x6f, 0x74, 0xd3, 0xdd, 0x53, 0xb6, 0xf9, 0x19, 0x40, 0xac, 0xfb, 0x60, - 0x17, 0xf1, 0x0f, 0x25, 0x18, 0x16, 0x0a, 0x7f, 0x74, 0xdc, 0xc4, 0x4f, 0x43, 0x52, 0xa0, 0x2c, - 0x57, 0xab, 0x39, 0x4c, 0x4c, 0x44, 0xe7, 0x6d, 0x1b, 0xc6, 0x85, 0x26, 0xd9, 0x69, 0xf7, 0x23, - 0xb6, 0x7a, 0xcb, 0xd6, 0x2a, 0xf5, 0x0f, 0x43, 0xb7, 0x2a, 0x3f, 0x82, 0x11, 0xc3, 0xba, 0xb6, - 0x9b, 0x8a, 0x1b, 0x99, 0x49, 0x2a, 0xc2, 0xb4, 0x1a, 0x91, 0x3f, 0xfb, 0xa1, 0x88, 0xb8, 0xf3, - 0x50, 0xc4, 0x04, 0xf4, 0xd4, 0xd5, 0xf6, 0x5e, 0x87, 0xed, 0xb0, 0xd1, 0x1f, 0x72, 0x0b, 0xc6, - 0xb8, 0xce, 0x3c, 0x18, 0x70, 0x8c, 0xfd, 0xbd, 0x1f, 0x83, 0x41, 0xae, 0x43, 0xdb, 0xd9, 0x7b, - 0xc9, 0x76, 0xf6, 0xbe, 0xbb, 0x9e, 0x7f, 0xb4, 0x51, 0x0f, 0x93, 0xee, 0x5e, 0x8e, 0x6e, 0xdf, - 0xf5, 0xdf, 0x1f, 0x4a, 0x30, 0xca, 0xf1, 0x84, 0x1c, 0xbd, 0xfc, 0x50, 0xf2, 0x25, 0x3a, 0x69, - 0x2f, 0x09, 0xe2, 0xe5, 0xa1, 0x09, 0x0e, 0x62, 0xe4, 0x43, 0x09, 0x4e, 0x71, 0xf5, 0x4e, 0xda, - 0x09, 0x5a, 0xb5, 0x39, 0x41, 0xd9, 0xb0, 0x7e, 0x2c, 0x1b, 0x2d, 0xd3, 0x0b, 0xfa, 0xb6, 0x04, - 0x29, 0x17, 0xdc, 0x74, 0x66, 0x0c, 0x18, 0xd2, 0x68, 0xab, 0xa3, 0x4d, 0xfb, 0xea, 0xe8, 0x7a, - 0x04, 0xcc, 0xae, 0xb3, 0xe6, 0x3f, 0x97, 0x60, 0xca, 0xbd, 0x0c, 0xda, 0xe4, 0xa7, 0xcc, 0x17, - 0x23, 0x77, 0xf4, 0x94, 0xe7, 0xcb, 0xef, 0xc6, 0x4c, 0xa1, 0xa3, 0x06, 0x98, 0x28, 0x94, 0xe7, - 0x3c, 0x28, 0x9c, 0xde, 0x8a, 0xd9, 0x4e, 0x6f, 0x99, 0xe7, 0x76, 0xe2, 0xfc, 0xb9, 0x1d, 0xf1, - 0x6c, 0x5b, 0xc2, 0xf7, 0x6c, 0x5b, 0x8f, 0xed, 0x6c, 0x9b, 0x39, 0x67, 0xf4, 0xfa, 0x4c, 0xbb, - 0x7d, 0x47, 0x9b, 0x76, 0xfb, 0x8f, 0x30, 0xed, 0x82, 0x4d, 0x83, 0xbf, 0x2d, 0xc1, 0x8c, 0xc0, - 0xcd, 0x93, 0x56, 0xc6, 0x82, 0x4d, 0x19, 0x9f, 0x0f, 0x29, 0x6f, 0xd6, 0x58, 0x9b, 0xea, 0xf8, - 0x8f, 0x24, 0x48, 0xbb, 0x62, 0x3f, 0x01, 0x85, 0x2c, 0xd9, 0x15, 0xf2, 0xe5, 0x48, 0xb8, 0x5d, - 0x55, 0xf2, 0x77, 0x2c, 0x73, 0xe2, 0x0c, 0x5b, 0x94, 0x78, 0xa5, 0xbc, 0xde, 0x45, 0x67, 0x4f, - 0x59, 0x2d, 0xff, 0x4b, 0x0c, 0x06, 0xb9, 0xef, 0xf0, 0x8e, 0x1c, 0x0b, 0xce, 0x75, 0x3a, 0x1f, - 0xf2, 0x58, 0xf0, 0x3a, 0x0c, 0xb6, 0x1b, 0xb5, 0x6a, 0xb9, 0xda, 0x6e, 0x3d, 0x6c, 0xd4, 0x99, - 0x56, 0x66, 0x02, 0x03, 0x4c, 0x85, 0x95, 0xe5, 0x65, 0x52, 0xe3, 0xee, 0x33, 0x25, 0xc0, 0x0d, - 0xd0, 0x5f, 0x7e, 0x27, 0x49, 0x97, 0x86, 0x00, 0x2a, 0x9d, 0x0e, 0xeb, 0x49, 0x7e, 0x00, 0x63, - 0x1c, 0xa7, 0xd9, 0xae, 0x42, 0x80, 0xb4, 0xd3, 0xe1, 0x88, 0x39, 0x22, 0x41, 0x3d, 0x1e, 0x91, - 0xa0, 0x9f, 0x4f, 0x00, 0x58, 0x50, 0xd1, 0x39, 0x18, 0x56, 0x95, 0x5a, 0x43, 0xc5, 0xcd, 0xef, - 0xa9, 0x0d, 0x63, 0x59, 0x32, 0x64, 0x24, 0xde, 0x53, 0x1b, 0x1a, 0xba, 0x4f, 0x96, 0xba, 0xc4, - 0x6e, 0x90, 0x8f, 0x41, 0xe9, 0xda, 0x23, 0xc4, 0x29, 0x13, 0xdc, 0x91, 0x61, 0x71, 0xc8, 0xd2, - 0x79, 0x58, 0xe5, 0x7e, 0x69, 0x68, 0x03, 0x06, 0xe9, 0x5a, 0x96, 0xb6, 0x1a, 0x27, 0xad, 0x5e, - 0x0d, 0xd3, 0x2a, 0x59, 0xdf, 0x91, 0x26, 0xa1, 0x6e, 0xfc, 0xab, 0xa1, 0xb7, 0x21, 0x59, 0xb1, - 0x18, 0x48, 0x3f, 0x5c, 0x4d, 0x10, 0xb1, 0x7c, 0x21, 0x4c, 0xa3, 0x1c, 0xf3, 0x49, 0xd3, 0xa3, - 0x15, 0x31, 0x01, 0xcf, 0x10, 0xd5, 0x66, 0x43, 0xa1, 0x8b, 0x6f, 0x36, 0x43, 0xd0, 0x84, 0x42, - 0x0d, 0xb3, 0x92, 0x65, 0x6a, 0x4a, 0x55, 0x55, 0x74, 0xe6, 0x6d, 0x0d, 0xd1, 0xc4, 0x2d, 0x92, - 0x86, 0x7e, 0x12, 0x92, 0x95, 0x3d, 0x7d, 0xa7, 0x4c, 0x55, 0x8e, 0x22, 0xec, 0x0b, 0x19, 0xc1, - 0xc4, 0x08, 0xf7, 0x74, 0xa6, 0xb5, 0x04, 0xe0, 0x48, 0x45, 0xf8, 0x8d, 0x5e, 0x81, 0x53, 0x9d, - 0x36, 0xfd, 0x52, 0xa6, 0xbd, 0xa7, 0x97, 0xc5, 0x91, 0xed, 0x27, 0x23, 0x3b, 0x85, 0x0b, 0xac, - 0x91, 0xfc, 0x12, 0x37, 0xc6, 0xf2, 0x2f, 0x24, 0x60, 0xd2, 0xc6, 0x03, 0xb6, 0xf5, 0x16, 0x20, - 0x80, 0x01, 0xa1, 0x47, 0xa7, 0x84, 0xc5, 0x43, 0x49, 0x58, 0xe2, 0x44, 0x24, 0xac, 0xe7, 0x24, - 0x24, 0xac, 0xf7, 0x18, 0x25, 0xec, 0x43, 0x2b, 0x1f, 0x5f, 0x49, 0x40, 0xd2, 0xb2, 0x1b, 0xe1, - 0x6c, 0xd3, 0x05, 0x18, 0xe1, 0x99, 0x65, 0xda, 0xa9, 0x61, 0x2e, 0x95, 0x2a, 0xce, 0x27, 0x12, - 0xf2, 0xe3, 0x2f, 0x21, 0x2f, 0xc0, 0xd0, 0x32, 0x6f, 0xea, 0x1c, 0xf6, 0x50, 0x72, 0xda, 0x43, - 0xf9, 0xbf, 0xc5, 0x60, 0x94, 0x23, 0xd9, 0xf5, 0xf3, 0xc5, 0x4f, 0x3c, 0x8c, 0x63, 0xf3, 0x30, - 0xf0, 0x02, 0x9d, 0x63, 0xf7, 0x87, 0x6e, 0x81, 0x6e, 0x13, 0x05, 0x61, 0x81, 0xee, 0x82, 0xfb, - 0x43, 0xb1, 0x40, 0x77, 0xe0, 0x72, 0x59, 0xa0, 0xbb, 0x97, 0x89, 0xb8, 0x40, 0x77, 0x34, 0xf2, - 0x94, 0x57, 0x02, 0x7f, 0x1c, 0x83, 0x21, 0xb6, 0x1e, 0x21, 0xa6, 0x2f, 0xe2, 0x85, 0x1c, 0xe8, - 0x3c, 0x8c, 0xd4, 0x69, 0x58, 0xbe, 0xcc, 0xb6, 0x44, 0x68, 0xf3, 0x43, 0x2c, 0xb5, 0x48, 0x76, - 0x46, 0x66, 0x60, 0x00, 0xaf, 0xad, 0xcb, 0x8f, 0x94, 0x7d, 0x3a, 0x04, 0x03, 0xa5, 0x7e, 0x9c, - 0xf0, 0x86, 0xb2, 0xaf, 0xa1, 0x55, 0xc3, 0x14, 0xf4, 0x10, 0xea, 0xc2, 0xae, 0x31, 0x09, 0x5c, - 0x7f, 0x9b, 0xf0, 0x34, 0x3f, 0x04, 0xf1, 0x53, 0x58, 0xf9, 0xb1, 0xb9, 0x6d, 0x40, 0x50, 0x87, - 0x73, 0xc2, 0x9c, 0xac, 0x8d, 0x05, 0xb1, 0x36, 0x2e, 0xb2, 0x56, 0xfe, 0xac, 0xd8, 0x6f, 0x77, - 0xab, 0x0f, 0xdf, 0x1e, 0x6e, 0x9b, 0x01, 0x72, 0xd2, 0x43, 0x61, 0x25, 0x62, 0xeb, 0xf2, 0xf7, - 0xe3, 0xe6, 0x5e, 0x02, 0x69, 0xc1, 0x75, 0xb6, 0x38, 0x16, 0x21, 0xbc, 0x04, 0x49, 0xbe, 0x14, - 0x17, 0x2f, 0x1a, 0xb1, 0xca, 0x91, 0xb8, 0xd0, 0x73, 0x80, 0xf8, 0x92, 0x6c, 0xd7, 0x8e, 0x1a, - 0xfb, 0xa4, 0x55, 0x96, 0x6d, 0xde, 0x09, 0xfc, 0xe9, 0xf5, 0x12, 0xee, 0xbe, 0xe3, 0x16, 0xee, - 0xa7, 0xf9, 0x79, 0x0c, 0x9e, 0x17, 0x8c, 0x01, 0xe0, 0xbf, 0x69, 0x67, 0x69, 0x8e, 0x8f, 0x2b, - 0x07, 0x9d, 0x7b, 0xe9, 0x69, 0x81, 0xb2, 0x13, 0x9e, 0xa3, 0xee, 0xda, 0xe6, 0xa8, 0x6b, 0x51, - 0xd8, 0x2e, 0x4c, 0x52, 0x3b, 0x66, 0xf0, 0x5b, 0x00, 0x7e, 0xfc, 0x93, 0x94, 0x9c, 0x85, 0x69, - 0xbe, 0xa7, 0xe0, 0xfd, 0xc5, 0x7f, 0x2b, 0x89, 0xda, 0xfd, 0x51, 0xdb, 0x64, 0xfc, 0x73, 0x12, - 0x4c, 0x3a, 0xe9, 0xcb, 0xd5, 0x6a, 0x41, 0x7c, 0xe7, 0x77, 0xd3, 0x63, 0xe2, 0x6e, 0x3a, 0xc7, - 0x9c, 0xb8, 0x3b, 0x73, 0x12, 0x3c, 0x8b, 0xbf, 0x60, 0x05, 0xfd, 0x38, 0x08, 0x6c, 0x67, 0xee, - 0xa9, 0xa1, 0xd8, 0x75, 0x03, 0xc1, 0xf6, 0x6f, 0x8e, 0x1f, 0x84, 0xfc, 0xbd, 0x98, 0xb9, 0xf9, - 0xc0, 0xf5, 0xf7, 0x49, 0xe0, 0x3e, 0x82, 0x28, 0xdb, 0xe7, 0xff, 0xdf, 0x92, 0x60, 0xde, 0xc9, - 0xd2, 0x93, 0xb6, 0x82, 0x1b, 0x36, 0x2b, 0x78, 0x3d, 0x8a, 0x15, 0x74, 0x09, 0xe1, 0x7f, 0x5f, - 0x82, 0x33, 0xde, 0x54, 0x84, 0x32, 0x89, 0x3e, 0xf2, 0x68, 0x91, 0x1f, 0x77, 0x27, 0x3f, 0xc1, - 0x93, 0x7f, 0xdf, 0x7e, 0x45, 0xc5, 0x6b, 0xd1, 0x89, 0x73, 0xf5, 0xec, 0x7f, 0x4f, 0x82, 0xd3, - 0xbe, 0x45, 0xd1, 0x7d, 0xde, 0xc1, 0xbf, 0xd9, 0x6d, 0xb7, 0x4f, 0xd9, 0xcf, 0xff, 0xcf, 0x31, - 0xfa, 0x81, 0xb6, 0xbb, 0x93, 0xef, 0x79, 0xaa, 0xc2, 0x3a, 0xe9, 0x14, 0xe7, 0x4f, 0x3a, 0x89, - 0xa3, 0x9c, 0xb0, 0x8f, 0xb2, 0xe0, 0x11, 0xf5, 0xd8, 0x3c, 0xa2, 0x15, 0xc3, 0x23, 0xa2, 0x01, - 0x94, 0x85, 0x30, 0xb7, 0x5d, 0x84, 0x70, 0x87, 0xfa, 0x8e, 0xe6, 0x0e, 0xf5, 0x1f, 0x9b, 0xaf, - 0xff, 0x90, 0x5e, 0x78, 0xc2, 0x3b, 0xfa, 0x9e, 0x66, 0x33, 0xc0, 0xaf, 0xf5, 0xf5, 0xbc, 0xef, - 0x73, 0xfd, 0x30, 0xc7, 0xde, 0xb3, 0x9f, 0x48, 0x2e, 0xfd, 0x75, 0xfa, 0x65, 0xb9, 0xe1, 0xcf, - 0x87, 0x6d, 0x54, 0xfe, 0x49, 0xd3, 0x1d, 0xe1, 0xab, 0x07, 0x18, 0x04, 0x4f, 0xc9, 0xa3, 0xad, - 0xc7, 0xcd, 0xd6, 0xdf, 0x33, 0x27, 0x25, 0x3b, 0xd5, 0xc7, 0xd4, 0x83, 0xef, 0x22, 0x55, 0x6e, - 0x8a, 0xde, 0x19, 0x4f, 0xe1, 0x25, 0x48, 0x1a, 0xfd, 0x9b, 0xb6, 0x8d, 0xa2, 0x18, 0xe9, 0xf0, - 0x4b, 0xa3, 0x08, 0xc4, 0xfe, 0x86, 0xb5, 0xd1, 0x2b, 0x76, 0x17, 0x24, 0x50, 0x96, 0xbe, 0xc6, - 0x78, 0x7d, 0x75, 0x83, 0x18, 0x77, 0x85, 0xf8, 0xac, 0x53, 0xb3, 0xd9, 0x85, 0x7d, 0x49, 0x29, - 0xac, 0x8a, 0xcb, 0x5f, 0xf4, 0x82, 0xcf, 0x46, 0xec, 0xf8, 0x39, 0xe6, 0x3f, 0x78, 0xff, 0x2e, - 0x01, 0xc3, 0x26, 0x06, 0xd7, 0x05, 0xe6, 0x27, 0x06, 0xb0, 0xbf, 0xfb, 0x8b, 0x0d, 0x07, 0x7c, - 0x2f, 0x4f, 0x03, 0x5f, 0xcf, 0x6e, 0xd0, 0xe9, 0xd9, 0xb9, 0xdc, 0x14, 0xc8, 0x9f, 0xac, 0x1d, - 0xf6, 0x3b, 0x59, 0x3b, 0x62, 0x3f, 0x59, 0x6b, 0x5f, 0xb8, 0x8e, 0xfa, 0x2f, 0x5c, 0x93, 0x81, - 0xd7, 0x7c, 0x8d, 0xb9, 0x5d, 0xf3, 0xf5, 0xab, 0x12, 0x4c, 0x5b, 0xc3, 0x74, 0xc2, 0x6e, 0x5d, - 0xde, 0xe6, 0xd6, 0x5d, 0x0d, 0x2d, 0x40, 0x82, 0x37, 0xf7, 0xd7, 0x24, 0x98, 0x72, 0x60, 0xee, - 0xe6, 0xdc, 0xf0, 0x86, 0xfd, 0xdc, 0xf0, 0x8b, 0xe1, 0x25, 0xda, 0xe3, 0xc8, 0xf0, 0x84, 0x5b, - 0x89, 0x88, 0x1f, 0x87, 0xd8, 0x9a, 0x70, 0xf1, 0xb7, 0x36, 0x8e, 0xe2, 0x6f, 0x19, 0x8d, 0xa5, - 0x9e, 0x09, 0xf0, 0xbc, 0x7e, 0xc3, 0x72, 0x28, 0x3d, 0xd8, 0x7d, 0xac, 0xb1, 0xee, 0xe8, 0x9f, - 0xea, 0x04, 0x8e, 0x86, 0xec, 0x6a, 0xcb, 0x45, 0x1a, 0xc2, 0x9b, 0xf4, 0x1f, 0x2d, 0x39, 0x5f, - 0x8c, 0xc1, 0x54, 0x6e, 0x4f, 0xdf, 0x39, 0xb2, 0xd4, 0x57, 0x3d, 0x6e, 0xe5, 0x0b, 0x94, 0x4b, - 0x5b, 0xef, 0x11, 0xaf, 0xe6, 0xdb, 0xb0, 0xaf, 0x7b, 0x5e, 0x8c, 0xd8, 0x9f, 0x8b, 0xb2, 0xb9, - 0x95, 0x88, 0xa8, 0x6c, 0xbe, 0x44, 0x3d, 0x45, 0x65, 0xfb, 0x86, 0x04, 0xd3, 0x8e, 0xe1, 0xfd, - 0xd0, 0x7c, 0xb8, 0x67, 0x22, 0x33, 0x8d, 0xf0, 0x2e, 0x0c, 0x98, 0x89, 0x18, 0x08, 0xf1, 0x2e, - 0xc4, 0x2f, 0xf5, 0x66, 0xc1, 0xb2, 0x05, 0xce, 0x25, 0xc2, 0x14, 0x30, 0x4f, 0x25, 0x4c, 0x24, - 0x29, 0xf3, 0x2b, 0xec, 0x9a, 0x2e, 0xe2, 0x49, 0xa0, 0x53, 0x30, 0x79, 0x6f, 0x2b, 0x5f, 0xda, - 0xda, 0xce, 0x6d, 0xe7, 0xcb, 0xf7, 0x36, 0xb6, 0x36, 0xf3, 0xcb, 0x85, 0x3b, 0x85, 0xfc, 0x4a, - 0xf2, 0x19, 0x34, 0x01, 0x49, 0x2b, 0x2b, 0xb7, 0xbc, 0x5d, 0x78, 0x33, 0x9f, 0x94, 0xd0, 0x14, - 0x20, 0x2b, 0xb5, 0xb0, 0xc1, 0xd2, 0x63, 0x68, 0x12, 0xc6, 0xac, 0xf4, 0x95, 0xfc, 0x5a, 0x7e, - 0x3b, 0xbf, 0x92, 0x8c, 0x8b, 0x8d, 0xac, 0x15, 0x97, 0xdf, 0xc8, 0xaf, 0x24, 0x13, 0x62, 0xe1, - 0xad, 0x7b, 0x5b, 0x9b, 0xf9, 0x8d, 0x95, 0x64, 0x8f, 0x98, 0x5c, 0xd8, 0x28, 0x6c, 0x17, 0x72, - 0x6b, 0xc9, 0xde, 0xcc, 0x9f, 0x86, 0x5e, 0x7a, 0xb9, 0x1b, 0xee, 0x7c, 0x35, 0xbf, 0xb1, 0x92, - 0x2f, 0xd9, 0xa0, 0x8e, 0xc1, 0x30, 0x4b, 0xbf, 0x93, 0x5f, 0xcf, 0xad, 0x61, 0x9c, 0xa3, 0x30, - 0xc8, 0x92, 0x48, 0x42, 0x0c, 0x21, 0x18, 0x61, 0x09, 0x2b, 0x85, 0x37, 0xf3, 0xa5, 0xad, 0x7c, - 0x32, 0x9e, 0xf9, 0xbf, 0x12, 0x75, 0x0a, 0x4d, 0x89, 0x45, 0xa7, 0xe1, 0x14, 0x81, 0x90, 0xcf, - 0x95, 0x96, 0xef, 0xbe, 0x91, 0x7f, 0xcb, 0xd6, 0xd1, 0x0c, 0x4c, 0xdb, 0xb2, 0xb7, 0xf2, 0xa5, - 0xf2, 0x46, 0x6e, 0x1d, 0x77, 0x39, 0x0b, 0x29, 0x31, 0xf3, 0x4e, 0xa1, 0xb4, 0xb5, 0x4d, 0x73, - 0x63, 0xce, 0xaa, 0x6b, 0x39, 0x23, 0x33, 0xee, 0xcc, 0xdc, 0x28, 0x2c, 0xbf, 0x41, 0x33, 0x13, - 0x68, 0x0e, 0xd2, 0x62, 0xe6, 0x4a, 0x61, 0x6b, 0x73, 0x2d, 0xf7, 0x16, 0xcd, 0xef, 0x41, 0xd3, - 0x30, 0x2e, 0xe6, 0xe7, 0xd7, 0x73, 0x85, 0xb5, 0x64, 0xaf, 0x33, 0x83, 0x70, 0x36, 0xd9, 0x97, - 0xf9, 0x7d, 0x09, 0x86, 0x78, 0xdd, 0xc2, 0x25, 0x69, 0xa9, 0xf5, 0xfc, 0xf6, 0xdd, 0xe2, 0x4a, - 0x39, 0xff, 0xe9, 0x7b, 0xb9, 0xb5, 0xad, 0xe4, 0x33, 0x98, 0x26, 0x21, 0x63, 0x6b, 0x3b, 0x57, - 0xda, 0xde, 0x2a, 0xdf, 0x2f, 0x6c, 0xdf, 0x4d, 0x4a, 0x58, 0x7a, 0x84, 0xdc, 0xe5, 0xe2, 0xc6, - 0x76, 0xae, 0xb0, 0xb1, 0x95, 0x8c, 0xa1, 0x73, 0x70, 0xc6, 0xa5, 0xc5, 0x72, 0x61, 0x75, 0xa3, - 0x58, 0xca, 0x97, 0x97, 0x73, 0x98, 0xff, 0xe8, 0x12, 0x9c, 0xf7, 0x6a, 0x5d, 0x28, 0x99, 0x40, - 0x17, 0xe0, 0xac, 0x6b, 0x4f, 0x42, 0xb1, 0x9e, 0xcc, 0x0a, 0xf4, 0xb1, 0x0b, 0xa4, 0x30, 0x49, - 0xeb, 0x77, 0x72, 0xdb, 0x6f, 0x6d, 0xda, 0xe5, 0x7a, 0x14, 0x06, 0x8d, 0x8c, 0xad, 0xf5, 0x2d, - 0x2a, 0x2a, 0x46, 0x42, 0x71, 0x7b, 0x33, 0x19, 0xcb, 0x3c, 0x84, 0x7e, 0xe3, 0x22, 0x29, 0x94, - 0x82, 0x09, 0xfc, 0xbf, 0x8b, 0x7e, 0x4c, 0x01, 0x32, 0x73, 0x36, 0x8a, 0xdb, 0xe5, 0x52, 0x3e, - 0xb7, 0xf2, 0x56, 0x52, 0xc2, 0x82, 0x66, 0xa6, 0xd3, 0xb4, 0x18, 0x56, 0x03, 0x2e, 0x6d, 0xbd, - 0xf8, 0x26, 0x56, 0x8e, 0xcc, 0x5d, 0x48, 0xda, 0xef, 0x6b, 0x42, 0x69, 0x98, 0xda, 0x28, 0x6e, - 0x17, 0xee, 0x14, 0x96, 0x73, 0xdb, 0x85, 0xe2, 0x06, 0x41, 0x45, 0xc7, 0xf3, 0x19, 0x8c, 0xc5, - 0x91, 0x47, 0x48, 0xc8, 0xec, 0xc1, 0x20, 0x77, 0xdd, 0x04, 0x16, 0xa7, 0xcd, 0xe2, 0x5a, 0x61, - 0xf9, 0x2d, 0x0f, 0xdc, 0x7c, 0xa6, 0xa9, 0xd9, 0x29, 0x98, 0xe0, 0xd3, 0x39, 0xdd, 0x9e, 0x86, - 0x71, 0x3e, 0xc7, 0xd4, 0xee, 0xcc, 0x26, 0xf4, 0x1b, 0x57, 0x00, 0xe0, 0xea, 0xc5, 0xd2, 0xaa, - 0x5b, 0x87, 0xe3, 0x30, 0x6a, 0xe6, 0x98, 0xbd, 0x4d, 0xc2, 0x98, 0x99, 0x68, 0x75, 0x95, 0xf9, - 0x75, 0x09, 0x90, 0xf3, 0x93, 0x5e, 0x24, 0xc3, 0x5c, 0xb1, 0xb4, 0xba, 0x9e, 0x5f, 0x5f, 0xf2, - 0xd6, 0xcd, 0xb3, 0x70, 0xda, 0xa5, 0x0c, 0xa7, 0x83, 0x12, 0x9a, 0x87, 0x59, 0x97, 0x22, 0x96, - 0x22, 0xc6, 0xb0, 0xbc, 0xbb, 0x94, 0xa0, 0x03, 0x10, 0xc7, 0x9a, 0xe8, 0x06, 0x03, 0xdb, 0x80, - 0xc2, 0x4a, 0x32, 0x91, 0xf9, 0xac, 0xb9, 0x91, 0x4e, 0x79, 0x32, 0x0b, 0xa9, 0xcd, 0x52, 0xf1, - 0x4f, 0xe5, 0x97, 0xb7, 0xdd, 0xf8, 0x82, 0xd9, 0xca, 0xe7, 0x9a, 0xbc, 0x39, 0x05, 0x93, 0x42, - 0x06, 0xc7, 0x9f, 0xcf, 0x98, 0x9f, 0xeb, 0xb0, 0x83, 0x8b, 0xd3, 0xac, 0xa4, 0x8b, 0xa0, 0x4f, - 0xc2, 0x18, 0x9f, 0x59, 0xbc, 0xbf, 0x91, 0x5f, 0x49, 0x4a, 0x5c, 0xb7, 0x24, 0x79, 0xb5, 0x94, - 0xdb, 0xc0, 0xa3, 0x19, 0xcb, 0xbc, 0x0d, 0xd3, 0x1e, 0x9f, 0xd7, 0x61, 0xc6, 0x19, 0x88, 0xbc, - 0xb9, 0xef, 0x28, 0xc1, 0x12, 0x18, 0xf7, 0x33, 0x7f, 0x5e, 0x32, 0xbf, 0x7a, 0x16, 0x3e, 0x46, - 0x40, 0xe7, 0x61, 0x9e, 0x15, 0x2d, 0x15, 0xd7, 0xf2, 0x5e, 0x3d, 0x58, 0xcc, 0x14, 0x4b, 0xbd, - 0x91, 0xc7, 0x5a, 0x77, 0x01, 0xce, 0xba, 0xe6, 0x0a, 0xb6, 0x32, 0x96, 0xf9, 0x81, 0xf5, 0x55, - 0x85, 0x5d, 0xc6, 0x9e, 0x05, 0x99, 0xb5, 0xe0, 0x2f, 0x67, 0x56, 0x4f, 0xbe, 0xb2, 0x66, 0x11, - 0xe5, 0x27, 0x6f, 0x16, 0x63, 0xbd, 0x64, 0x4e, 0x86, 0x39, 0x2f, 0x58, 0x86, 0xdc, 0xf9, 0xf4, - 0x65, 0xcd, 0x4f, 0x3d, 0x58, 0x5b, 0x8d, 0x23, 0x54, 0x58, 0x5b, 0x73, 0x9b, 0x9b, 0x1e, 0xda, - 0x6a, 0xe6, 0xf0, 0xda, 0x6a, 0x26, 0x72, 0xd2, 0xb8, 0x43, 0xcf, 0x0e, 0xf2, 0xc7, 0xf0, 0xb0, - 0xf0, 0x92, 0xb4, 0xfc, 0xd6, 0x66, 0x71, 0x63, 0x2b, 0x4f, 0x64, 0x6c, 0xb9, 0xb8, 0x92, 0x4f, - 0x3e, 0x83, 0x27, 0x57, 0x47, 0x56, 0x61, 0xa5, 0xbc, 0x5d, 0x7c, 0x23, 0xbf, 0x91, 0x94, 0xb0, - 0xe9, 0x73, 0x64, 0xd3, 0xbc, 0x58, 0x46, 0x85, 0x61, 0xe1, 0x68, 0x1e, 0x26, 0x99, 0x24, 0x60, - 0xe9, 0x25, 0x25, 0x73, 0xf7, 0xb6, 0xef, 0x16, 0x4b, 0x85, 0xcf, 0x10, 0xd3, 0x68, 0xf4, 0xc8, - 0x9a, 0xb4, 0x4a, 0x15, 0xd6, 0x37, 0xd7, 0x0a, 0xcb, 0x85, 0xed, 0xa4, 0x84, 0xce, 0xc0, 0x8c, - 0x98, 0x57, 0xca, 0xdf, 0x29, 0xe5, 0xb7, 0xee, 0x9a, 0x7d, 0x3e, 0x86, 0x71, 0x97, 0x93, 0x7b, - 0x58, 0xe7, 0x48, 0xf2, 0x26, 0x6e, 0xc9, 0x32, 0xc4, 0xf7, 0xf3, 0x4b, 0xc9, 0x67, 0x88, 0xa1, - 0x72, 0xc9, 0x24, 0xc3, 0x90, 0x5b, 0xcd, 0x6f, 0xe0, 0x8e, 0xb1, 0x15, 0x71, 0x29, 0xb3, 0x91, - 0x63, 0x5c, 0x6d, 0x02, 0x72, 0x9e, 0xe8, 0x23, 0x96, 0x09, 0xa7, 0xde, 0xdb, 0x66, 0x73, 0x20, - 0xa9, 0xb4, 0x94, 0xdb, 0x2a, 0x2c, 0x53, 0xc7, 0xc4, 0x25, 0x77, 0xb3, 0xb8, 0x85, 0x3b, 0x74, - 0xcf, 0xdc, 0x28, 0x6e, 0xe0, 0xde, 0xca, 0x30, 0xe1, 0x76, 0x00, 0x09, 0x33, 0x98, 0x43, 0xb8, - 0x95, 0x2f, 0xe5, 0x3c, 0xd4, 0x5e, 0x28, 0x65, 0xc8, 0x5d, 0x6e, 0x73, 0xd3, 0x50, 0x7b, 0xdd, - 0xfc, 0xfc, 0xc7, 0x8a, 0x60, 0x71, 0xe6, 0x82, 0xf0, 0xdf, 0x4d, 0x10, 0x2d, 0x7d, 0xe7, 0x8a, - 0x98, 0x12, 0x39, 0x07, 0x69, 0x67, 0x2e, 0x27, 0x9a, 0x7f, 0x33, 0x26, 0xc6, 0x1f, 0xed, 0xda, - 0x7e, 0x05, 0x2e, 0xf2, 0xf5, 0xfd, 0x55, 0x3e, 0x03, 0xcf, 0xfa, 0x15, 0x16, 0xf4, 0xfe, 0x32, - 0x5c, 0xf0, 0x2b, 0xcb, 0x2b, 0xbf, 0x65, 0x49, 0x5c, 0x8b, 0x1a, 0x16, 0xe0, 0x22, 0x9c, 0xf3, - 0x85, 0x6a, 0x9a, 0x81, 0x80, 0xae, 0x79, 0x5b, 0xb0, 0x03, 0x23, 0x62, 0x4c, 0xd1, 0xf0, 0x32, - 0x3d, 0x87, 0x83, 0xad, 0x14, 0xdc, 0xc6, 0x82, 0x79, 0xaf, 0xee, 0x03, 0xf1, 0x65, 0x76, 0x85, - 0xba, 0xb8, 0x34, 0xc4, 0x8a, 0x62, 0xd5, 0xf1, 0x9e, 0x53, 0x5c, 0xca, 0x18, 0xb3, 0x4a, 0x61, - 0x85, 0x8a, 0x81, 0x5b, 0x33, 0x8c, 0x25, 0x31, 0xc3, 0x9f, 0xb7, 0xe5, 0x17, 0x4b, 0xab, 0x38, - 0x3b, 0x4e, 0xc0, 0x39, 0xd7, 0xad, 0x18, 0x1c, 0x56, 0x16, 0x5f, 0x70, 0xa7, 0xe1, 0x94, 0x4b, - 0x19, 0xd6, 0xb2, 0x44, 0x14, 0xc3, 0x99, 0xcd, 0x61, 0x8f, 0x61, 0xec, 0x6e, 0xbd, 0x30, 0xec, - 0xf1, 0xc5, 0x9f, 0xff, 0xb2, 0x04, 0x63, 0xeb, 0xe6, 0x0a, 0x72, 0x4b, 0x51, 0x1f, 0x37, 0xaa, - 0x0a, 0x7a, 0x03, 0xfa, 0xee, 0x2a, 0x95, 0xa6, 0xbe, 0xf3, 0x79, 0x34, 0xe5, 0x08, 0xd5, 0xe6, - 0x77, 0x3b, 0xfa, 0x7e, 0xda, 0x23, 0x5d, 0x4e, 0x1e, 0xfc, 0xeb, 0xff, 0xf8, 0xa5, 0x18, 0xa0, - 0xfe, 0xec, 0x0e, 0x6b, 0x61, 0x15, 0x7a, 0x4a, 0x4a, 0xa5, 0xb6, 0x1f, 0xb9, 0xa9, 0x11, 0xd2, - 0x54, 0x3f, 0xea, 0xcd, 0xaa, 0xa4, 0xfe, 0x06, 0xf4, 0xbf, 0xc9, 0x9e, 0x71, 0xf3, 0x6c, 0xcb, - 0xeb, 0x61, 0x30, 0x79, 0x8c, 0x34, 0x36, 0x88, 0x06, 0xcc, 0xa7, 0xe0, 0xd0, 0x9f, 0x85, 0xc1, - 0x55, 0x85, 0x44, 0x9a, 0x96, 0xf6, 0x0b, 0x2b, 0xe8, 0xd9, 0x30, 0x21, 0x9f, 0xc2, 0x4a, 0xfa, - 0x7c, 0x98, 0x72, 0xb2, 0x7c, 0x70, 0x98, 0x1a, 0xa4, 0xe1, 0xeb, 0x05, 0x0c, 0x9f, 0x74, 0x3f, - 0x8c, 0x06, 0xb3, 0x38, 0x45, 0xcb, 0xbe, 0xdb, 0xa8, 0xbd, 0x87, 0xbe, 0x2a, 0xc1, 0x84, 0x89, - 0x80, 0xdc, 0x74, 0xbd, 0xda, 0x6c, 0x3f, 0xa8, 0x34, 0xd1, 0x95, 0x30, 0x5d, 0xb0, 0x67, 0xc6, - 0xd2, 0xa1, 0x2f, 0xf2, 0x97, 0x17, 0xdd, 0x30, 0x9d, 0x46, 0x33, 0xd9, 0x3a, 0xe9, 0x96, 0x41, - 0x23, 0xb1, 0xf0, 0xec, 0xbb, 0xe4, 0xcf, 0x7b, 0xe8, 0x6f, 0x49, 0x30, 0x48, 0xa5, 0x16, 0x37, - 0xa3, 0xa1, 0xe7, 0xc3, 0x3f, 0xa4, 0xc0, 0x22, 0x5e, 0xe9, 0xc5, 0x28, 0x55, 0xe8, 0x34, 0x2f, - 0x5f, 0x72, 0x83, 0x3a, 0x2e, 0x8f, 0x30, 0x8c, 0x65, 0x8d, 0x14, 0x7f, 0x55, 0xca, 0x60, 0x80, - 0x43, 0x05, 0x0d, 0x37, 0x41, 0x5f, 0x33, 0x0b, 0x81, 0xd0, 0xfe, 0xfc, 0x5a, 0x08, 0x84, 0x8e, - 0x17, 0xd5, 0xe4, 0x8b, 0x6e, 0x08, 0x11, 0x4a, 0x1a, 0x08, 0x1b, 0x1a, 0x7d, 0x6d, 0x0d, 0xfd, - 0xb4, 0x04, 0x60, 0xbd, 0xae, 0x16, 0x0c, 0xcf, 0xf1, 0x12, 0x5b, 0x48, 0x89, 0x3b, 0x7b, 0x70, - 0x98, 0x1a, 0x02, 0x20, 0x80, 0x9e, 0xa8, 0x0d, 0x5d, 0xa1, 0x12, 0x2f, 0xf7, 0x52, 0x44, 0x98, - 0x57, 0x3f, 0x27, 0xc1, 0xc8, 0x8a, 0x52, 0xa9, 0xea, 0x8d, 0xc7, 0x06, 0x9c, 0xe3, 0x95, 0xfa, - 0x45, 0x57, 0x0c, 0xb3, 0xe9, 0x69, 0x4e, 0xec, 0xb3, 0xe5, 0x9a, 0x09, 0xc1, 0x00, 0x55, 0xfa, - 0xd1, 0x83, 0x52, 0x05, 0x50, 0x7f, 0x41, 0x82, 0xfe, 0xb5, 0x76, 0xf5, 0xd1, 0x09, 0xc0, 0x79, - 0xce, 0x15, 0xce, 0x54, 0x7a, 0x4c, 0x80, 0xd3, 0x6c, 0x57, 0x1f, 0x61, 0x20, 0x3f, 0x23, 0x01, - 0xdc, 0x6b, 0x35, 0x4f, 0x06, 0xca, 0x82, 0x2b, 0x94, 0x54, 0x7a, 0x5c, 0x80, 0xb2, 0xd7, 0x32, - 0xc0, 0xa8, 0x00, 0x2b, 0x4a, 0x53, 0x89, 0x38, 0x4a, 0x5e, 0xf6, 0xfd, 0xfc, 0xc1, 0x61, 0x6a, - 0x18, 0x06, 0x49, 0xef, 0x35, 0xd2, 0x2c, 0x35, 0x92, 0x19, 0xc1, 0x48, 0xbe, 0x2f, 0xd1, 0x83, - 0x02, 0xc6, 0x9b, 0x98, 0x57, 0x43, 0x3e, 0x81, 0xc9, 0x74, 0xe7, 0x62, 0xb8, 0xe2, 0x9a, 0x9c, - 0x71, 0xd3, 0xe7, 0x49, 0x24, 0xb0, 0xc2, 0x78, 0x55, 0xf3, 0xef, 0xe0, 0x39, 0x9d, 0xfb, 0xda, - 0xed, 0x84, 0xa1, 0xbd, 0x7c, 0x70, 0x98, 0x42, 0xe6, 0xce, 0xc7, 0x42, 0xa5, 0xd3, 0xb1, 0x10, - 0xce, 0xa2, 0x74, 0x96, 0xfb, 0xce, 0xc7, 0x06, 0xf4, 0x2f, 0x49, 0x00, 0x45, 0xb5, 0x7e, 0xd2, - 0x00, 0xb1, 0xb5, 0x06, 0xb2, 0x79, 0x6a, 0x01, 0x9b, 0x40, 0x28, 0xdb, 0x56, 0xeb, 0x36, 0x40, - 0x5f, 0x96, 0xcc, 0x93, 0xdc, 0x27, 0x0d, 0xea, 0xda, 0xc1, 0x61, 0x6a, 0xc4, 0xdc, 0x97, 0xb5, - 0x80, 0xa5, 0xd0, 0x54, 0xd6, 0xb8, 0x8c, 0x4c, 0x04, 0xf7, 0xbe, 0x04, 0x23, 0x6c, 0x3e, 0x36, - 0xde, 0xb8, 0x09, 0x2b, 0xe3, 0xa1, 0x66, 0x6c, 0xd6, 0x68, 0x28, 0x51, 0xeb, 0x30, 0x00, 0xbf, - 0x24, 0xc1, 0x98, 0xe3, 0xc9, 0x16, 0x14, 0xf8, 0xa5, 0xb9, 0xd7, 0x2b, 0x2f, 0xd1, 0x80, 0x86, - 0xb2, 0x0f, 0x0c, 0x29, 0xb6, 0x0f, 0x3f, 0x2b, 0xc1, 0x10, 0x63, 0x20, 0x7d, 0x14, 0x25, 0x2c, - 0xfb, 0x2e, 0x87, 0x76, 0x78, 0x3c, 0x3c, 0x03, 0x24, 0x58, 0x4f, 0xba, 0x9d, 0xff, 0x35, 0x09, - 0x46, 0xa9, 0x30, 0x58, 0x80, 0xae, 0x87, 0x67, 0x1c, 0xff, 0xae, 0x49, 0x14, 0x80, 0xa1, 0xec, - 0x3b, 0x41, 0x88, 0x59, 0xf6, 0x15, 0x09, 0x66, 0x4a, 0x8a, 0xa6, 0xb4, 0x6a, 0xdc, 0x53, 0x27, - 0x54, 0x97, 0xd7, 0xa3, 0x70, 0xd0, 0xcb, 0xc8, 0xbe, 0xee, 0x8a, 0x26, 0x23, 0x5f, 0x70, 0xa0, - 0xc1, 0x53, 0x20, 0xc6, 0xf1, 0x98, 0x83, 0x60, 0x1b, 0x54, 0xfa, 0xee, 0xca, 0xb1, 0x0e, 0x2a, - 0x69, 0x32, 0xd4, 0xa0, 0xd2, 0xd7, 0x4b, 0xc4, 0x41, 0xa5, 0x80, 0x22, 0x0c, 0x2a, 0xff, 0x74, - 0x4a, 0x14, 0x80, 0xa1, 0x06, 0x95, 0x20, 0x14, 0x07, 0x95, 0x7b, 0x4e, 0x85, 0xcd, 0x15, 0xed, - 0x9a, 0xf2, 0x74, 0x06, 0x95, 0xa0, 0xf1, 0x1a, 0x54, 0xce, 0xd4, 0x19, 0xaf, 0xa6, 0x1c, 0xab, - 0xa9, 0x33, 0xde, 0xfe, 0x08, 0x63, 0xea, 0xd8, 0x33, 0x22, 0x36, 0x53, 0x67, 0xc0, 0x8a, 0x60, - 0xea, 0xc4, 0xf7, 0x54, 0xa2, 0x01, 0x0d, 0x65, 0xea, 0x18, 0x52, 0xcc, 0xc0, 0xbf, 0x28, 0x99, - 0xab, 0xc7, 0xf5, 0x87, 0x95, 0xf0, 0xdc, 0x7b, 0x2e, 0xc2, 0x73, 0x27, 0x5a, 0xd0, 0x22, 0x83, - 0x80, 0xda, 0xc5, 0xdd, 0xff, 0x7d, 0x09, 0x66, 0xb6, 0x94, 0x56, 0xcd, 0xe3, 0xe9, 0x0f, 0x74, - 0x2b, 0x78, 0x1f, 0xdc, 0xef, 0xcd, 0x10, 0x4f, 0x49, 0xbc, 0xe1, 0xca, 0xb6, 0xb3, 0xf2, 0xac, - 0xe0, 0x41, 0x62, 0x09, 0xd4, 0x14, 0xbd, 0xf3, 0xa4, 0x85, 0x9b, 0xde, 0xc7, 0xfc, 0xfb, 0x92, - 0x04, 0x68, 0x4b, 0xd1, 0x0b, 0xad, 0x86, 0xde, 0xa8, 0x34, 0x8d, 0xae, 0x51, 0xf0, 0x3d, 0x4c, - 0xe2, 0xf3, 0x27, 0x9e, 0xc0, 0x5e, 0x74, 0x05, 0x36, 0x27, 0x9f, 0xb2, 0x01, 0xd3, 0x1b, 0x14, - 0x41, 0xe7, 0x09, 0x46, 0xf5, 0x77, 0x25, 0x98, 0x59, 0xb5, 0x38, 0xe1, 0x78, 0x99, 0xc4, 0x2b, - 0xec, 0xf0, 0x72, 0x58, 0xd8, 0xf6, 0x16, 0x09, 0x03, 0x87, 0x61, 0xb0, 0x43, 0x7e, 0x59, 0x63, - 0x3c, 0x8f, 0xe6, 0xb2, 0x24, 0xad, 0xa1, 0x68, 0x59, 0xe3, 0x0d, 0x18, 0x2d, 0x5b, 0x35, 0xab, - 0xa3, 0x3f, 0x90, 0x60, 0x8e, 0x2e, 0x15, 0x3d, 0xd1, 0xde, 0xea, 0x16, 0x15, 0x6d, 0xf7, 0x08, - 0x54, 0xdd, 0x64, 0xbe, 0x17, 0xa5, 0xca, 0xe2, 0xff, 0x39, 0x39, 0x80, 0x2c, 0x3c, 0x08, 0x7f, - 0x24, 0xc1, 0x1c, 0x55, 0xea, 0xe3, 0xa7, 0x8c, 0xb6, 0x7b, 0x04, 0xca, 0x5e, 0xf7, 0xa0, 0xec, - 0x52, 0xfa, 0x9c, 0x3f, 0x65, 0x44, 0xe2, 0x30, 0x79, 0xdf, 0x94, 0x60, 0x8e, 0xae, 0xa2, 0x3c, - 0xc9, 0x7b, 0xb5, 0x5b, 0x78, 0x3e, 0x73, 0xc6, 0xad, 0x83, 0xc3, 0xd4, 0x28, 0x0c, 0x33, 0xe0, - 0xdc, 0x7a, 0xeb, 0x42, 0x26, 0x0c, 0x72, 0xac, 0xb0, 0x13, 0x9c, 0x6a, 0x58, 0xcf, 0x77, 0x78, - 0xe9, 0xc4, 0xf3, 0x61, 0x89, 0x30, 0x9b, 0x22, 0x2e, 0xbb, 0x8b, 0x32, 0x9c, 0x42, 0xd3, 0x6e, - 0x08, 0x2b, 0x75, 0x05, 0xfd, 0xba, 0x04, 0xd3, 0xa2, 0x16, 0x58, 0xc0, 0x6e, 0x44, 0x06, 0xc0, - 0xe4, 0xbe, 0x0b, 0xe4, 0x2f, 0x7a, 0x88, 0xc5, 0xac, 0xec, 0x05, 0x1d, 0x8b, 0xc2, 0x77, 0x24, - 0x98, 0x16, 0x25, 0xfd, 0x28, 0xe8, 0x99, 0x6c, 0x77, 0x81, 0xfe, 0x15, 0x0f, 0xf4, 0x67, 0xd3, - 0xb3, 0x1e, 0xe8, 0x4d, 0x69, 0xfe, 0x8a, 0x04, 0xd3, 0xa2, 0x34, 0x5b, 0x24, 0xbc, 0x10, 0x19, - 0x89, 0x8f, 0xfc, 0xde, 0xf0, 0x92, 0xdf, 0xb9, 0x8c, 0x2f, 0x48, 0x8c, 0x30, 0xc5, 0x09, 0xae, - 0xf8, 0x46, 0x87, 0x97, 0xf0, 0xbe, 0x14, 0x16, 0xba, 0xd0, 0x1c, 0x11, 0x03, 0x17, 0x01, 0x3e, - 0x8d, 0x66, 0xdc, 0x20, 0x36, 0x69, 0x5d, 0xf4, 0x5d, 0x09, 0x66, 0x44, 0x21, 0x16, 0x41, 0xde, - 0xec, 0x0a, 0x0c, 0x13, 0xe6, 0x2e, 0x29, 0x79, 0xd9, 0x43, 0x24, 0xe6, 0x65, 0x3f, 0x52, 0xb0, - 0x44, 0x7c, 0x4f, 0x82, 0x19, 0x51, 0xa8, 0x8f, 0x83, 0x1a, 0x26, 0xdc, 0x5d, 0x52, 0xf3, 0x9a, - 0x07, 0x35, 0x17, 0xd2, 0xf3, 0x3e, 0xd4, 0x98, 0x42, 0xfe, 0xcb, 0x12, 0xcc, 0x88, 0x42, 0x2e, - 0x92, 0x74, 0xa3, 0x2b, 0x54, 0x3e, 0xc2, 0x7e, 0xd3, 0x4b, 0xd8, 0xe5, 0x4c, 0x20, 0x60, 0xf4, - 0x79, 0x80, 0x55, 0x45, 0x2f, 0xaa, 0x75, 0xb2, 0xad, 0x71, 0x21, 0xc4, 0xf5, 0xf6, 0x85, 0x95, - 0xf4, 0xb9, 0x10, 0xc5, 0xe4, 0x79, 0x97, 0x38, 0xcf, 0x10, 0x02, 0x2b, 0xce, 0x83, 0xbe, 0x4c, - 0x67, 0x09, 0xd2, 0x39, 0x3d, 0x1b, 0xcf, 0xb6, 0x34, 0xc2, 0x3c, 0x37, 0x40, 0x2b, 0x84, 0x83, - 0xb2, 0xe8, 0x02, 0x65, 0x0e, 0xcd, 0x1a, 0x5b, 0x19, 0x04, 0x11, 0x3d, 0xad, 0x9f, 0x7d, 0x97, - 0xfe, 0x7d, 0x0f, 0x7d, 0x51, 0x82, 0x61, 0x2b, 0xfc, 0x5d, 0x54, 0xeb, 0xc7, 0xca, 0x9c, 0x6b, - 0xd4, 0x57, 0xc7, 0x88, 0x2c, 0x01, 0x9b, 0x49, 0x4f, 0x71, 0x51, 0x30, 0x5b, 0xe4, 0x1b, 0xe3, - 0x29, 0xfd, 0x48, 0xf1, 0xa8, 0x76, 0x3c, 0x63, 0x74, 0xf0, 0xf8, 0xcf, 0xc2, 0xbd, 0x4c, 0xe4, - 0x42, 0xf8, 0x07, 0x24, 0xc8, 0xf7, 0xc5, 0x18, 0xcf, 0x18, 0x8c, 0x62, 0x3c, 0xbb, 0x24, 0x59, - 0x5c, 0x10, 0x12, 0x54, 0x34, 0x43, 0xcb, 0xd2, 0x2f, 0x6d, 0xbf, 0x2e, 0xc1, 0x10, 0xff, 0x4e, - 0x48, 0xf0, 0x84, 0xe2, 0xf2, 0xaa, 0x48, 0x3a, 0xfc, 0x43, 0x17, 0x64, 0x8e, 0x41, 0x90, 0xe4, - 0x20, 0x72, 0x9c, 0x93, 0x0d, 0xce, 0xd1, 0x2f, 0x75, 0xde, 0x33, 0xc0, 0x62, 0xce, 0xfd, 0x9a, - 0x19, 0x95, 0xb0, 0xc0, 0x5e, 0x0f, 0x17, 0xa8, 0x3c, 0x0a, 0xde, 0x9c, 0x0f, 0x5e, 0x6c, 0xda, - 0x5c, 0xf1, 0x66, 0xdf, 0x65, 0xdf, 0x20, 0x11, 0xd3, 0xf6, 0x35, 0x09, 0x46, 0x6d, 0xcf, 0x99, - 0x04, 0x23, 0x77, 0x7f, 0xff, 0xc4, 0xd3, 0x9a, 0xdd, 0x3e, 0x38, 0x4c, 0x8d, 0xc3, 0x18, 0x07, - 0xd3, 0x66, 0xd1, 0x02, 0x70, 0xa2, 0xdf, 0x92, 0x20, 0x49, 0x37, 0x08, 0xcd, 0x3e, 0xb5, 0x60, - 0x94, 0xee, 0x4f, 0x95, 0xa4, 0x6f, 0x44, 0xae, 0xc7, 0x76, 0xfc, 0x6e, 0x79, 0x0b, 0x30, 0x5e, - 0xd7, 0xb8, 0x13, 0xc1, 0xed, 0x54, 0xfe, 0xb6, 0x04, 0x93, 0xb4, 0x49, 0xf1, 0x0c, 0x9c, 0x16, - 0x3c, 0x25, 0xfa, 0x5c, 0xbf, 0x9f, 0xfe, 0x54, 0x77, 0x95, 0x19, 0x51, 0x2f, 0x79, 0x44, 0xc9, - 0x4f, 0xcb, 0xa9, 0x2c, 0xbb, 0x83, 0xc4, 0x0c, 0x96, 0x73, 0xb4, 0xfc, 0x65, 0xc9, 0x3c, 0x25, - 0x48, 0x66, 0x99, 0xcb, 0x21, 0x3f, 0x50, 0x2e, 0xac, 0xa4, 0xc3, 0x3e, 0x19, 0x42, 0x62, 0x6e, - 0x48, 0x84, 0x86, 0x62, 0x05, 0x0a, 0x2f, 0x89, 0x46, 0xc4, 0x20, 0x3e, 0xfa, 0xeb, 0x12, 0x0c, - 0x33, 0x27, 0x8a, 0xbd, 0x46, 0x11, 0xf6, 0xda, 0x62, 0xe1, 0x5d, 0x95, 0xf0, 0xf0, 0x2e, 0xb2, - 0x39, 0x9a, 0xc1, 0xb3, 0x34, 0x6f, 0x44, 0x1e, 0x30, 0xb1, 0x61, 0x5e, 0xfd, 0xa2, 0x04, 0xc3, - 0xcc, 0x21, 0x8a, 0x88, 0x4c, 0x78, 0xb9, 0x25, 0x3c, 0xb2, 0x6b, 0x44, 0xdf, 0x44, 0x64, 0x26, - 0xe7, 0xc6, 0xd3, 0x36, 0xce, 0x61, 0x88, 0x7f, 0x5b, 0x82, 0x31, 0x6b, 0x66, 0x34, 0x60, 0x9e, - 0xc4, 0xa0, 0x7e, 0xca, 0x0f, 0xdb, 0x99, 0x74, 0xda, 0xb6, 0x35, 0x63, 0x9b, 0x31, 0x31, 0xce, - 0xd2, 0x87, 0x12, 0xa7, 0x38, 0x93, 0xfe, 0xa6, 0x04, 0xe9, 0x55, 0x45, 0x17, 0x35, 0x8f, 0xfc, - 0x22, 0xda, 0xb2, 0x10, 0xe5, 0x73, 0xfe, 0x30, 0x41, 0x43, 0xbe, 0xbc, 0xbc, 0xec, 0xa1, 0xd2, - 0x57, 0xd0, 0x65, 0x87, 0x4a, 0xbf, 0x6b, 0x7d, 0x12, 0xf6, 0x1e, 0xcd, 0x64, 0xea, 0xf4, 0x0b, - 0x12, 0x4c, 0xe2, 0x55, 0x93, 0xf3, 0x19, 0x0a, 0x2f, 0x7f, 0x60, 0x31, 0xd2, 0x85, 0xc4, 0xd4, - 0x27, 0xc0, 0xab, 0x8c, 0x49, 0x18, 0x37, 0xa0, 0xda, 0xcd, 0x2a, 0x59, 0xf8, 0x1b, 0x50, 0x45, - 0xdf, 0xe0, 0x4f, 0x24, 0x98, 0xa0, 0xa6, 0x4c, 0x68, 0x56, 0x0b, 0x11, 0x3b, 0xf1, 0xbc, 0x1e, - 0x3a, 0x7d, 0xb3, 0xab, 0xba, 0xcc, 0x92, 0xde, 0x3b, 0x38, 0x4c, 0xcd, 0xbb, 0xd2, 0x82, 0x06, - 0x0c, 0x01, 0x64, 0x03, 0x21, 0x3f, 0x9b, 0x75, 0x1f, 0x01, 0x97, 0x59, 0xe3, 0x9b, 0x12, 0x24, - 0x73, 0xb5, 0x9a, 0xf8, 0xc4, 0xc7, 0xb5, 0x48, 0x40, 0x73, 0xb5, 0x5a, 0xfa, 0x6a, 0xa4, 0x1a, - 0x64, 0xca, 0x4e, 0xc3, 0x84, 0x8d, 0x18, 0x51, 0x0b, 0xb0, 0x47, 0x24, 0x6a, 0x01, 0xe7, 0x11, - 0xfd, 0x53, 0x09, 0xc6, 0xa9, 0x83, 0x23, 0x22, 0x7f, 0x21, 0x12, 0x0e, 0xda, 0x42, 0x54, 0xf0, - 0x85, 0x10, 0xe0, 0xc9, 0xca, 0xcf, 0x0d, 0xbc, 0xe8, 0x1e, 0xfd, 0xb2, 0x04, 0xe3, 0xd4, 0xdb, - 0x39, 0x0a, 0x19, 0xb4, 0x05, 0x4f, 0xff, 0x68, 0xf5, 0xe0, 0x30, 0x35, 0x03, 0x93, 0x36, 0xbc, - 0xd4, 0x47, 0x32, 0x01, 0x93, 0x95, 0x9f, 0x3f, 0x60, 0xf4, 0x47, 0x24, 0xa8, 0xce, 0x29, 0x05, - 0xd5, 0xd8, 0x97, 0x23, 0xdf, 0xdf, 0x6f, 0x28, 0xc4, 0x2b, 0x5d, 0xd4, 0x64, 0xea, 0xf0, 0xe9, - 0x83, 0xc3, 0xd4, 0x1c, 0x8c, 0x99, 0x56, 0xa8, 0xdd, 0x54, 0x5c, 0x95, 0xe1, 0xb2, 0x7c, 0xde, - 0x43, 0x19, 0x88, 0xa2, 0xf3, 0xaa, 0xf0, 0x4b, 0x12, 0x8c, 0x58, 0xaa, 0x40, 0x1e, 0x13, 0x59, - 0x88, 0x00, 0x10, 0xab, 0xc1, 0x95, 0x08, 0xe5, 0xc9, 0x2a, 0x3c, 0x05, 0x48, 0x20, 0x41, 0x94, - 0xa2, 0x53, 0xf2, 0x84, 0x6d, 0x50, 0x08, 0x68, 0x0c, 0xf6, 0x1f, 0x48, 0x30, 0x26, 0x28, 0x00, - 0xc1, 0xfb, 0x7c, 0x84, 0xfe, 0x99, 0xf0, 0x47, 0x82, 0x9c, 0x0b, 0x84, 0xec, 0x9c, 0xbb, 0x28, - 0x9f, 0xdf, 0x7d, 0xa4, 0xec, 0x1b, 0x11, 0xbd, 0x31, 0x41, 0xe4, 0x23, 0x03, 0x0f, 0x10, 0x77, - 0x6c, 0x5b, 0x4e, 0x59, 0x86, 0x92, 0x60, 0xb4, 0x09, 0xfb, 0x6c, 0xc6, 0x07, 0x24, 0xfa, 0xbe, - 0x29, 0xe6, 0xdc, 0x21, 0x9c, 0x10, 0x62, 0xee, 0x75, 0x0d, 0x68, 0xb0, 0x98, 0x7b, 0x5e, 0x7c, - 0x2a, 0xdf, 0x3f, 0x38, 0x4c, 0x9d, 0x76, 0x9e, 0xcd, 0xb1, 0x4b, 0xf9, 0x35, 0xf9, 0x8a, 0x87, - 0x94, 0x0b, 0x87, 0x77, 0x38, 0x61, 0xff, 0x8e, 0x24, 0x5c, 0x6f, 0x4b, 0xfc, 0x86, 0xab, 0x11, - 0x70, 0x86, 0xd9, 0xa9, 0xe5, 0x8a, 0x13, 0x7d, 0x0d, 0x41, 0x48, 0x06, 0x5d, 0x0a, 0x43, 0x08, - 0xf1, 0x21, 0x7e, 0x57, 0x82, 0x49, 0xea, 0x5c, 0xdb, 0x3e, 0x72, 0x40, 0x2f, 0x45, 0xbc, 0xcf, - 0x98, 0xc5, 0x32, 0x23, 0x11, 0xb4, 0x2d, 0x1a, 0x20, 0x4c, 0x10, 0xd5, 0x04, 0x1b, 0x45, 0xcf, - 0xc9, 0x17, 0x3d, 0x28, 0x6a, 0x37, 0x6a, 0x55, 0x9e, 0x2a, 0x3c, 0x2c, 0xbf, 0x63, 0x6e, 0x52, - 0xf3, 0xf4, 0x3c, 0x1f, 0x01, 0x18, 0x8b, 0x64, 0x46, 0xa2, 0xe5, 0x5e, 0x48, 0x5a, 0xae, 0xa6, - 0x43, 0x8f, 0x0e, 0x26, 0xe6, 0xf7, 0x25, 0x98, 0xb4, 0xdc, 0x7e, 0x9e, 0xa0, 0x93, 0x94, 0xb4, - 0x4a, 0x48, 0x62, 0x5e, 0x49, 0xbf, 0x18, 0x96, 0x18, 0xfb, 0x3a, 0x01, 0x13, 0x56, 0xfa, 0x68, - 0x10, 0x26, 0x2e, 0x2c, 0x7e, 0xc5, 0x34, 0xce, 0x47, 0x20, 0xca, 0xcb, 0x30, 0x6f, 0x1d, 0x1c, - 0xa6, 0xce, 0x58, 0x93, 0x07, 0xc6, 0xcf, 0xec, 0xb2, 0xdd, 0x08, 0x64, 0xc2, 0x1b, 0x81, 0xff, - 0x6a, 0x6e, 0x07, 0x70, 0x20, 0xb8, 0x67, 0x24, 0xae, 0x85, 0xbf, 0xbb, 0x9a, 0x69, 0x4e, 0x84, - 0xdb, 0xae, 0xe5, 0x66, 0xc8, 0x21, 0x59, 0x49, 0xdf, 0x0e, 0x45, 0x91, 0x78, 0x29, 0x3d, 0x35, - 0x11, 0xf4, 0x82, 0x6c, 0x3c, 0x3a, 0xff, 0x43, 0x82, 0x74, 0x49, 0xa9, 0x2b, 0x2d, 0x45, 0x65, - 0x46, 0x4f, 0xb8, 0xd6, 0x3c, 0xe2, 0x30, 0x05, 0xae, 0xfa, 0xf8, 0xc6, 0x65, 0x3d, 0x24, 0xa5, - 0x6b, 0xe9, 0xd5, 0xd0, 0xc2, 0x67, 0x51, 0x97, 0x2d, 0xd3, 0x43, 0x92, 0xf4, 0x06, 0x76, 0x7a, - 0x2b, 0x3b, 0xa6, 0xf8, 0x3f, 0x48, 0x30, 0x2e, 0x78, 0x9c, 0x64, 0x09, 0xaa, 0xa1, 0x57, 0x22, - 0xdd, 0x40, 0x2b, 0x4c, 0xc6, 0xaf, 0x76, 0x53, 0x95, 0xcd, 0xc6, 0x36, 0x09, 0x26, 0x0b, 0x5a, - 0xf7, 0x69, 0x4c, 0xbe, 0x90, 0xf5, 0x5d, 0x04, 0xdb, 0x56, 0x60, 0x4f, 0x79, 0x09, 0xbf, 0x74, - 0x70, 0x98, 0x9a, 0x70, 0xa3, 0x83, 0x80, 0x3f, 0x8f, 0xe4, 0x6c, 0xf0, 0x0a, 0xfe, 0xdb, 0x12, - 0x20, 0x21, 0x20, 0x46, 0xaf, 0x7f, 0x58, 0x8c, 0x02, 0x84, 0xcd, 0xbb, 0xd1, 0xc0, 0xe7, 0xc4, - 0x45, 0x3d, 0x05, 0x6f, 0x85, 0xc7, 0x64, 0xf9, 0xb4, 0x2f, 0x7a, 0xcc, 0xf2, 0x7f, 0x2c, 0x01, - 0x12, 0x42, 0x66, 0x5d, 0x60, 0x67, 0xd6, 0x22, 0x1a, 0xf6, 0x3b, 0xfe, 0xd8, 0x2f, 0xa6, 0x43, - 0x70, 0x9e, 0xb9, 0x09, 0x53, 0x8e, 0x80, 0x1a, 0x25, 0xe2, 0x64, 0x25, 0xa7, 0xe4, 0x4f, 0xc0, - 0x0b, 0xe9, 0x85, 0x60, 0x02, 0xec, 0xb3, 0x29, 0x26, 0xa6, 0xf4, 0xe3, 0x4b, 0x8c, 0x38, 0x83, - 0x7e, 0x4d, 0x02, 0x24, 0x2c, 0x6f, 0xba, 0x23, 0xc4, 0x6b, 0x0e, 0x5d, 0x39, 0x38, 0x4c, 0x4d, - 0x59, 0xb1, 0x07, 0x0a, 0x99, 0xdb, 0xee, 0x38, 0x9f, 0x09, 0xa3, 0xbb, 0xdf, 0xa4, 0xf1, 0x43, - 0xaf, 0x9b, 0x9a, 0xbd, 0x42, 0x70, 0x37, 0xa2, 0x5f, 0x13, 0x4a, 0xe3, 0x70, 0x79, 0x12, 0x81, - 0x38, 0x25, 0xa2, 0xb6, 0x47, 0xe3, 0xc8, 0x99, 0x34, 0x03, 0x3a, 0x43, 0x2b, 0x06, 0xe5, 0x0e, - 0x62, 0x70, 0xca, 0x39, 0x1b, 0x18, 0x91, 0xb9, 0xdb, 0xdd, 0x5e, 0x62, 0x6a, 0xcc, 0x0c, 0xaf, - 0x77, 0xdf, 0x00, 0x9b, 0x1f, 0x1e, 0x84, 0xa1, 0xf3, 0x35, 0xf9, 0xe5, 0x80, 0x21, 0x32, 0xee, - 0x9e, 0x72, 0x0d, 0xd8, 0xfd, 0x7b, 0x09, 0x26, 0xad, 0x28, 0x05, 0x7f, 0x67, 0xf6, 0x4b, 0xd1, - 0xf1, 0xe7, 0x6a, 0xb5, 0xf4, 0x62, 0xf4, 0x6a, 0xf2, 0x4f, 0x1c, 0x1c, 0xa6, 0x66, 0x21, 0xed, - 0x4a, 0xa8, 0xa5, 0x40, 0x2f, 0xc9, 0xd7, 0xa2, 0x52, 0xca, 0xdc, 0x9c, 0x94, 0x10, 0xda, 0xe0, - 0x89, 0x7c, 0x39, 0x3a, 0x5a, 0x16, 0xe8, 0xe8, 0x86, 0x4e, 0x25, 0x14, 0x9d, 0xb7, 0xd3, 0xaf, - 0x46, 0x1e, 0x51, 0x21, 0x0c, 0xf8, 0xbb, 0x12, 0xa4, 0x9c, 0x46, 0xa3, 0x7b, 0x8a, 0x03, 0x22, - 0x24, 0x55, 0xb2, 0x16, 0x9f, 0x71, 0xa5, 0x8a, 0xb3, 0x25, 0x9f, 0xca, 0x1c, 0x81, 0x2c, 0xf4, - 0x0f, 0xcd, 0x4d, 0x55, 0xf3, 0xdb, 0xe9, 0x10, 0x9b, 0xaa, 0xee, 0x17, 0xb3, 0x05, 0x5b, 0x1e, - 0x8f, 0x7b, 0x0b, 0xc9, 0xfe, 0xe3, 0x18, 0x8c, 0x92, 0x73, 0xba, 0x36, 0x37, 0x27, 0x2d, 0x4f, - 0xb2, 0xc3, 0xba, 0x4e, 0x9f, 0xec, 0x6b, 0x12, 0x77, 0xd7, 0x26, 0x71, 0xc8, 0xae, 0x84, 0x46, - 0x10, 0xf6, 0xd3, 0x04, 0x3a, 0x07, 0xbd, 0xe2, 0x0d, 0x70, 0x0e, 0x99, 0xc7, 0x9c, 0x0d, 0xae, - 0x0a, 0x56, 0xfc, 0xeb, 0x12, 0x8c, 0x5a, 0x5f, 0x73, 0xd2, 0x79, 0x26, 0x1b, 0xba, 0x67, 0xe6, - 0x7b, 0x45, 0x80, 0xca, 0xbe, 0x13, 0xe3, 0xa0, 0x8a, 0x07, 0x11, 0xdd, 0xb1, 0x62, 0x76, 0xfe, - 0x3d, 0x09, 0x46, 0xad, 0x73, 0xf4, 0x51, 0x91, 0x32, 0x4f, 0x2b, 0x02, 0xd2, 0xd7, 0x7c, 0x90, - 0x9e, 0x4d, 0xfb, 0x72, 0x15, 0xc3, 0xfd, 0x96, 0x04, 0xe3, 0xe2, 0x77, 0xac, 0x14, 0xf2, 0x49, - 0xc9, 0x40, 0xc1, 0x07, 0xee, 0xd5, 0xf4, 0x25, 0x3f, 0xb8, 0x76, 0x5f, 0xea, 0x5b, 0x64, 0x43, - 0xe1, 0xc7, 0x04, 0xba, 0xe8, 0x39, 0x7d, 0xc9, 0x3c, 0x2a, 0xd2, 0x25, 0x6c, 0xbf, 0xd3, 0x6e, - 0xe3, 0x30, 0xc6, 0x61, 0xb4, 0x1d, 0xef, 0xf4, 0x53, 0xb2, 0xff, 0x29, 0xc1, 0xb4, 0xe0, 0x73, - 0x70, 0xd6, 0x2c, 0xec, 0x6d, 0xed, 0xc7, 0x6d, 0xd4, 0xde, 0x3e, 0x38, 0x4c, 0x9d, 0x87, 0x69, - 0xc3, 0x7e, 0xdb, 0x6c, 0x47, 0xf8, 0xd8, 0xb0, 0x97, 0xf5, 0xfb, 0x37, 0xd6, 0x35, 0x47, 0xa2, - 0x11, 0x5c, 0x8c, 0x4a, 0x70, 0x34, 0x61, 0x7a, 0x10, 0x89, 0xae, 0x17, 0xd1, 0xa2, 0x2f, 0x5d, - 0xee, 0xe3, 0xf9, 0x07, 0x12, 0x4c, 0x09, 0xcb, 0xd6, 0xa7, 0x63, 0x3b, 0x2b, 0x07, 0x87, 0xa9, - 0x0b, 0x90, 0x72, 0x21, 0xcd, 0x35, 0x8a, 0xb2, 0x28, 0x5f, 0x8d, 0x44, 0x1b, 0x1e, 0xb5, 0x3f, - 0x96, 0x60, 0x4a, 0x58, 0xd4, 0x5a, 0x94, 0x5d, 0x8f, 0x3a, 0x6e, 0xd1, 0x4d, 0xee, 0xc3, 0x68, - 0x04, 0xde, 0x48, 0x77, 0x31, 0x78, 0x46, 0x0c, 0xcc, 0xb1, 0xf2, 0xb5, 0x28, 0x3d, 0x61, 0x09, - 0x55, 0xa3, 0x51, 0xb9, 0x9c, 0xbe, 0x15, 0x9d, 0x4a, 0xbb, 0x49, 0xa7, 0x51, 0xbf, 0x8f, 0x36, - 0xc5, 0xe2, 0x4c, 0xf0, 0x7e, 0x0c, 0x66, 0x9d, 0xeb, 0x3c, 0xce, 0xf0, 0x2e, 0x45, 0x0a, 0xd4, - 0x1c, 0xb3, 0xf5, 0xd5, 0x0f, 0x0e, 0x53, 0x59, 0x38, 0x2d, 0x7a, 0xcf, 0x76, 0x5b, 0x25, 0xbe, - 0x27, 0x46, 0x79, 0x73, 0x53, 0xbe, 0x6e, 0xf0, 0xc6, 0x20, 0xde, 0x7e, 0xdb, 0xb0, 0xb7, 0x4d, - 0xfe, 0x81, 0x24, 0xbe, 0xe1, 0x24, 0x1a, 0xe6, 0x1b, 0x5d, 0x31, 0x24, 0x9a, 0x24, 0xbc, 0xd3, - 0x2d, 0xdd, 0xb7, 0xd1, 0x6b, 0x61, 0xe9, 0x76, 0xb7, 0xd9, 0x3f, 0xb4, 0x3e, 0x60, 0x70, 0x23, - 0x03, 0xdd, 0xec, 0x8a, 0xfa, 0xe8, 0x46, 0xfc, 0xc9, 0xc1, 0x61, 0xea, 0x1a, 0xcc, 0x79, 0x72, - 0x80, 0x6a, 0x84, 0x1b, 0x0b, 0xb8, 0x35, 0x7f, 0x54, 0x16, 0xe0, 0xc1, 0xff, 0x42, 0xcc, 0xfc, - 0xe6, 0xe1, 0x18, 0x19, 0x10, 0xdd, 0xc8, 0xff, 0x99, 0xae, 0x19, 0xb0, 0x94, 0x3e, 0x9a, 0x0c, - 0x60, 0x2e, 0xfc, 0x95, 0x18, 0x9c, 0x71, 0x0f, 0x7a, 0x5a, 0x9c, 0x78, 0x1a, 0x8a, 0xf0, 0xd3, - 0x52, 0xd7, 0x6c, 0xd8, 0x48, 0x17, 0x8e, 0xc4, 0x06, 0xfb, 0xdc, 0x80, 0x59, 0x52, 0xfa, 0xb8, - 0xb3, 0xc4, 0x11, 0x80, 0x1d, 0x65, 0xa7, 0x37, 0xcc, 0x3b, 0xa9, 0xaf, 0x47, 0xbc, 0xf9, 0x3b, - 0xf4, 0x1c, 0xe1, 0x71, 0x4b, 0xb7, 0x3c, 0x47, 0x3f, 0xef, 0x96, 0xc7, 0xb3, 0x95, 0x3d, 0x7d, - 0xc7, 0x61, 0xcd, 0x97, 0x7e, 0x5b, 0xfa, 0xb9, 0xdc, 0x5f, 0x95, 0xd0, 0x2a, 0x8c, 0x58, 0xb7, - 0xa3, 0xcd, 0xe7, 0x36, 0x0b, 0xf2, 0x35, 0xb4, 0xb0, 0xa3, 0xeb, 0x1d, 0xed, 0xd5, 0x6c, 0xb6, - 0xde, 0xd0, 0x77, 0xf6, 0x1e, 0x2c, 0x54, 0xdb, 0xbb, 0x59, 0x8c, 0x22, 0xcb, 0x50, 0x64, 0x3b, - 0x8f, 0xea, 0x59, 0x0b, 0xc9, 0x62, 0xfc, 0xda, 0xc2, 0xf3, 0x19, 0x29, 0xb6, 0xc8, 0xbf, 0xed, - 0x9c, 0xfd, 0x29, 0xad, 0xdd, 0x12, 0x53, 0xea, 0x6a, 0xa7, 0xfa, 0xaa, 0xa3, 0xcc, 0xab, 0x8e, - 0x32, 0x9f, 0x09, 0xd9, 0x6f, 0xb6, 0xd2, 0x69, 0x90, 0x0a, 0x0f, 0x7a, 0xc9, 0x72, 0xeb, 0x85, - 0xff, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xbd, 0xe2, 0xd0, 0xf3, 0xe8, 0xbb, 0x00, 0x00, + // 8431 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0xbd, 0x6b, 0x6c, 0x1c, 0x59, + 0x76, 0x1f, 0x3e, 0xd5, 0xdd, 0x7c, 0x1d, 0xbe, 0x9a, 0x97, 0xaf, 0x56, 0x53, 0xa2, 0xa8, 0x1a, + 0x69, 0x24, 0xb5, 0x46, 0x6c, 0x0d, 0x67, 0x46, 0x9a, 0x19, 0xed, 0x8e, 0xb6, 0xc9, 0x6e, 0x51, + 0xfd, 0x1f, 0x92, 0xcd, 0x6d, 0x52, 0xa3, 0xff, 0xac, 0x8d, 0xe9, 0x6d, 0x75, 0x17, 0x9b, 0x6d, + 0x35, 0xbb, 0x7b, 0xab, 0x8a, 0xd2, 0x70, 0x27, 0x83, 0x24, 0x5c, 0x20, 0x30, 0xec, 0x6c, 0x92, + 0xf1, 0xe4, 0x81, 0x6c, 0xb2, 0x59, 0xef, 0x02, 0xf1, 0x06, 0x4e, 0x36, 0x0b, 0x03, 0x66, 0xbc, + 0x1b, 0x3b, 0xb1, 0x11, 0x27, 0x41, 0xec, 0x4d, 0x80, 0x18, 0x31, 0x6c, 0x07, 0xc8, 0x03, 0x59, + 0x27, 0x4e, 0x02, 0x04, 0x30, 0xf2, 0x82, 0xe1, 0xf9, 0x60, 0x04, 0xf7, 0x51, 0x55, 0xf7, 0xd6, + 0xbb, 0x9a, 0xa4, 0x76, 0x76, 0x76, 0x3e, 0x91, 0x7d, 0x9f, 0xbf, 0x73, 0xee, 0x39, 0xe7, 0x9e, + 0x7b, 0xee, 0xad, 0x7b, 0x21, 0xb9, 0x57, 0x6d, 0x57, 0x1b, 0xca, 0x9e, 0xd2, 0xd6, 0x17, 0xbb, + 0x6a, 0x47, 0xef, 0xa0, 0xf9, 0x5a, 0xb5, 0xa3, 0x2d, 0x7e, 0xb1, 0xa9, 0x57, 0xeb, 0x4a, 0x6b, + 0x91, 0xcb, 0xae, 0x76, 0x9b, 0x8b, 0x8f, 0x5f, 0x48, 0x9f, 0x6d, 0x74, 0x3a, 0x8d, 0x96, 0x92, + 0xad, 0x76, 0x9b, 0xd9, 0x6a, 0xbb, 0xdd, 0xd1, 0xab, 0x7a, 0xb3, 0xd3, 0xd6, 0x68, 0xed, 0xf4, + 0x1c, 0xcb, 0x25, 0xbf, 0x1e, 0xee, 0xef, 0x64, 0x95, 0xbd, 0xae, 0x7e, 0xc0, 0x32, 0xcf, 0xda, + 0x33, 0x35, 0x5d, 0xdd, 0xaf, 0xb1, 0x8e, 0xd3, 0xe7, 0xed, 0xb9, 0x7a, 0x73, 0x4f, 0xd1, 0xf4, + 0xea, 0x5e, 0x97, 0x15, 0x78, 0x9e, 0xfc, 0xa9, 0x5d, 0x6f, 0x28, 0xed, 0xeb, 0xda, 0x93, 0x6a, + 0xa3, 0xa1, 0xa8, 0xd9, 0x4e, 0x97, 0xf4, 0xee, 0x82, 0x64, 0xf6, 0x71, 0xb5, 0xd5, 0xac, 0x57, + 0x75, 0x25, 0x6b, 0xfc, 0xc3, 0x32, 0x16, 0xec, 0xfd, 0xd4, 0x15, 0xad, 0xa6, 0x36, 0xbb, 0x7a, + 0x47, 0x65, 0x25, 0x52, 0xd5, 0x7d, 0x7d, 0x97, 0xb6, 0x6c, 0x74, 0x40, 0x73, 0xe4, 0xb7, 0x61, + 0x74, 0x65, 0xb7, 0xda, 0x6e, 0x28, 0x65, 0xe5, 0x0b, 0xfb, 0x8a, 0xa6, 0xa3, 0x31, 0x88, 0x35, + 0xeb, 0x29, 0x69, 0x41, 0xba, 0x32, 0x54, 0x8e, 0x35, 0xeb, 0x68, 0x0a, 0xfa, 0x5a, 0xcd, 0xbd, + 0xa6, 0x9e, 0x8a, 0x2d, 0x48, 0x57, 0x12, 0x65, 0xfa, 0x03, 0x5d, 0x86, 0x71, 0x0d, 0x57, 0x68, + 0xd7, 0x94, 0x4a, 0x67, 0x67, 0x47, 0x53, 0xf4, 0x54, 0x9c, 0xe4, 0x8f, 0x19, 0xc9, 0x25, 0x92, + 0x2a, 0x1f, 0xc0, 0x00, 0x6d, 0x5f, 0x43, 0x9f, 0x81, 0x81, 0x1a, 0xfd, 0x37, 0x25, 0x2d, 0xc4, + 0xaf, 0x0c, 0x2f, 0x3d, 0xb7, 0xe8, 0x3f, 0x32, 0x8b, 0x0c, 0x99, 0x51, 0x0d, 0xcd, 0x40, 0x3f, + 0xeb, 0x8c, 0x82, 0x61, 0xbf, 0x2c, 0x8c, 0x71, 0x0e, 0xa3, 0xfc, 0xcf, 0x24, 0xe8, 0xa7, 0x2d, + 0xa0, 0xdb, 0x30, 0x4c, 0xdb, 0xa8, 0x60, 0xb6, 0x11, 0xea, 0x86, 0x97, 0xd2, 0x8b, 0x94, 0x6f, + 0x8b, 0x06, 0xdf, 0x16, 0xb7, 0x8d, 0xf1, 0x29, 0x03, 0x2d, 0x9e, 0xaf, 0xea, 0x0a, 0x3a, 0x07, + 0xa0, 0x3c, 0x56, 0xda, 0x7a, 0x45, 0x3f, 0xe8, 0x2a, 0xa4, 0xe7, 0xa1, 0xf2, 0x10, 0x49, 0xd9, + 0x3e, 0xe8, 0x2a, 0x28, 0x0d, 0x83, 0x06, 0xcd, 0xac, 0x7f, 0xf3, 0x37, 0x06, 0xac, 0xd4, 0x9b, + 0x7a, 0x47, 0x4d, 0x25, 0x48, 0x35, 0xf6, 0x0b, 0x5d, 0x83, 0x44, 0xbd, 0xaa, 0x57, 0x53, 0x7d, + 0x04, 0xc8, 0xac, 0x03, 0xc8, 0x16, 0x11, 0xa3, 0x32, 0x29, 0x24, 0xbf, 0x0e, 0xa3, 0xb9, 0x6e, + 0xb7, 0xd5, 0xac, 0x11, 0x69, 0x28, 0xe6, 0x1d, 0x43, 0x74, 0x0e, 0xa0, 0xab, 0x76, 0x7e, 0x42, + 0xa9, 0xe9, 0x95, 0x66, 0xdd, 0x00, 0xc8, 0x52, 0x8a, 0x75, 0x79, 0x0e, 0x86, 0x36, 0xd9, 0x0f, + 0x47, 0x5d, 0x39, 0x05, 0xfd, 0xf7, 0x35, 0x45, 0x75, 0xc9, 0x79, 0x16, 0x86, 0x71, 0x4e, 0x61, + 0xaf, 0xda, 0x6c, 0x15, 0xf3, 0x98, 0xc7, 0x0a, 0xfe, 0x97, 0x95, 0xa0, 0x3f, 0xe4, 0xb7, 0x61, + 0xe2, 0x7e, 0xbb, 0xf9, 0x85, 0x7d, 0x05, 0x17, 0x35, 0x44, 0xe8, 0x32, 0x0c, 0xed, 0x6b, 0x8a, + 0x5a, 0x69, 0x57, 0xf7, 0x28, 0xaf, 0x87, 0x96, 0xe1, 0xc3, 0xe5, 0x01, 0xb5, 0x2f, 0x29, 0xa5, + 0xfe, 0x85, 0x54, 0x1e, 0xc4, 0x99, 0x1b, 0xd5, 0x3d, 0x05, 0x2d, 0x18, 0x6d, 0xc6, 0x1c, 0x85, + 0x58, 0xfb, 0x2f, 0x00, 0xe2, 0xdb, 0xd7, 0xba, 0x9d, 0xb6, 0xa6, 0xa0, 0x39, 0x18, 0x6a, 0x6a, + 0x95, 0x7d, 0x92, 0x41, 0x3a, 0x18, 0x2c, 0x0f, 0x36, 0x35, 0x5a, 0x50, 0xfe, 0x2f, 0x7d, 0x30, + 0xb1, 0xa2, 0x2a, 0x55, 0xbd, 0x37, 0x4c, 0x57, 0x01, 0x76, 0x9a, 0xaa, 0xa6, 0xd3, 0x92, 0x4e, + 0x60, 0x43, 0x24, 0x97, 0x14, 0xbd, 0x0c, 0x43, 0xad, 0xaa, 0x51, 0x32, 0xee, 0x6c, 0x13, 0x67, + 0x92, 0x82, 0x97, 0x60, 0xa8, 0xdd, 0xac, 0x3d, 0xa2, 0x05, 0x89, 0x24, 0x2c, 0x0f, 0x7e, 0xb8, + 0xdc, 0xa7, 0xc6, 0x49, 0x31, 0x9c, 0x45, 0x8a, 0x5d, 0x83, 0x91, 0x7a, 0x53, 0xeb, 0xb6, 0xaa, + 0x07, 0xb4, 0x64, 0x9f, 0xad, 0xe4, 0x30, 0xcb, 0x25, 0x85, 0x6f, 0x01, 0xea, 0xaa, 0xca, 0x8e, + 0xa2, 0xaa, 0x4a, 0xbd, 0xd2, 0xaa, 0xb6, 0x1b, 0xfb, 0xd5, 0x86, 0x92, 0xea, 0xb7, 0x55, 0x99, + 0x30, 0xcb, 0xac, 0xb1, 0x22, 0xe8, 0x75, 0xe8, 0x6f, 0x28, 0xed, 0xba, 0xa2, 0xa6, 0x06, 0x16, + 0xa4, 0x2b, 0x63, 0xc1, 0x5a, 0xb8, 0x4a, 0x4a, 0x97, 0x59, 0x2d, 0x24, 0x1b, 0x83, 0x36, 0x48, + 0xfa, 0x1a, 0xf9, 0x70, 0x79, 0x48, 0x1d, 0x20, 0x14, 0x7f, 0xde, 0x18, 0x36, 0x94, 0x81, 0x89, + 0xa6, 0x56, 0x21, 0xff, 0x57, 0x1e, 0x2b, 0x6a, 0x73, 0xa7, 0xa9, 0xd4, 0x53, 0x43, 0x64, 0xa0, + 0xc6, 0x9b, 0x1a, 0x11, 0xa9, 0x37, 0x59, 0x32, 0x3a, 0x07, 0x7d, 0xdd, 0xdd, 0x4e, 0x5b, 0x49, + 0x0d, 0x93, 0xf6, 0x06, 0x3e, 0x5c, 0x4e, 0xa8, 0xb1, 0xd4, 0x54, 0x99, 0xa6, 0xb2, 0xa6, 0xc8, + 0xff, 0x56, 0x53, 0x23, 0x46, 0x53, 0x9b, 0x38, 0xdd, 0x6c, 0x4a, 0x86, 0x81, 0x5a, 0x67, 0xbf, + 0xad, 0xab, 0x07, 0xa9, 0x51, 0x1b, 0x23, 0x8c, 0x0c, 0x74, 0x11, 0x06, 0x5b, 0x9d, 0x5a, 0xb5, + 0xd5, 0xd4, 0x0f, 0x52, 0x63, 0xf6, 0xa1, 0x30, 0x72, 0xd0, 0x55, 0x18, 0xee, 0x76, 0x34, 0xbd, + 0xda, 0xaa, 0xd4, 0x3a, 0x75, 0x25, 0x35, 0x6e, 0x2b, 0x08, 0x34, 0x73, 0xa5, 0x53, 0xc7, 0x42, + 0xdc, 0xaf, 0x2a, 0x8d, 0x66, 0xa7, 0x9d, 0x4a, 0xda, 0x4a, 0xb1, 0x74, 0x94, 0x85, 0x31, 0x4d, + 0x57, 0x15, 0x45, 0xaf, 0x54, 0xeb, 0x75, 0x55, 0xd1, 0xb4, 0xd4, 0x84, 0xad, 0xe4, 0x28, 0xcd, + 0xcf, 0xd1, 0x6c, 0xf4, 0x2c, 0x0c, 0x76, 0xab, 0x9a, 0xf6, 0xa4, 0xa3, 0xd6, 0x53, 0x88, 0xe7, + 0xca, 0xbd, 0xb2, 0x99, 0x21, 0x7f, 0xd0, 0x0f, 0x09, 0x2c, 0xe1, 0x0e, 0x73, 0x70, 0x07, 0xfa, + 0x34, 0x1d, 0x9b, 0xb9, 0x18, 0x19, 0xdf, 0xab, 0x41, 0xe3, 0x8b, 0x1b, 0xd9, 0xc2, 0x15, 0xca, + 0xb4, 0x1e, 0xba, 0x03, 0xa3, 0x35, 0xac, 0x40, 0xcd, 0x4e, 0x9b, 0xda, 0xcb, 0x78, 0xa0, 0xbd, + 0x1c, 0x31, 0x2a, 0x10, 0x8b, 0x69, 0x33, 0xb7, 0x89, 0x48, 0xe6, 0x76, 0x8e, 0xd7, 0x54, 0xa2, + 0x02, 0x9c, 0x76, 0x9e, 0x13, 0xb4, 0xb3, 0x9f, 0x9a, 0x3a, 0x4b, 0x23, 0xe7, 0x78, 0x8d, 0x1c, + 0xa0, 0x75, 0x4d, 0x2d, 0xbc, 0x60, 0x53, 0x2f, 0x22, 0xbf, 0xa2, 0x52, 0xcd, 0xf1, 0x8a, 0x3a, + 0x44, 0xeb, 0x9b, 0xea, 0x79, 0xdd, 0x55, 0xe3, 0x80, 0x94, 0xf2, 0xd5, 0xb3, 0xe1, 0x9e, 0xf4, + 0xcc, 0x34, 0xb8, 0x23, 0x9c, 0xc1, 0x75, 0xd7, 0xac, 0x51, 0x77, 0xcd, 0x9a, 0x32, 0x34, 0x6b, + 0x8c, 0xb6, 0xe0, 0xa3, 0x50, 0xe3, 0xee, 0x0a, 0x95, 0xb2, 0x14, 0x8a, 0x08, 0xb7, 0xa5, 0x46, + 0x69, 0x4e, 0x8d, 0x26, 0x18, 0xa3, 0x0d, 0xe5, 0x39, 0x2f, 0x2a, 0x0f, 0x91, 0x60, 0x41, 0x65, + 0x66, 0x4c, 0x95, 0x99, 0xa4, 0xd3, 0x22, 0x53, 0x94, 0x4b, 0x0e, 0x45, 0x99, 0x22, 0xf9, 0x36, + 0xf5, 0xe0, 0x67, 0xdc, 0x69, 0x71, 0xc6, 0x95, 0x7f, 0x6d, 0x00, 0x06, 0xb1, 0x40, 0xbf, 0xd9, + 0x54, 0x9e, 0x7c, 0xdc, 0x34, 0xe3, 0x55, 0x00, 0x22, 0xdd, 0xad, 0x4e, 0xa3, 0xd9, 0x66, 0xbe, + 0x83, 0x5f, 0x5d, 0xa2, 0x0b, 0x6b, 0xb8, 0x30, 0x2a, 0x40, 0xd2, 0x30, 0x1c, 0x15, 0xda, 0x62, + 0x9d, 0x68, 0x8f, 0x7f, 0x03, 0xe3, 0x46, 0x1d, 0xea, 0x46, 0xd5, 0x45, 0xdd, 0x1c, 0xf0, 0xd5, + 0xcd, 0x41, 0x5f, 0xdd, 0x1c, 0x0a, 0xd0, 0x4d, 0x08, 0xd0, 0xcd, 0xe1, 0x50, 0xba, 0x39, 0x12, + 0xac, 0x9b, 0xa3, 0xc7, 0xd3, 0xcd, 0xb1, 0x40, 0xdd, 0x1c, 0x0f, 0xd0, 0xcd, 0x64, 0xa0, 0x6e, + 0x4e, 0x04, 0xea, 0x26, 0xf2, 0xd6, 0xcd, 0x49, 0x7f, 0xdd, 0x9c, 0xf2, 0xd1, 0xcd, 0xe9, 0x00, + 0xdd, 0x9c, 0x09, 0xd2, 0xcd, 0x59, 0x9b, 0x37, 0x7c, 0x09, 0xc6, 0x54, 0x45, 0xeb, 0xec, 0xab, + 0x78, 0xd1, 0xf0, 0xa4, 0xad, 0xa8, 0xa9, 0x14, 0x6d, 0xc2, 0x48, 0x2d, 0xe1, 0x44, 0xf9, 0x4f, + 0x24, 0x98, 0x20, 0x9a, 0xa7, 0x54, 0xd5, 0xda, 0xae, 0xe1, 0xc0, 0x59, 0xbe, 0xbf, 0xe4, 0xee, + 0xfb, 0x0b, 0xeb, 0x93, 0xb7, 0x61, 0x4c, 0xeb, 0xa8, 0x7a, 0xb3, 0xdd, 0xa8, 0xd4, 0x3a, 0xad, + 0xfd, 0xbd, 0x36, 0xd1, 0xd4, 0xb1, 0xa5, 0xeb, 0xa1, 0x54, 0x9e, 0x74, 0xfc, 0x86, 0x72, 0x40, + 0x66, 0xe8, 0x43, 0x29, 0xb6, 0xf0, 0x4c, 0x79, 0x94, 0x35, 0xb7, 0x42, 0x5a, 0x43, 0x49, 0x88, + 0x57, 0xb5, 0x1a, 0xd1, 0xdf, 0xc1, 0x32, 0xfe, 0x17, 0x15, 0x61, 0xe0, 0x0b, 0xfb, 0x8a, 0xda, + 0x54, 0xb4, 0x54, 0x1f, 0x59, 0xdd, 0x64, 0xc3, 0x77, 0xf5, 0xd9, 0x7d, 0x45, 0x3d, 0x28, 0x1b, + 0xf5, 0xe5, 0xef, 0x48, 0x30, 0x6e, 0xcb, 0x44, 0x45, 0x88, 0x3f, 0x52, 0x0e, 0x08, 0xed, 0xc7, + 0xa0, 0x02, 0xb7, 0x81, 0xf2, 0xd0, 0xbf, 0xa7, 0xe8, 0xbb, 0x9d, 0x3a, 0x33, 0x83, 0xcf, 0x07, + 0xb5, 0x46, 0x5b, 0x5a, 0x27, 0x75, 0xca, 0xac, 0x2e, 0xe6, 0xfb, 0xe3, 0x6a, 0x6b, 0x9f, 0x39, + 0xbe, 0x65, 0xfa, 0x43, 0xfe, 0xa6, 0x04, 0x88, 0x1f, 0x3b, 0xe6, 0xb0, 0x47, 0x1b, 0xbc, 0x0b, + 0x30, 0xa2, 0x77, 0xb0, 0x88, 0xaa, 0x8a, 0xb6, 0xdf, 0x32, 0x56, 0x75, 0xc3, 0x24, 0xad, 0x4c, + 0x92, 0xd0, 0x67, 0xb0, 0x94, 0x92, 0xcc, 0x04, 0x61, 0xf6, 0x95, 0x30, 0x1c, 0xc1, 0x73, 0x42, + 0x99, 0xd5, 0x93, 0x7f, 0x35, 0x4e, 0xd7, 0x37, 0x9b, 0x6a, 0x67, 0xa7, 0xd9, 0x52, 0xdc, 0x16, + 0x55, 0xf6, 0x75, 0x80, 0xa7, 0x35, 0x8b, 0xdb, 0xac, 0xd9, 0x9c, 0xc3, 0xdf, 0xe7, 0x4c, 0xd5, + 0x05, 0x37, 0x2f, 0x5f, 0x34, 0x75, 0xd7, 0xbd, 0x7d, 0xfb, 0xd3, 0xf0, 0xe8, 0x05, 0xab, 0x3e, + 0x68, 0xb3, 0xea, 0xbc, 0x42, 0x0f, 0xd9, 0x14, 0xda, 0x31, 0x1d, 0xc2, 0xf1, 0xa6, 0xc3, 0xe1, + 0x28, 0xd3, 0xa1, 0xfc, 0xbd, 0x18, 0xa4, 0xee, 0x77, 0xeb, 0x6c, 0xa1, 0xc7, 0xc6, 0xd1, 0x2b, + 0x8c, 0xf1, 0xc9, 0xb2, 0xce, 0x5f, 0x08, 0xe4, 0x3f, 0x92, 0x60, 0xc8, 0x5c, 0xef, 0xbb, 0x45, + 0x81, 0xb8, 0x95, 0xba, 0xef, 0x84, 0x17, 0x77, 0x9f, 0xf0, 0x78, 0x39, 0x4a, 0x04, 0xc9, 0x51, + 0xdf, 0xf1, 0xe4, 0xa8, 0x3f, 0x92, 0x1c, 0x3d, 0x86, 0x19, 0x4b, 0x8c, 0x08, 0x68, 0x2f, 0x21, + 0x0a, 0x8c, 0x57, 0x44, 0xe1, 0x88, 0xc9, 0x71, 0x32, 0xad, 0xbb, 0x71, 0x9c, 0x3a, 0x08, 0xb1, + 0x40, 0x07, 0x21, 0xee, 0xee, 0x20, 0xf0, 0x1c, 0xef, 0x0b, 0xe2, 0x78, 0xff, 0xf1, 0x38, 0x3e, + 0x10, 0x89, 0xe3, 0xfb, 0x3c, 0xc7, 0x09, 0x68, 0x2f, 0x8e, 0x9f, 0x17, 0xb8, 0xb0, 0x3c, 0xf4, + 0xe1, 0x72, 0xbf, 0x9a, 0x48, 0x4a, 0x01, 0xe1, 0x01, 0x77, 0x86, 0xc8, 0xff, 0x2a, 0x46, 0x4d, + 0xbe, 0xe1, 0xab, 0xd8, 0x3b, 0xe3, 0x3c, 0xaa, 0x98, 0xb7, 0x47, 0x15, 0xf7, 0xf7, 0xa8, 0x12, + 0x3e, 0x1e, 0x55, 0x5f, 0x80, 0x47, 0xd5, 0x1f, 0xe4, 0x51, 0x0d, 0x04, 0x0d, 0xe3, 0xe0, 0xf1, + 0x86, 0x71, 0x28, 0xd2, 0x30, 0xfe, 0x2f, 0x89, 0x37, 0xc0, 0x0c, 0xaf, 0xd7, 0x48, 0xca, 0x36, + 0xe6, 0x06, 0xc5, 0x66, 0xe2, 0x61, 0x63, 0x33, 0x89, 0x50, 0xb1, 0x99, 0xbe, 0xd0, 0xb1, 0x99, + 0x7e, 0xdf, 0xd8, 0x8c, 0x5c, 0x82, 0x91, 0xf5, 0xfd, 0x96, 0xde, 0xbc, 0x5b, 0xad, 0xe9, 0x1d, + 0x55, 0x43, 0x77, 0x20, 0xb1, 0xb7, 0x53, 0x35, 0x42, 0xda, 0xd7, 0x82, 0xac, 0x2e, 0x57, 0xb7, + 0x4c, 0x2a, 0xca, 0x3f, 0x25, 0xc1, 0x30, 0x97, 0x8a, 0x6e, 0x43, 0x82, 0x04, 0x9a, 0xa9, 0xab, + 0x77, 0x39, 0xb0, 0xc1, 0x9d, 0xea, 0xf6, 0x41, 0x57, 0x29, 0x93, 0x4a, 0xe8, 0x75, 0x71, 0x85, + 0x1b, 0xe8, 0x16, 0xad, 0xdf, 0xcd, 0xf1, 0x0b, 0x5c, 0xf9, 0x2c, 0xc0, 0x26, 0x5b, 0xf3, 0xb9, + 0x84, 0x84, 0xef, 0xc1, 0xb8, 0x91, 0xeb, 0x35, 0xcc, 0x97, 0xb8, 0xd0, 0x95, 0x4d, 0x67, 0xf9, + 0xe0, 0xd5, 0x73, 0x30, 0x55, 0x56, 0x34, 0x45, 0x0f, 0x68, 0x4e, 0x7e, 0x0c, 0xf3, 0x5b, 0x56, + 0xa9, 0x8d, 0x8e, 0xde, 0xdc, 0x61, 0x71, 0x70, 0x2f, 0x00, 0x79, 0xc6, 0x3e, 0xca, 0x80, 0x1b, + 0x41, 0x0c, 0xe0, 0x9b, 0xb4, 0xf8, 0x28, 0x3f, 0x0f, 0x69, 0xa3, 0xd3, 0x95, 0xce, 0x5e, 0xb7, + 0xa5, 0xbc, 0xd3, 0xd4, 0x0f, 0x36, 0x3b, 0xad, 0x66, 0xed, 0xc0, 0x85, 0x2f, 0x7f, 0x18, 0x87, + 0x94, 0x57, 0x71, 0x97, 0x49, 0x64, 0xd8, 0xd8, 0x9f, 0xc1, 0x82, 0x19, 0x63, 0xee, 0x9f, 0x95, + 0x84, 0x72, 0xc6, 0x20, 0xd2, 0x35, 0x4b, 0xa0, 0x4c, 0xd1, 0x8e, 0xfc, 0x03, 0x15, 0x89, 0xe3, + 0x19, 0x86, 0xbe, 0xa8, 0x3b, 0x26, 0x7b, 0xcd, 0x76, 0xa5, 0xa5, 0xb4, 0x1b, 0xfa, 0x2e, 0x51, + 0xa8, 0x44, 0x79, 0x68, 0xaf, 0xd9, 0x5e, 0x23, 0x09, 0xe8, 0x59, 0x18, 0xdd, 0xad, 0x6a, 0x95, + 0x56, 0xe7, 0x89, 0xa2, 0xd6, 0xaa, 0x1a, 0x35, 0x6b, 0x83, 0xe5, 0x91, 0xdd, 0xaa, 0xb6, 0x66, + 0xa4, 0x19, 0x85, 0xf6, 0xbb, 0x5d, 0x56, 0x68, 0xd0, 0x2c, 0x74, 0xdf, 0x48, 0xc3, 0x1d, 0xe1, + 0x42, 0xed, 0xfd, 0xbd, 0x87, 0x8a, 0xca, 0x02, 0xcc, 0x43, 0xbb, 0x55, 0x6d, 0x83, 0x24, 0x18, + 0xd9, 0xda, 0xc1, 0xde, 0xc3, 0x4e, 0x8b, 0x38, 0xa7, 0x34, 0x7b, 0x8b, 0x24, 0x08, 0x96, 0x75, + 0xd8, 0x66, 0x59, 0xcf, 0x01, 0x34, 0xb5, 0x4a, 0x5d, 0xd9, 0xa9, 0xe2, 0x45, 0x06, 0x8d, 0x37, + 0x0f, 0x35, 0xb5, 0x3c, 0x4d, 0x90, 0xff, 0xb7, 0x04, 0xf3, 0x5e, 0x23, 0x4e, 0x37, 0x1f, 0x50, + 0x46, 0x1c, 0x67, 0x89, 0x37, 0x2b, 0xff, 0x27, 0x2e, 0x8e, 0xb8, 0xc8, 0xb0, 0x58, 0x20, 0xc3, + 0xe2, 0x61, 0x18, 0x96, 0x08, 0x64, 0x58, 0x9f, 0x3f, 0xc3, 0xfa, 0x6d, 0x0c, 0x93, 0xbf, 0x14, + 0xf3, 0xa6, 0x9a, 0x4e, 0x04, 0x0e, 0x69, 0xcf, 0xb8, 0x48, 0x7b, 0x38, 0x2e, 0xc4, 0x03, 0xb9, + 0x90, 0x08, 0xc3, 0x85, 0xbe, 0x40, 0x2e, 0xf4, 0xfb, 0x73, 0x61, 0xc0, 0xce, 0x85, 0x4b, 0x30, + 0x69, 0x30, 0x21, 0xd7, 0x50, 0x3c, 0x8d, 0xc2, 0x97, 0xe3, 0x30, 0xe1, 0x28, 0xf7, 0xa3, 0x68, + 0x0d, 0x16, 0x60, 0x64, 0xaf, 0xfa, 0x4e, 0xa5, 0x4a, 0x6a, 0x1f, 0x68, 0xcc, 0x1e, 0xc0, 0x5e, + 0xf5, 0x9d, 0x1c, 0x2e, 0x71, 0xa0, 0xa1, 0x2b, 0x90, 0x54, 0xde, 0xe9, 0x36, 0x55, 0xa5, 0xf2, + 0xa4, 0xaa, 0xb6, 0x69, 0x29, 0xea, 0xea, 0x8c, 0xd1, 0xf4, 0x07, 0x55, 0xb5, 0x4d, 0x4a, 0xf2, + 0x2a, 0x3b, 0xe8, 0xab, 0xb2, 0x43, 0x76, 0x95, 0x7d, 0x5f, 0x82, 0x59, 0xc7, 0x78, 0xf4, 0xa0, + 0xab, 0x76, 0x72, 0x62, 0xa1, 0xc8, 0x89, 0xbb, 0x91, 0x23, 0x7f, 0xdd, 0x0d, 0xd3, 0x09, 0x68, + 0x92, 0x1d, 0x63, 0x3c, 0x14, 0xc6, 0x84, 0x2b, 0xc6, 0xab, 0x16, 0xc4, 0xb5, 0x4e, 0xed, 0x51, + 0x67, 0x5f, 0xf7, 0x14, 0xf9, 0xaf, 0xc6, 0x61, 0xda, 0xb5, 0xec, 0x8f, 0xa2, 0xd8, 0x5f, 0x60, + 0x63, 0xa0, 0xeb, 0xca, 0x5e, 0x57, 0x37, 0xc4, 0x7e, 0x18, 0x8f, 0x01, 0x4b, 0x42, 0x2f, 0xc2, + 0x8c, 0xb6, 0xdb, 0x79, 0x52, 0x69, 0x75, 0x6a, 0x8f, 0x2a, 0x9d, 0x7d, 0xbd, 0xb2, 0x53, 0x6d, + 0xb6, 0xf6, 0x55, 0x45, 0x63, 0x46, 0x67, 0x12, 0xe7, 0x62, 0x46, 0x96, 0xf6, 0xf5, 0xbb, 0x2c, + 0xeb, 0x38, 0x2a, 0xf0, 0x75, 0x09, 0xe6, 0x5c, 0xc7, 0xa7, 0x07, 0x35, 0xb0, 0x93, 0x17, 0x8b, + 0x42, 0x5e, 0xdc, 0x93, 0x3c, 0xf9, 0x17, 0xbc, 0x30, 0x9e, 0x80, 0x5a, 0xd8, 0x31, 0xc7, 0xa3, + 0x60, 0x4e, 0x78, 0x63, 0x9e, 0x85, 0xbe, 0x92, 0xda, 0x70, 0x3d, 0x43, 0x31, 0x54, 0x52, 0x1b, + 0xf9, 0xce, 0x5e, 0xb5, 0xd9, 0xc6, 0xeb, 0xc0, 0x3a, 0xf9, 0x8f, 0x15, 0x60, 0xbf, 0xe4, 0xbf, + 0x11, 0x83, 0x78, 0x49, 0x6d, 0x38, 0x28, 0x8b, 0xea, 0xcb, 0x97, 0xd4, 0xc6, 0x47, 0x68, 0xb3, + 0x0a, 0x41, 0x82, 0x0b, 0x6f, 0x92, 0xff, 0x39, 0x0e, 0xf4, 0xf3, 0x1c, 0xf0, 0x5b, 0xe2, 0xca, + 0xcf, 0xc1, 0x58, 0x49, 0x6d, 0xac, 0x2b, 0x78, 0x66, 0x2e, 0x77, 0x5a, 0x8a, 0x86, 0xa6, 0xa0, + 0x4f, 0xc5, 0xff, 0x90, 0x25, 0xd7, 0x50, 0x99, 0xfe, 0x90, 0x7f, 0x5b, 0x22, 0xbc, 0xa6, 0x05, + 0xd1, 0x2c, 0x0c, 0x90, 0x90, 0xa6, 0xc9, 0xd0, 0x7e, 0xfc, 0xb3, 0x58, 0xb7, 0x2a, 0xc7, 0xb8, + 0xca, 0x76, 0x4a, 0xe3, 0x91, 0x28, 0x3d, 0xb6, 0x99, 0xf1, 0x09, 0xd4, 0xc8, 0x3f, 0x06, 0x93, + 0xb9, 0x7a, 0xdd, 0xe2, 0x00, 0x5b, 0xf5, 0x4c, 0x43, 0x7f, 0x47, 0x6d, 0x58, 0xe4, 0xf5, 0x75, + 0xd4, 0x46, 0xb1, 0xce, 0x93, 0x1d, 0x73, 0x27, 0x3b, 0xce, 0xf3, 0xec, 0x6d, 0x98, 0xa1, 0x3b, + 0x7b, 0xa7, 0xd4, 0xfe, 0x3d, 0x98, 0x29, 0x2b, 0x7b, 0x9d, 0xc7, 0xc7, 0x6e, 0x5f, 0xfe, 0x96, + 0x04, 0xb3, 0x66, 0x23, 0xa7, 0xbd, 0xb9, 0x90, 0xb3, 0x6d, 0x2e, 0x5c, 0x0d, 0xa1, 0x79, 0x8c, + 0x3c, 0x63, 0x77, 0xe1, 0x5b, 0x12, 0xcc, 0x38, 0xf0, 0xfa, 0x92, 0x1e, 0xe9, 0x6c, 0x1b, 0xda, + 0xb0, 0x76, 0x9b, 0x28, 0xc6, 0x97, 0x42, 0x63, 0x74, 0xdd, 0x72, 0xfa, 0x27, 0x12, 0x4c, 0xb9, + 0x95, 0x40, 0x1b, 0xfc, 0xbe, 0xd3, 0x52, 0xc4, 0x4e, 0x9e, 0xf2, 0xe6, 0xd3, 0x4d, 0x98, 0x62, + 0x07, 0xdd, 0xe8, 0x7c, 0x66, 0x70, 0x7c, 0x9e, 0x99, 0x22, 0xe7, 0xb1, 0x2f, 0x92, 0x2e, 0xdf, + 0x35, 0xeb, 0xd1, 0x39, 0xc6, 0x2b, 0xb4, 0x60, 0xb4, 0x13, 0xf3, 0x68, 0xa7, 0x04, 0x83, 0xac, + 0x1d, 0x0d, 0xad, 0xc0, 0x20, 0x3b, 0x81, 0x67, 0x84, 0x86, 0x02, 0x23, 0x39, 0xac, 0x6e, 0xd9, + 0xac, 0x28, 0xff, 0x74, 0x0c, 0x06, 0x58, 0xaa, 0x03, 0x0c, 0xe2, 0xc1, 0x30, 0xfb, 0xba, 0x2c, + 0xfa, 0x4c, 0xcf, 0x87, 0xec, 0x51, 0x98, 0x35, 0x8e, 0x65, 0xf4, 0x8f, 0x1d, 0xc8, 0xe7, 0x4d, + 0x61, 0xbf, 0xcd, 0x14, 0xfe, 0x92, 0x04, 0x67, 0x57, 0xd5, 0x6a, 0x5b, 0x57, 0xea, 0x06, 0xf0, + 0x53, 0x36, 0x04, 0x77, 0x6d, 0x86, 0x60, 0x31, 0x70, 0x4f, 0x45, 0x80, 0x67, 0x5a, 0x83, 0x3f, + 0x88, 0xc3, 0x98, 0x98, 0xf5, 0x23, 0x32, 0x9c, 0x77, 0x58, 0x30, 0xae, 0x3f, 0xa4, 0x0f, 0x4f, + 0x09, 0xe0, 0xe2, 0x99, 0xce, 0x23, 0x03, 0x03, 0x2e, 0x47, 0x06, 0x38, 0x9b, 0x3a, 0xc8, 0xdb, + 0xd4, 0x33, 0x30, 0x88, 0x93, 0xb9, 0x13, 0x27, 0x03, 0x1d, 0xb5, 0x61, 0x1c, 0x56, 0xc1, 0x59, + 0xcc, 0x1d, 0xa1, 0xc7, 0x4d, 0x86, 0x3a, 0xa6, 0xaf, 0x76, 0x06, 0x06, 0x1b, 0x78, 0xc0, 0x70, + 0x93, 0xf4, 0xac, 0xc9, 0x00, 0xf9, 0x5d, 0x14, 0xb7, 0x55, 0x46, 0x6c, 0x22, 0xfa, 0xb3, 0x12, + 0xcc, 0xb9, 0x8b, 0x68, 0x2f, 0x87, 0x18, 0xb6, 0x2c, 0x23, 0x1f, 0x27, 0xf2, 0xf7, 0x6a, 0x34, + 0xf9, 0x73, 0xb5, 0xf4, 0xff, 0x52, 0x82, 0x33, 0x9e, 0xc5, 0xd0, 0x16, 0x6f, 0xee, 0x6f, 0xf5, + 0xd2, 0xdd, 0x53, 0xb6, 0xf9, 0x19, 0x40, 0xac, 0xfb, 0x60, 0x17, 0xf1, 0xf7, 0x24, 0x18, 0x15, + 0x0a, 0x7f, 0x7c, 0xdc, 0xc4, 0xcf, 0x42, 0x52, 0xa0, 0x2c, 0x57, 0xaf, 0x3b, 0x4c, 0x4c, 0x44, + 0xe7, 0x6d, 0x1b, 0x26, 0x85, 0x26, 0xd9, 0x51, 0xfa, 0x63, 0xb6, 0xfa, 0xba, 0xad, 0x55, 0xea, + 0x1f, 0x86, 0x6e, 0x55, 0x7e, 0x04, 0x63, 0x86, 0x75, 0xed, 0xb4, 0x14, 0x37, 0x32, 0x93, 0x54, + 0x84, 0x69, 0x35, 0x22, 0x7f, 0xf6, 0x13, 0x17, 0x71, 0xe7, 0x89, 0x8b, 0x29, 0xe8, 0x6b, 0xa8, + 0x9d, 0xfd, 0x2e, 0xdb, 0xbe, 0xa3, 0x3f, 0xe4, 0x36, 0x4c, 0x70, 0x9d, 0x79, 0x30, 0xe0, 0x04, + 0xfb, 0x7b, 0x3f, 0x06, 0xc3, 0x5c, 0x87, 0xb6, 0x83, 0xfd, 0x92, 0xed, 0x60, 0x7f, 0x6f, 0x3d, + 0xff, 0x60, 0x83, 0x22, 0x26, 0xdd, 0xfd, 0x1c, 0xdd, 0xbe, 0xeb, 0xbf, 0xdf, 0x93, 0x60, 0x9c, + 0xe3, 0x09, 0x39, 0xd7, 0xf9, 0x91, 0xe4, 0x4b, 0x74, 0xd2, 0x5e, 0x16, 0xc4, 0xcb, 0x43, 0x13, + 0x1c, 0xc4, 0xc8, 0x47, 0x12, 0x9c, 0xe1, 0xea, 0x9d, 0xb6, 0x13, 0xb4, 0x6a, 0x73, 0x82, 0xb2, + 0x61, 0xfd, 0x58, 0x36, 0x5a, 0xa6, 0x17, 0xf4, 0x5d, 0x09, 0x52, 0x2e, 0xb8, 0xe9, 0xcc, 0x18, + 0x30, 0xa4, 0xd1, 0x56, 0x47, 0x9b, 0xf6, 0xd5, 0xd1, 0xcd, 0x08, 0x98, 0x5d, 0x67, 0xcd, 0x7f, + 0x2e, 0xc1, 0x8c, 0x7b, 0x19, 0xb4, 0xc9, 0x4f, 0x99, 0x2f, 0x45, 0xee, 0xe8, 0x29, 0xcf, 0x97, + 0xdf, 0x8b, 0x99, 0x42, 0x47, 0x0d, 0x30, 0x51, 0x28, 0xcf, 0x79, 0x50, 0x38, 0x1a, 0x16, 0xb3, + 0x1d, 0x0d, 0x33, 0x0f, 0x05, 0xc5, 0xf9, 0x43, 0x41, 0xe2, 0xc1, 0xb9, 0x84, 0xef, 0xc1, 0xb9, + 0x3e, 0xdb, 0xc1, 0x39, 0x73, 0xce, 0xe8, 0xf7, 0x99, 0x76, 0x07, 0x8e, 0x37, 0xed, 0x0e, 0x1e, + 0x63, 0xda, 0x05, 0x9b, 0x06, 0x7f, 0x57, 0x82, 0x39, 0x81, 0x9b, 0xa7, 0xad, 0x8c, 0x45, 0x9b, + 0x32, 0xbe, 0x10, 0x52, 0xde, 0xac, 0xb1, 0x36, 0xd5, 0xf1, 0x1f, 0x49, 0x90, 0x76, 0xc5, 0x7e, + 0x0a, 0x0a, 0x59, 0xb6, 0x2b, 0xe4, 0x2b, 0x91, 0x70, 0xbb, 0xaa, 0xe4, 0x6f, 0x5a, 0xe6, 0xc4, + 0x19, 0xb6, 0x28, 0xf3, 0x4a, 0x79, 0xb3, 0x87, 0xce, 0x9e, 0xb2, 0x5a, 0xfe, 0xb7, 0x18, 0x0c, + 0x73, 0x1f, 0xf9, 0x1d, 0x3b, 0x16, 0x9c, 0xeb, 0x76, 0x3f, 0xe2, 0xb1, 0xe0, 0x75, 0x18, 0xee, + 0x34, 0xeb, 0xb5, 0x4a, 0xad, 0xd3, 0xde, 0x69, 0x36, 0x98, 0x56, 0x66, 0x02, 0x03, 0x4c, 0xc5, + 0xfc, 0xca, 0x0a, 0xa9, 0x71, 0xef, 0x99, 0x32, 0xe0, 0x06, 0xe8, 0x2f, 0xbf, 0x63, 0xaa, 0xcb, + 0x23, 0x00, 0xd5, 0x6e, 0x97, 0xf5, 0x24, 0x3f, 0x84, 0x09, 0x8e, 0xd3, 0x6c, 0x57, 0x21, 0x40, + 0xda, 0xe9, 0x70, 0xc4, 0x1c, 0x91, 0xa0, 0x3e, 0x8f, 0x48, 0xd0, 0x5f, 0x49, 0x00, 0x58, 0x50, + 0xd1, 0xb3, 0x30, 0xaa, 0x2a, 0xf5, 0xa6, 0x8a, 0x9b, 0xdf, 0x57, 0x9b, 0xc6, 0xb2, 0x64, 0xc4, + 0x48, 0xbc, 0xaf, 0x36, 0x35, 0xf4, 0x80, 0x2c, 0x75, 0x89, 0xdd, 0x20, 0x5f, 0x9a, 0xd2, 0xb5, + 0x47, 0x88, 0x23, 0x2c, 0xb8, 0x23, 0xc3, 0xe2, 0x90, 0xa5, 0xf3, 0xa8, 0xca, 0xfd, 0xd2, 0xd0, + 0x06, 0x0c, 0xd3, 0xb5, 0x2c, 0x6d, 0x35, 0x4e, 0x5a, 0xbd, 0x1e, 0xa6, 0x55, 0xb2, 0xbe, 0x23, + 0x4d, 0x42, 0xc3, 0xf8, 0x57, 0x43, 0x6f, 0x43, 0xb2, 0x6a, 0x31, 0x90, 0x7e, 0x15, 0x9b, 0x20, + 0x62, 0xf9, 0x62, 0x98, 0x46, 0x39, 0xe6, 0x93, 0xa6, 0xc7, 0xab, 0x62, 0x02, 0x9e, 0x21, 0x6a, + 0xad, 0xa6, 0x42, 0x17, 0xdf, 0x6c, 0x86, 0xa0, 0x09, 0xc5, 0x3a, 0x66, 0x25, 0xcb, 0xd4, 0x94, + 0x9a, 0xaa, 0xe8, 0xcc, 0xdb, 0x1a, 0xa1, 0x89, 0x5b, 0x24, 0x0d, 0xfd, 0x38, 0x24, 0xab, 0xfb, + 0xfa, 0x6e, 0x85, 0xaa, 0x1c, 0x45, 0x38, 0x10, 0x32, 0x82, 0x89, 0x11, 0xee, 0xeb, 0x4c, 0x6b, + 0x09, 0xc0, 0xb1, 0xaa, 0xf0, 0x1b, 0xbd, 0x0a, 0x67, 0xba, 0x1d, 0xfa, 0x19, 0x4e, 0x67, 0x5f, + 0xaf, 0x88, 0x23, 0x3b, 0x48, 0x46, 0x76, 0x06, 0x17, 0x58, 0x23, 0xf9, 0x65, 0x6e, 0x8c, 0xe5, + 0xaf, 0x26, 0x60, 0xda, 0xc6, 0x03, 0xb6, 0xf5, 0x16, 0x20, 0x80, 0x01, 0xa1, 0x47, 0xa7, 0x84, + 0xc5, 0x43, 0x49, 0x58, 0xe2, 0x54, 0x24, 0xac, 0xef, 0x34, 0x24, 0xac, 0xff, 0x04, 0x25, 0xec, + 0x23, 0x2b, 0x1f, 0x5f, 0x4b, 0x40, 0xd2, 0xb2, 0x1b, 0xe1, 0x6c, 0xd3, 0x25, 0x18, 0xe3, 0x99, + 0x65, 0xda, 0xa9, 0x51, 0x2e, 0x95, 0x2a, 0xce, 0x27, 0x12, 0xf2, 0xc3, 0x2f, 0x21, 0x2f, 0xc2, + 0xc8, 0x0a, 0x6f, 0xea, 0x1c, 0xf6, 0x50, 0x72, 0xda, 0x43, 0xf9, 0x7f, 0xc4, 0x60, 0x9c, 0x23, + 0xd9, 0xf5, 0xdb, 0xc8, 0x4f, 0x3c, 0x8c, 0x13, 0xf3, 0x30, 0xf0, 0x02, 0x9d, 0x63, 0xf7, 0x47, + 0x6e, 0x81, 0x6e, 0x13, 0x05, 0x61, 0x81, 0xee, 0x82, 0xfb, 0x23, 0xb1, 0x40, 0x77, 0xe0, 0x72, + 0x59, 0xa0, 0xbb, 0x97, 0x89, 0xb8, 0x40, 0x77, 0x34, 0xf2, 0x94, 0x57, 0x02, 0xbf, 0x1f, 0x83, + 0x11, 0xb6, 0x1e, 0x21, 0xa6, 0x2f, 0xe2, 0x6d, 0x1f, 0xe8, 0x22, 0x8c, 0x35, 0x68, 0x58, 0xbe, + 0xc2, 0xb6, 0x44, 0x68, 0xf3, 0x23, 0x2c, 0xb5, 0x44, 0x76, 0x46, 0xe6, 0x60, 0x08, 0xaf, 0xad, + 0x2b, 0x8f, 0x94, 0x03, 0x3a, 0x04, 0x43, 0xe5, 0x41, 0x9c, 0xf0, 0x86, 0x72, 0xa0, 0xa1, 0x55, + 0xc3, 0x14, 0xf4, 0x11, 0xea, 0xc2, 0xae, 0x31, 0x09, 0x5c, 0x7f, 0x9b, 0xf0, 0x34, 0xbf, 0x32, + 0xf1, 0x53, 0x58, 0xf9, 0xb1, 0xb9, 0x6d, 0x40, 0x50, 0x87, 0x73, 0xc2, 0x9c, 0xac, 0x8d, 0x05, + 0xb1, 0x36, 0x2e, 0xb2, 0x56, 0xfe, 0xbc, 0xd8, 0x6f, 0x6f, 0xab, 0x0f, 0xdf, 0x1e, 0xee, 0x98, + 0x01, 0x72, 0xd2, 0x43, 0x31, 0x1f, 0xb1, 0x75, 0xf9, 0xfb, 0x71, 0x73, 0x2f, 0x81, 0xb4, 0xe0, + 0x3a, 0x5b, 0x9c, 0x88, 0x10, 0x5e, 0x81, 0x24, 0x5f, 0x8a, 0x8b, 0x17, 0x8d, 0x59, 0xe5, 0x48, + 0x5c, 0xe8, 0x79, 0x40, 0x7c, 0x49, 0xb6, 0x6b, 0x47, 0x8d, 0x7d, 0xd2, 0x2a, 0xcb, 0x36, 0xef, + 0x04, 0xfe, 0xf4, 0x7b, 0x09, 0xf7, 0xc0, 0x49, 0x0b, 0xf7, 0xd3, 0xfc, 0xf6, 0x06, 0xcf, 0x0b, + 0xc6, 0x00, 0xf0, 0x1f, 0xcc, 0xb3, 0x34, 0xc7, 0x97, 0x9b, 0xc3, 0xce, 0xbd, 0xf4, 0xb4, 0x40, + 0xd9, 0x29, 0xcf, 0x51, 0xf7, 0x6c, 0x73, 0xd4, 0x8d, 0x28, 0x6c, 0x17, 0x26, 0xa9, 0x5d, 0x33, + 0xf8, 0x2d, 0x00, 0x3f, 0xf9, 0x49, 0x4a, 0xce, 0xc2, 0x2c, 0xdf, 0x53, 0xf0, 0xfe, 0xe2, 0xbf, + 0x97, 0x44, 0xed, 0xfe, 0xb8, 0x6d, 0x32, 0xfe, 0x19, 0x09, 0xa6, 0x9d, 0xf4, 0xe5, 0xea, 0xf5, + 0x20, 0xbe, 0xf3, 0xbb, 0xe9, 0x31, 0x71, 0x37, 0x9d, 0x63, 0x4e, 0xdc, 0x9d, 0x39, 0x09, 0x9e, + 0xc5, 0x5f, 0xb2, 0x82, 0x7e, 0x1c, 0x04, 0xb6, 0x33, 0xf7, 0xd4, 0x50, 0xec, 0xb9, 0x81, 0x60, + 0xfb, 0x37, 0x27, 0x0f, 0x42, 0xfe, 0xd7, 0x31, 0x73, 0xf3, 0x81, 0xeb, 0xef, 0x93, 0xc0, 0x7d, + 0x04, 0x51, 0xb6, 0xcf, 0xff, 0xbf, 0x2e, 0xc1, 0x82, 0x93, 0xa5, 0xa7, 0x6d, 0x05, 0x37, 0x6c, + 0x56, 0xf0, 0x66, 0x14, 0x2b, 0xe8, 0x12, 0xc2, 0xff, 0xbe, 0x04, 0xe7, 0xbd, 0xa9, 0x08, 0x65, + 0x12, 0x7d, 0xe4, 0xd1, 0x22, 0x3f, 0xee, 0x4e, 0x7e, 0x82, 0x27, 0xff, 0x81, 0xfd, 0xfe, 0x8b, + 0x4f, 0x47, 0x27, 0xce, 0xd5, 0xb3, 0xff, 0x6d, 0x09, 0xce, 0xf9, 0x16, 0x45, 0x0f, 0x78, 0x07, + 0xff, 0x76, 0xaf, 0xdd, 0x3e, 0x65, 0x3f, 0xff, 0xbf, 0xc6, 0xe8, 0xd7, 0xdf, 0xee, 0x4e, 0xbe, + 0xe7, 0xa9, 0x0a, 0xeb, 0xa4, 0x53, 0x9c, 0x3f, 0xe9, 0x24, 0x8e, 0x72, 0xc2, 0x3e, 0xca, 0x82, + 0x47, 0xd4, 0x67, 0xf3, 0x88, 0xf2, 0x86, 0x47, 0x44, 0x03, 0x28, 0x8b, 0x61, 0xae, 0xd2, 0x08, + 0xe1, 0x0e, 0x0d, 0x1c, 0xcf, 0x1d, 0x1a, 0x3c, 0x31, 0x5f, 0x7f, 0x87, 0xde, 0xa6, 0xc2, 0x3b, + 0xfa, 0x9e, 0x66, 0x33, 0xc0, 0xaf, 0xf5, 0xf5, 0xbc, 0x1f, 0x70, 0xfd, 0x30, 0xc7, 0xde, 0xb3, + 0x9f, 0x48, 0x2e, 0xfd, 0x4d, 0xfa, 0xd9, 0xba, 0xe1, 0xcf, 0x87, 0x6d, 0x54, 0xfe, 0x71, 0xd3, + 0x1d, 0xe1, 0xab, 0x07, 0x18, 0x04, 0x4f, 0xc9, 0xa3, 0xad, 0xc7, 0xcd, 0xd6, 0xdf, 0x33, 0x27, + 0x25, 0x3b, 0xd5, 0x27, 0xd4, 0x83, 0xef, 0x22, 0x55, 0x6e, 0x89, 0xde, 0x19, 0x4f, 0xe1, 0x15, + 0x48, 0x1a, 0xfd, 0x9b, 0xb6, 0x8d, 0xa2, 0x18, 0xeb, 0xf2, 0x4b, 0xa3, 0x08, 0xc4, 0xfe, 0x8a, + 0xb5, 0xd1, 0x2b, 0x76, 0x17, 0x24, 0x50, 0x96, 0xbe, 0xc6, 0x78, 0x7d, 0x75, 0x83, 0x18, 0x77, + 0x85, 0xf8, 0x9c, 0x53, 0xb3, 0xd9, 0x6d, 0x80, 0x49, 0x29, 0xac, 0x8a, 0xcb, 0x5f, 0xf6, 0x82, + 0xcf, 0x46, 0xec, 0xe4, 0x39, 0xe6, 0x3f, 0x78, 0xff, 0x21, 0x01, 0xa3, 0x26, 0x06, 0xd7, 0x05, + 0xe6, 0x27, 0x06, 0x70, 0xb0, 0xf7, 0x5b, 0x13, 0x87, 0x7c, 0x6f, 0x66, 0x03, 0x5f, 0xcf, 0x6e, + 0xd8, 0xe9, 0xd9, 0xb9, 0x5c, 0x43, 0xc8, 0x9f, 0xac, 0x1d, 0xf5, 0x3b, 0x59, 0x3b, 0x66, 0x3f, + 0x59, 0x6b, 0x5f, 0xb8, 0x8e, 0xfb, 0x2f, 0x5c, 0x93, 0x81, 0x77, 0x88, 0x4d, 0xb8, 0xdd, 0x21, + 0xf6, 0x0b, 0x12, 0xcc, 0x5a, 0xc3, 0x74, 0xca, 0x6e, 0x5d, 0xc1, 0xe6, 0xd6, 0x5d, 0x0f, 0x2d, + 0x40, 0x82, 0x37, 0xf7, 0x57, 0x25, 0x98, 0x71, 0x60, 0xee, 0xe5, 0xdc, 0xf0, 0x86, 0xfd, 0xdc, + 0xf0, 0x4b, 0xe1, 0x25, 0xda, 0xe3, 0xc8, 0xf0, 0x94, 0x5b, 0x89, 0x88, 0x1f, 0x87, 0xd8, 0x9a, + 0x70, 0xf1, 0xb7, 0x36, 0x8e, 0xe3, 0x6f, 0x19, 0x8d, 0xa5, 0x9e, 0x09, 0xf0, 0xbc, 0x7e, 0xc5, + 0x72, 0x28, 0x3d, 0xd8, 0x7d, 0xa2, 0xb1, 0xee, 0xe8, 0x9f, 0xea, 0x04, 0x8e, 0x86, 0xec, 0x6a, + 0xcb, 0x45, 0x1a, 0xc2, 0x9b, 0xf4, 0x1f, 0x2c, 0x39, 0x5f, 0x8e, 0xc1, 0x4c, 0x6e, 0x5f, 0xdf, + 0x3d, 0xb6, 0xd4, 0xd7, 0x3c, 0xae, 0xfc, 0x0b, 0x94, 0x4b, 0x5b, 0xef, 0x11, 0xef, 0xfd, 0xdb, + 0xb0, 0xaf, 0x7b, 0x5e, 0x8a, 0xd8, 0x9f, 0x8b, 0xb2, 0xb9, 0x95, 0x88, 0xa8, 0x6c, 0xbe, 0x44, + 0x3d, 0x45, 0x65, 0xfb, 0x96, 0x04, 0xb3, 0x8e, 0xe1, 0xfd, 0xc8, 0x7c, 0xb8, 0x67, 0x22, 0x33, + 0x8d, 0xf0, 0x1e, 0x0c, 0x99, 0x89, 0x18, 0x08, 0xf1, 0x2e, 0xc4, 0x2f, 0xf5, 0xce, 0x82, 0x65, + 0x0b, 0x9c, 0x4b, 0x84, 0x19, 0x60, 0x9e, 0x4a, 0x98, 0x48, 0x52, 0xe6, 0xdb, 0xec, 0x0e, 0x30, + 0xe2, 0x49, 0xa0, 0x33, 0x30, 0x7d, 0x7f, 0xab, 0x50, 0xde, 0xda, 0xce, 0x6d, 0x17, 0x2a, 0xf7, + 0x37, 0xb6, 0x36, 0x0b, 0x2b, 0xc5, 0xbb, 0xc5, 0x42, 0x3e, 0xf9, 0x0c, 0x9a, 0x82, 0xa4, 0x95, + 0x95, 0x5b, 0xd9, 0x2e, 0xbe, 0x59, 0x48, 0x4a, 0x68, 0x06, 0x90, 0x95, 0x5a, 0xdc, 0x60, 0xe9, + 0x31, 0x34, 0x0d, 0x13, 0x56, 0x7a, 0xbe, 0xb0, 0x56, 0xd8, 0x2e, 0xe4, 0x93, 0x71, 0xb1, 0x91, + 0xb5, 0xd2, 0xca, 0x1b, 0x85, 0x7c, 0x32, 0x21, 0x16, 0xde, 0xba, 0xbf, 0xb5, 0x59, 0xd8, 0xc8, + 0x27, 0xfb, 0xc4, 0xe4, 0xe2, 0x46, 0x71, 0xbb, 0x98, 0x5b, 0x4b, 0xf6, 0x67, 0xfe, 0x7f, 0xe8, + 0xa7, 0x37, 0xc7, 0xe1, 0xce, 0x57, 0x0b, 0x1b, 0xf9, 0x42, 0xd9, 0x06, 0x75, 0x02, 0x46, 0x59, + 0xfa, 0xdd, 0xc2, 0x7a, 0x6e, 0x0d, 0xe3, 0x1c, 0x87, 0x61, 0x96, 0x44, 0x12, 0x62, 0x08, 0xc1, + 0x18, 0x4b, 0xc8, 0x17, 0xdf, 0x2c, 0x94, 0xb7, 0x0a, 0xc9, 0x78, 0xe6, 0xff, 0x4a, 0xd4, 0x29, + 0x34, 0x25, 0x16, 0x9d, 0x83, 0x33, 0x04, 0x42, 0x21, 0x57, 0x5e, 0xb9, 0xf7, 0x46, 0xe1, 0x2d, + 0x5b, 0x47, 0x73, 0x30, 0x6b, 0xcb, 0xde, 0x2a, 0x94, 0x2b, 0x1b, 0xb9, 0x75, 0xdc, 0xe5, 0x59, + 0x48, 0x89, 0x99, 0x77, 0x8b, 0xe5, 0xad, 0x6d, 0x9a, 0x1b, 0x73, 0x56, 0x5d, 0xcb, 0x19, 0x99, + 0x71, 0x67, 0xe6, 0x46, 0x71, 0xe5, 0x0d, 0x9a, 0x99, 0x40, 0xf3, 0x90, 0x16, 0x33, 0xf3, 0xc5, + 0xad, 0xcd, 0xb5, 0xdc, 0x5b, 0x34, 0xbf, 0x0f, 0xcd, 0xc2, 0xa4, 0x98, 0x5f, 0x58, 0xcf, 0x15, + 0xd7, 0x92, 0xfd, 0xce, 0x0c, 0xc2, 0xd9, 0xe4, 0x40, 0xe6, 0x77, 0x24, 0x18, 0xe1, 0x75, 0x0b, + 0x97, 0xa4, 0xa5, 0xd6, 0x0b, 0xdb, 0xf7, 0x4a, 0xf9, 0x4a, 0xe1, 0xb3, 0xf7, 0x73, 0x6b, 0x5b, + 0xc9, 0x67, 0x30, 0x4d, 0x42, 0xc6, 0xd6, 0x76, 0xae, 0xbc, 0xbd, 0x55, 0x79, 0x50, 0xdc, 0xbe, + 0x97, 0x94, 0xb0, 0xf4, 0x08, 0xb9, 0x2b, 0xa5, 0x8d, 0xed, 0x5c, 0x71, 0x63, 0x2b, 0x19, 0x43, + 0xcf, 0xc2, 0x79, 0x97, 0x16, 0x2b, 0xc5, 0xd5, 0x8d, 0x52, 0xb9, 0x50, 0x59, 0xc9, 0x61, 0xfe, + 0xa3, 0x2b, 0x70, 0xd1, 0xab, 0x75, 0xa1, 0x64, 0x02, 0x5d, 0x82, 0x0b, 0xae, 0x3d, 0x09, 0xc5, + 0xfa, 0x32, 0x79, 0x18, 0x60, 0xb7, 0x53, 0x61, 0x92, 0xd6, 0xef, 0xe6, 0xb6, 0xdf, 0xda, 0xb4, + 0xcb, 0xf5, 0x38, 0x0c, 0x1b, 0x19, 0x5b, 0xeb, 0x5b, 0x54, 0x54, 0x8c, 0x84, 0xd2, 0xf6, 0x66, + 0x32, 0x96, 0xd9, 0x81, 0x41, 0xe3, 0x96, 0x2a, 0x94, 0x82, 0x29, 0xfc, 0xbf, 0x8b, 0x7e, 0xcc, + 0x00, 0x32, 0x73, 0x36, 0x4a, 0xdb, 0x95, 0x72, 0x21, 0x97, 0x7f, 0x2b, 0x29, 0x61, 0x41, 0x33, + 0xd3, 0x69, 0x5a, 0x0c, 0xab, 0x01, 0x97, 0xb6, 0x5e, 0x7a, 0x13, 0x2b, 0x47, 0xe6, 0x1e, 0x24, + 0xed, 0x97, 0x41, 0xa1, 0x34, 0xcc, 0x6c, 0x94, 0xb6, 0x8b, 0x77, 0x8b, 0x2b, 0xb9, 0xed, 0x62, + 0x69, 0x83, 0xa0, 0xa2, 0xe3, 0xf9, 0x0c, 0xc6, 0xe2, 0xc8, 0x23, 0x24, 0x64, 0xf6, 0x61, 0x98, + 0xbb, 0x8d, 0x02, 0x8b, 0xd3, 0x66, 0x69, 0xad, 0xb8, 0xf2, 0x96, 0x07, 0x6e, 0x3e, 0xd3, 0xd4, + 0xec, 0x14, 0x4c, 0xf1, 0xe9, 0x9c, 0x6e, 0xcf, 0xc2, 0x24, 0x9f, 0x63, 0x6a, 0x77, 0x66, 0x13, + 0x06, 0x8d, 0x2b, 0x00, 0x70, 0xf5, 0x52, 0x79, 0xd5, 0xad, 0xc3, 0x49, 0x18, 0x37, 0x73, 0xcc, + 0xde, 0xa6, 0x61, 0xc2, 0x4c, 0xb4, 0xba, 0xca, 0xfc, 0xb2, 0x04, 0xc8, 0xf9, 0x49, 0x2f, 0x92, + 0x61, 0xbe, 0x54, 0x5e, 0x5d, 0x2f, 0xac, 0x2f, 0x7b, 0xeb, 0xe6, 0x05, 0x38, 0xe7, 0x52, 0x86, + 0xd3, 0x41, 0x09, 0x2d, 0xc0, 0x59, 0x97, 0x22, 0x96, 0x22, 0xc6, 0xb0, 0xbc, 0xbb, 0x94, 0xa0, + 0x03, 0x10, 0xc7, 0x9a, 0xe8, 0x06, 0x03, 0xdb, 0x80, 0x62, 0x3e, 0x99, 0xc8, 0x7c, 0xde, 0xdc, + 0x48, 0xa7, 0x3c, 0x39, 0x0b, 0xa9, 0xcd, 0x72, 0xe9, 0xff, 0x2b, 0xac, 0x6c, 0xbb, 0xf1, 0x05, + 0xb3, 0x95, 0xcf, 0x35, 0x79, 0x73, 0x06, 0xa6, 0x85, 0x0c, 0x8e, 0x3f, 0x9f, 0x33, 0x3f, 0xd7, + 0x61, 0x07, 0x17, 0x67, 0x59, 0x49, 0x17, 0x41, 0x9f, 0x86, 0x09, 0x3e, 0xb3, 0xf4, 0x60, 0xa3, + 0x90, 0x4f, 0x4a, 0x5c, 0xb7, 0x24, 0x79, 0xb5, 0x9c, 0xdb, 0xc0, 0xa3, 0x19, 0xcb, 0xbc, 0x0d, + 0xb3, 0x1e, 0x9f, 0xd7, 0x61, 0xc6, 0x19, 0x88, 0xbc, 0xb9, 0xef, 0x28, 0xc1, 0x12, 0x18, 0xf7, + 0x33, 0x7f, 0x56, 0x32, 0xbf, 0x7a, 0x16, 0x3e, 0x46, 0x40, 0x17, 0x61, 0x81, 0x15, 0x2d, 0x97, + 0xd6, 0x0a, 0x5e, 0x3d, 0x58, 0xcc, 0x14, 0x4b, 0xbd, 0x51, 0xc0, 0x5a, 0x77, 0x09, 0x2e, 0xb8, + 0xe6, 0x0a, 0xb6, 0x32, 0x96, 0xf9, 0x63, 0xeb, 0xab, 0x0a, 0xbb, 0x8c, 0x3d, 0x07, 0x32, 0x6b, + 0xc1, 0x5f, 0xce, 0xac, 0x9e, 0x7c, 0x65, 0xcd, 0x22, 0xca, 0x4f, 0xde, 0x2c, 0xc6, 0x7a, 0xc9, + 0x9c, 0x0c, 0xf3, 0x5e, 0xb0, 0x0c, 0xb9, 0xf3, 0xe9, 0xcb, 0x9a, 0x9f, 0xfa, 0xb0, 0xb6, 0x1a, + 0x47, 0xa8, 0xb0, 0xb6, 0xe6, 0x36, 0x37, 0x3d, 0xb4, 0xd5, 0xcc, 0xe1, 0xb5, 0xd5, 0x4c, 0xe4, + 0xa4, 0x71, 0x97, 0x9e, 0x1d, 0xe4, 0x8f, 0xe1, 0x61, 0xe1, 0x25, 0x69, 0x85, 0xad, 0xcd, 0xd2, + 0xc6, 0x56, 0x81, 0xc8, 0xd8, 0x4a, 0x29, 0x5f, 0x48, 0x3e, 0x83, 0x27, 0x57, 0x47, 0x56, 0x31, + 0x5f, 0xd9, 0x2e, 0xbd, 0x51, 0xd8, 0x48, 0x4a, 0xd8, 0xf4, 0x39, 0xb2, 0x69, 0x5e, 0x2c, 0xa3, + 0xc2, 0xa8, 0x70, 0x34, 0x0f, 0x93, 0x4c, 0x12, 0xb0, 0xf4, 0x92, 0x92, 0xb9, 0xfb, 0xdb, 0xf7, + 0x4a, 0xe5, 0xe2, 0xe7, 0x88, 0x69, 0x34, 0x7a, 0x64, 0x4d, 0x5a, 0xa5, 0x8a, 0xeb, 0x9b, 0x6b, + 0xc5, 0x95, 0xe2, 0x76, 0x52, 0x42, 0xe7, 0x61, 0x4e, 0xcc, 0x2b, 0x17, 0xee, 0x96, 0x0b, 0x5b, + 0xf7, 0xcc, 0x3e, 0x1f, 0xc3, 0xa4, 0xcb, 0xc9, 0x3d, 0xac, 0x73, 0x24, 0x79, 0x13, 0xb7, 0x64, + 0x19, 0xe2, 0x07, 0x85, 0xe5, 0xe4, 0x33, 0xc4, 0x50, 0xb9, 0x64, 0x92, 0x61, 0xc8, 0xad, 0x16, + 0x36, 0x70, 0xc7, 0xd8, 0x8a, 0xb8, 0x94, 0xd9, 0xc8, 0x31, 0xae, 0xb6, 0x00, 0x39, 0x4f, 0xf4, + 0x11, 0xcb, 0x84, 0x53, 0xef, 0x6f, 0xb3, 0x39, 0x90, 0x54, 0x5a, 0xce, 0x6d, 0x15, 0x57, 0xa8, + 0x63, 0xe2, 0x92, 0xbb, 0x59, 0xda, 0xc2, 0x1d, 0xba, 0x67, 0x6e, 0x94, 0x36, 0x70, 0x6f, 0x15, + 0x98, 0x72, 0x3b, 0x80, 0x84, 0x19, 0xcc, 0x21, 0xdc, 0x2a, 0x94, 0x73, 0x1e, 0x6a, 0x2f, 0x94, + 0x32, 0xe4, 0x2e, 0xb7, 0xb9, 0x69, 0xa8, 0xbd, 0x6e, 0x7e, 0xfe, 0x63, 0x45, 0xb0, 0x38, 0x73, + 0x41, 0xf8, 0xef, 0x26, 0x88, 0x96, 0xbe, 0x73, 0x45, 0x4c, 0x89, 0x9c, 0x87, 0xb4, 0x33, 0x97, + 0x13, 0xcd, 0xbf, 0x19, 0x13, 0xe3, 0x8f, 0x76, 0x6d, 0xbf, 0x06, 0x97, 0xf9, 0xfa, 0xfe, 0x2a, + 0x9f, 0x81, 0xe7, 0xfc, 0x0a, 0x0b, 0x7a, 0x7f, 0x15, 0x2e, 0xf9, 0x95, 0xe5, 0x95, 0xdf, 0xb2, + 0x24, 0xae, 0x45, 0x0d, 0x0b, 0x70, 0x19, 0x9e, 0xf5, 0x85, 0x6a, 0x9a, 0x81, 0x80, 0xae, 0x79, + 0x5b, 0xb0, 0x0b, 0x63, 0x62, 0x4c, 0xd1, 0xf0, 0x32, 0x3d, 0x87, 0x83, 0xad, 0x14, 0xdc, 0xc6, + 0x82, 0x79, 0xaf, 0xee, 0x03, 0xf1, 0x15, 0x76, 0x3f, 0xbb, 0xb8, 0x34, 0xc4, 0x8a, 0x62, 0xd5, + 0xf1, 0x9e, 0x53, 0x5c, 0xca, 0x18, 0xb3, 0x4a, 0x31, 0x4f, 0xc5, 0xc0, 0xad, 0x19, 0xc6, 0x92, + 0x98, 0xe1, 0xcf, 0xdb, 0xf2, 0x4b, 0xe5, 0x55, 0x9c, 0x1d, 0x27, 0xe0, 0x9c, 0xeb, 0x56, 0x0c, + 0x0e, 0x2b, 0x8b, 0x2f, 0xb8, 0x73, 0x70, 0xc6, 0xa5, 0x0c, 0x6b, 0x59, 0x22, 0x8a, 0xe1, 0xcc, + 0xe6, 0xb0, 0xc7, 0x30, 0x76, 0xb7, 0x5e, 0x18, 0xf6, 0xf8, 0xd2, 0x1f, 0xfd, 0x75, 0x09, 0x26, + 0xd6, 0xcd, 0x15, 0xe4, 0x96, 0xa2, 0x3e, 0x6e, 0xd6, 0x14, 0xf4, 0x06, 0x0c, 0xdc, 0x53, 0xaa, + 0x2d, 0x7d, 0xf7, 0x8b, 0x68, 0xc6, 0x11, 0xaa, 0x2d, 0xec, 0x75, 0xf5, 0x83, 0xb4, 0x47, 0xba, + 0x9c, 0x3c, 0xfc, 0x37, 0xff, 0xf9, 0x83, 0x18, 0xa0, 0xc1, 0xec, 0x2e, 0x6b, 0x61, 0x15, 0xfa, + 0xca, 0x4a, 0xb5, 0x7e, 0x10, 0xb9, 0xa9, 0x31, 0xd2, 0xd4, 0x20, 0xea, 0xcf, 0xaa, 0xa4, 0xfe, + 0x06, 0x0c, 0xbe, 0xc9, 0xde, 0x88, 0xf3, 0x6c, 0xcb, 0xeb, 0xd5, 0x31, 0x79, 0x82, 0x34, 0x36, + 0x8c, 0x86, 0xcc, 0x77, 0xe6, 0xd0, 0x9f, 0x86, 0xe1, 0x55, 0x85, 0x44, 0x9a, 0x96, 0x0f, 0x8a, + 0x79, 0xf4, 0x5c, 0x98, 0x90, 0x4f, 0x31, 0x9f, 0xbe, 0x18, 0xa6, 0x9c, 0x2c, 0x1f, 0x1e, 0xa5, + 0x86, 0x69, 0xf8, 0x7a, 0x11, 0xc3, 0x27, 0xdd, 0x8f, 0xa2, 0xe1, 0x2c, 0x4e, 0xd1, 0xb2, 0xef, + 0x36, 0xeb, 0xef, 0xa1, 0xaf, 0x4b, 0x30, 0x65, 0x22, 0x20, 0xd7, 0x68, 0xaf, 0xb6, 0x3a, 0x0f, + 0xab, 0x2d, 0x74, 0x2d, 0x4c, 0x17, 0xec, 0x0d, 0xb3, 0x74, 0xe8, 0x57, 0x02, 0xe4, 0x25, 0x37, + 0x4c, 0xe7, 0xd0, 0x5c, 0xb6, 0x41, 0xba, 0x65, 0xd0, 0x48, 0x2c, 0x3c, 0xfb, 0x2e, 0xf9, 0xf3, + 0x1e, 0xfa, 0x5b, 0x12, 0x0c, 0x53, 0xa9, 0xc5, 0xcd, 0x68, 0xe8, 0x85, 0xf0, 0xaf, 0x34, 0xb0, + 0x88, 0x57, 0x7a, 0x29, 0x4a, 0x15, 0x3a, 0xcd, 0xcb, 0x57, 0xdc, 0xa0, 0x4e, 0xca, 0x63, 0x0c, + 0x63, 0x45, 0x23, 0xc5, 0x5f, 0x93, 0x32, 0x18, 0xe0, 0x48, 0x51, 0xc3, 0x4d, 0xd0, 0xa7, 0xd2, + 0x42, 0x20, 0xb4, 0xbf, 0xed, 0x16, 0x02, 0xa1, 0xe3, 0xb9, 0x36, 0xf9, 0xb2, 0x1b, 0x42, 0x84, + 0x92, 0x06, 0xc2, 0xa6, 0x46, 0x9f, 0x72, 0x43, 0x3f, 0x29, 0x01, 0x58, 0x4f, 0xb7, 0x05, 0xc3, + 0x73, 0x3c, 0xf3, 0x16, 0x52, 0xe2, 0x2e, 0x1c, 0x1e, 0xa5, 0x46, 0x00, 0x08, 0xa0, 0x27, 0x6a, + 0x53, 0x57, 0xa8, 0xc4, 0xcb, 0xfd, 0x14, 0x11, 0xe6, 0xd5, 0xcf, 0x48, 0x30, 0x96, 0x57, 0xaa, + 0x35, 0xbd, 0xf9, 0xd8, 0x80, 0x73, 0xb2, 0x52, 0xbf, 0xe4, 0x8a, 0xe1, 0x6c, 0x7a, 0x96, 0x13, + 0xfb, 0x6c, 0xa5, 0x6e, 0x42, 0x30, 0x40, 0x95, 0x7f, 0xf0, 0xa0, 0x54, 0x01, 0xd4, 0x9f, 0x93, + 0x60, 0x70, 0xad, 0x53, 0x7b, 0x74, 0x0a, 0x70, 0x9e, 0x77, 0x85, 0x33, 0x93, 0x9e, 0x10, 0xe0, + 0xb4, 0x3a, 0xb5, 0x47, 0x18, 0xc8, 0x4f, 0x49, 0x00, 0xf7, 0xdb, 0xad, 0xd3, 0x81, 0xb2, 0xe8, + 0x0a, 0x25, 0x95, 0x9e, 0x14, 0xa0, 0xec, 0xb7, 0x0d, 0x30, 0x2a, 0x40, 0x5e, 0x69, 0x29, 0x11, + 0x47, 0xc9, 0xcb, 0xbe, 0x5f, 0x3c, 0x3c, 0x4a, 0x8d, 0xc2, 0x30, 0xe9, 0xbd, 0x4e, 0x9a, 0xa5, + 0x46, 0x32, 0x23, 0x18, 0xc9, 0xf7, 0x25, 0x7a, 0x50, 0xc0, 0x78, 0x70, 0xf3, 0x7a, 0xc8, 0xf7, + 0x35, 0x99, 0xee, 0x5c, 0x0e, 0x57, 0x5c, 0x93, 0x33, 0x6e, 0xfa, 0x3c, 0x8d, 0x04, 0x56, 0x18, + 0x4f, 0x76, 0xfe, 0x1c, 0x9e, 0xd3, 0xb9, 0xaf, 0xdd, 0x4e, 0x19, 0xda, 0x2b, 0x87, 0x47, 0x29, + 0x64, 0xee, 0x7c, 0x2c, 0x56, 0xbb, 0x5d, 0x0b, 0xe1, 0x59, 0x94, 0xce, 0x72, 0xdf, 0xf9, 0xd8, + 0x80, 0xfe, 0x05, 0x09, 0xa0, 0xa4, 0x36, 0x4e, 0x1b, 0x20, 0xb6, 0xd6, 0x40, 0x36, 0x4f, 0x2d, + 0x60, 0x53, 0x08, 0x65, 0x3b, 0x6a, 0xc3, 0x06, 0xe8, 0x2b, 0x92, 0x79, 0x92, 0xfb, 0xb4, 0x41, + 0xdd, 0x38, 0x3c, 0x4a, 0x8d, 0x99, 0xfb, 0xb2, 0x16, 0xb0, 0x14, 0x9a, 0xc9, 0x1a, 0x97, 0x91, + 0x89, 0xe0, 0xde, 0x97, 0x60, 0x8c, 0xcd, 0xc7, 0xc6, 0x03, 0x3a, 0x61, 0x65, 0x3c, 0xd4, 0x8c, + 0xcd, 0x1a, 0x0d, 0x25, 0x6a, 0x5d, 0x06, 0xe0, 0xe7, 0x25, 0x98, 0x70, 0xbc, 0x07, 0x83, 0x02, + 0xbf, 0x34, 0xf7, 0x7a, 0x42, 0x26, 0x1a, 0xd0, 0x50, 0xf6, 0x81, 0x21, 0xc5, 0xf6, 0xe1, 0xa7, + 0x25, 0x18, 0x61, 0x0c, 0xa4, 0x2f, 0xae, 0x84, 0x65, 0xdf, 0xd5, 0xd0, 0x0e, 0x8f, 0x87, 0x67, + 0x80, 0x04, 0xeb, 0x49, 0xb7, 0xf3, 0xbf, 0x21, 0xc1, 0x38, 0x15, 0x06, 0x0b, 0xd0, 0xcd, 0xf0, + 0x8c, 0xe3, 0x1f, 0x4d, 0x89, 0x02, 0x30, 0x94, 0x7d, 0x27, 0x08, 0x31, 0xcb, 0xbe, 0x26, 0xc1, + 0x5c, 0x59, 0xd1, 0x94, 0x76, 0x9d, 0x7b, 0x47, 0x85, 0xea, 0xf2, 0x7a, 0x14, 0x0e, 0x7a, 0x19, + 0xd9, 0xcf, 0xb8, 0xa2, 0xc9, 0xc8, 0x97, 0x1c, 0x68, 0xf0, 0x14, 0x88, 0x71, 0x3c, 0xe6, 0x20, + 0xd8, 0x06, 0x95, 0x3e, 0xea, 0x72, 0xa2, 0x83, 0x4a, 0x9a, 0x0c, 0x35, 0xa8, 0xf4, 0x69, 0x14, + 0x71, 0x50, 0x29, 0xa0, 0x08, 0x83, 0xca, 0xbf, 0xcb, 0x12, 0x05, 0x60, 0xa8, 0x41, 0x25, 0x08, + 0xc5, 0x41, 0xe5, 0xde, 0x6a, 0x61, 0x73, 0x45, 0xa7, 0xae, 0x3c, 0x9d, 0x41, 0x25, 0x68, 0xbc, + 0x06, 0x95, 0x33, 0x75, 0xc6, 0x93, 0x2c, 0x27, 0x6a, 0xea, 0x8c, 0x87, 0x45, 0xc2, 0x98, 0x3a, + 0xf6, 0x46, 0x89, 0xcd, 0xd4, 0x19, 0xb0, 0x22, 0x98, 0x3a, 0xf1, 0xb1, 0x96, 0x68, 0x40, 0x43, + 0x99, 0x3a, 0x86, 0x14, 0x33, 0xf0, 0xcf, 0x4b, 0xe6, 0xea, 0x71, 0x7d, 0xa7, 0x1a, 0x9e, 0x7b, + 0xcf, 0x47, 0x78, 0x4b, 0x45, 0x0b, 0x5a, 0x64, 0x10, 0x50, 0x7b, 0xb8, 0xfb, 0xbf, 0x2f, 0xc1, + 0xdc, 0x96, 0xd2, 0xae, 0x7b, 0xbc, 0x2b, 0x82, 0x5e, 0x0f, 0xde, 0x07, 0xf7, 0x7b, 0x90, 0xc4, + 0x53, 0x12, 0x6f, 0xb9, 0xb2, 0xed, 0x82, 0x7c, 0x56, 0xf0, 0x20, 0xb1, 0x04, 0x6a, 0x8a, 0xde, + 0x7d, 0xd2, 0xc6, 0x4d, 0x1f, 0x60, 0xfe, 0x7d, 0x20, 0x01, 0xda, 0x52, 0xf4, 0x62, 0xbb, 0xa9, + 0x37, 0xab, 0x2d, 0xa3, 0x6b, 0x14, 0x7c, 0x0f, 0x93, 0xf8, 0xb6, 0x8a, 0x27, 0xb0, 0x97, 0x5c, + 0x81, 0xcd, 0xcb, 0x67, 0x6c, 0xc0, 0xf4, 0x26, 0x45, 0xd0, 0x7d, 0x82, 0x51, 0xfd, 0x1d, 0x09, + 0xe6, 0x56, 0x2d, 0x4e, 0x38, 0x9e, 0x3d, 0xf1, 0x0a, 0x3b, 0xbc, 0x12, 0x16, 0xb6, 0xbd, 0x45, + 0xc2, 0xc0, 0x51, 0x18, 0xee, 0x92, 0x5f, 0xd6, 0x18, 0x2f, 0xa0, 0xf9, 0x2c, 0x49, 0x6b, 0x2a, + 0x5a, 0xd6, 0x78, 0x60, 0x46, 0xcb, 0xd6, 0xcc, 0xea, 0xe8, 0x77, 0x25, 0x98, 0xa7, 0x4b, 0x45, + 0x4f, 0xb4, 0xaf, 0xf7, 0x8a, 0x8a, 0xb6, 0x7b, 0x0c, 0xaa, 0x6e, 0x33, 0xdf, 0x8b, 0x52, 0x65, + 0xf1, 0xff, 0x59, 0x39, 0x80, 0x2c, 0x3c, 0x08, 0x98, 0x32, 0xaa, 0xd4, 0x27, 0x4f, 0x19, 0x6d, + 0xf7, 0x34, 0x28, 0x4b, 0x87, 0xa0, 0xec, 0xdb, 0x12, 0xcc, 0xd3, 0x05, 0x94, 0x27, 0x65, 0xaf, + 0xf5, 0x8a, 0xcc, 0x67, 0xba, 0x78, 0xf5, 0xf0, 0x28, 0x35, 0x0e, 0xa3, 0x0c, 0x33, 0xb7, 0xd4, + 0x5a, 0xc8, 0x04, 0x49, 0xd9, 0x07, 0x34, 0x44, 0xe5, 0x7c, 0xf2, 0xc3, 0x4b, 0x13, 0x5e, 0x08, + 0x8b, 0xdf, 0x6c, 0x8a, 0x38, 0xea, 0x2e, 0x2a, 0x70, 0x06, 0xcd, 0xba, 0x81, 0xab, 0x36, 0x14, + 0xf4, 0xcb, 0x12, 0xcc, 0x8a, 0xb2, 0x6f, 0x01, 0xbb, 0x15, 0x19, 0x00, 0x93, 0xf6, 0x1e, 0x90, + 0xbf, 0xe4, 0x21, 0x0c, 0x67, 0x65, 0x2f, 0xe8, 0x58, 0x0a, 0x30, 0x7a, 0x51, 0xbe, 0x8f, 0x83, + 0x9e, 0x49, 0xf4, 0x49, 0xa2, 0x4f, 0xfb, 0xa1, 0xff, 0x8a, 0x04, 0xb3, 0xa2, 0x0c, 0x5b, 0xe8, + 0x5f, 0x8c, 0x0c, 0xc2, 0x47, 0x6a, 0x97, 0xbc, 0xa4, 0xf6, 0x4c, 0xc6, 0x53, 0x30, 0xbe, 0x26, + 0x41, 0x8a, 0x13, 0x57, 0xf1, 0xb9, 0x0e, 0x2f, 0x91, 0x7d, 0x39, 0x2c, 0x6a, 0xa1, 0x39, 0xc2, + 0x3e, 0x17, 0xb1, 0x3d, 0x87, 0xe6, 0xdc, 0xd0, 0xb5, 0x68, 0x5d, 0xf4, 0x3d, 0x09, 0xe6, 0x44, + 0xd1, 0x15, 0x41, 0xde, 0xee, 0x09, 0x0c, 0x13, 0xe1, 0x1e, 0x29, 0x79, 0xc5, 0x43, 0x10, 0x16, + 0x64, 0x3f, 0x52, 0xb0, 0x30, 0x60, 0x6a, 0x44, 0x51, 0x3e, 0x09, 0x6a, 0x98, 0x48, 0x9f, 0x34, + 0x35, 0xe9, 0x20, 0x6a, 0x7e, 0x4e, 0x82, 0x39, 0x51, 0xb4, 0x45, 0x6a, 0x6e, 0xf5, 0x04, 0xc8, + 0x47, 0xc4, 0x6f, 0x7a, 0x89, 0xf8, 0xb9, 0x8c, 0xaf, 0x10, 0x7d, 0x11, 0x60, 0x55, 0xd1, 0x4b, + 0x6a, 0x83, 0x6c, 0x5c, 0x5c, 0x0a, 0x71, 0x81, 0x7d, 0x31, 0x9f, 0x7e, 0x36, 0x44, 0x31, 0x79, + 0xc1, 0x25, 0x92, 0x33, 0x82, 0xc0, 0x8a, 0xe4, 0x60, 0xfd, 0x9f, 0x32, 0x3a, 0xa7, 0xa7, 0xdf, + 0xd9, 0xa6, 0x45, 0x98, 0x07, 0x05, 0x68, 0x85, 0x70, 0x50, 0x96, 0x5c, 0xa0, 0xcc, 0xa3, 0xb3, + 0xc6, 0x66, 0x05, 0x41, 0x44, 0xcf, 0xe3, 0x67, 0xdf, 0xa5, 0x7f, 0xdf, 0x43, 0x5f, 0x96, 0x60, + 0xd4, 0x0a, 0x70, 0x97, 0xd4, 0xc6, 0x89, 0x32, 0xe7, 0x06, 0xf5, 0xc6, 0x31, 0x22, 0x4b, 0xac, + 0xe6, 0xd2, 0x33, 0x5c, 0x9c, 0xcb, 0x16, 0xdb, 0xc6, 0x78, 0xca, 0x3f, 0x50, 0x3c, 0xaa, 0x1d, + 0xcf, 0x04, 0x1d, 0x3c, 0xfe, 0xc3, 0x6f, 0x2f, 0xc3, 0xb8, 0x18, 0xfe, 0x89, 0x08, 0xf2, 0x05, + 0x31, 0xc6, 0x33, 0x01, 0xe3, 0x18, 0xcf, 0x1e, 0x49, 0x16, 0x97, 0x7c, 0x04, 0x15, 0xcd, 0xd0, + 0xb2, 0xf4, 0x5b, 0xda, 0x6f, 0x4a, 0x30, 0xc2, 0xbf, 0x04, 0x12, 0x3c, 0x83, 0xb8, 0xbc, 0x1b, + 0x92, 0x0e, 0xff, 0x94, 0x05, 0x71, 0xb7, 0x11, 0x24, 0x39, 0x88, 0x1c, 0xe7, 0x64, 0x83, 0x73, + 0xf4, 0x5b, 0x9c, 0xf7, 0x0c, 0xb0, 0x98, 0x73, 0xbf, 0x64, 0xc6, 0x1d, 0x2c, 0xb0, 0x37, 0xc3, + 0x85, 0x22, 0x8f, 0x83, 0x37, 0xe7, 0x83, 0xf7, 0x52, 0x7a, 0xc1, 0x1d, 0x6f, 0xf6, 0x5d, 0xf6, + 0x95, 0xd1, 0x7b, 0x18, 0xf9, 0x37, 0x24, 0x18, 0xb7, 0x3d, 0x58, 0x12, 0x8c, 0xdc, 0xfd, 0x85, + 0x13, 0x4f, 0x43, 0x76, 0xe7, 0xf0, 0x28, 0x35, 0x09, 0x13, 0x1c, 0x4c, 0xce, 0x98, 0xc9, 0x99, + 0x40, 0x9c, 0xe8, 0xd7, 0x25, 0x48, 0xd2, 0x2d, 0x40, 0xb3, 0x4f, 0x2d, 0x18, 0xa5, 0xfb, 0x63, + 0x24, 0xe9, 0x5b, 0x91, 0xeb, 0xb1, 0x3d, 0xbd, 0xd7, 0xbd, 0x05, 0x18, 0xaf, 0x5c, 0xdc, 0x89, + 0xe0, 0xf6, 0x22, 0x7f, 0x43, 0x82, 0x69, 0xda, 0xa4, 0x78, 0xca, 0x4d, 0x0b, 0x9e, 0x08, 0x7d, + 0x2e, 0xd8, 0x4f, 0x7f, 0xaa, 0xb7, 0xca, 0x8c, 0xa8, 0x97, 0x3d, 0xe2, 0xe0, 0xe7, 0xe4, 0x54, + 0x96, 0xdd, 0x32, 0x62, 0x86, 0xc3, 0x39, 0x5a, 0xfe, 0xa2, 0x64, 0x9e, 0x03, 0x24, 0xb3, 0xcc, + 0xd5, 0x90, 0x9f, 0x20, 0x17, 0xf3, 0xe9, 0xb0, 0x8f, 0x82, 0x90, 0xa8, 0x1a, 0x12, 0xa1, 0xa1, + 0x58, 0x91, 0xc2, 0x4b, 0xa2, 0x31, 0x31, 0x4c, 0x8f, 0xfe, 0x9a, 0x04, 0xa3, 0xcc, 0x75, 0x62, + 0xef, 0x4d, 0x84, 0xbd, 0x98, 0x58, 0x78, 0x39, 0x25, 0x3c, 0xbc, 0xcb, 0x6c, 0x7a, 0x66, 0xf0, + 0x2c, 0xcd, 0x1b, 0x93, 0x87, 0x4c, 0x6c, 0x98, 0x57, 0x3f, 0x2b, 0xc1, 0x28, 0x73, 0x83, 0x22, + 0x22, 0x13, 0xde, 0x66, 0x09, 0x8f, 0xec, 0x06, 0xd1, 0x37, 0x11, 0x99, 0xc9, 0xb9, 0xc9, 0xb4, + 0x8d, 0x73, 0x18, 0xe2, 0xdf, 0x96, 0x60, 0xc2, 0x9a, 0x19, 0x0d, 0x98, 0xa7, 0x31, 0xa8, 0x9f, + 0xf2, 0xc3, 0x76, 0x3e, 0x9d, 0xb6, 0x6d, 0xbe, 0xd8, 0x66, 0x4c, 0x8c, 0xb3, 0xfc, 0x91, 0xc4, + 0x29, 0xce, 0xa4, 0xbf, 0x2a, 0x41, 0x7a, 0x55, 0xd1, 0x45, 0xcd, 0x23, 0xbf, 0x88, 0xb6, 0x2c, + 0x46, 0xf9, 0x60, 0x3f, 0x4c, 0x58, 0x90, 0x2f, 0x2f, 0xaf, 0x78, 0xa8, 0xf4, 0x35, 0x74, 0xd5, + 0xa1, 0xd2, 0xef, 0x5a, 0x1f, 0x7d, 0xbd, 0x47, 0x33, 0x99, 0x3a, 0x7d, 0x55, 0x82, 0x69, 0xbc, + 0x56, 0x72, 0x3e, 0x34, 0xe1, 0xe5, 0x0f, 0x2c, 0x45, 0xba, 0x72, 0x98, 0xfa, 0x04, 0xd8, 0x1b, + 0x9f, 0x86, 0x49, 0x03, 0xaa, 0xdd, 0xac, 0x92, 0x45, 0xbe, 0x01, 0x55, 0xf4, 0x0d, 0xfe, 0x40, + 0x82, 0x29, 0x6a, 0xca, 0x84, 0x66, 0xb5, 0x10, 0x21, 0x12, 0xcf, 0x0b, 0xa0, 0xd3, 0xb7, 0x7b, + 0xaa, 0xcb, 0x2c, 0xe9, 0xfd, 0xc3, 0xa3, 0xd4, 0x82, 0x2b, 0x2d, 0x68, 0xc8, 0x10, 0x40, 0x36, + 0x10, 0xf2, 0x73, 0x59, 0xf7, 0x11, 0x70, 0x99, 0x35, 0x7e, 0x51, 0x82, 0x64, 0xae, 0x5e, 0x17, + 0x1f, 0xf1, 0xb8, 0x11, 0x09, 0x68, 0xae, 0x5e, 0x4f, 0x5f, 0x8f, 0x54, 0x83, 0x4c, 0xd9, 0x69, + 0x98, 0xb2, 0x11, 0x23, 0x6a, 0x01, 0xf6, 0x88, 0x44, 0x2d, 0xe0, 0x3c, 0xa2, 0x7f, 0x2a, 0xc1, + 0x24, 0x75, 0x70, 0x44, 0xe4, 0x2f, 0x46, 0xc2, 0x41, 0x5b, 0x88, 0x0a, 0xbe, 0x18, 0x02, 0x3c, + 0x76, 0x8f, 0x5c, 0xc1, 0x8b, 0xee, 0xd1, 0xdf, 0x95, 0x60, 0x92, 0x7a, 0x3b, 0xc7, 0x21, 0x83, + 0xb6, 0xe0, 0xe9, 0x1f, 0xad, 0x1e, 0x1e, 0xa5, 0xe6, 0x60, 0xda, 0x86, 0x97, 0xfa, 0x48, 0x26, + 0x60, 0xec, 0x27, 0x05, 0x00, 0x46, 0xff, 0x8e, 0x84, 0xcd, 0x39, 0xa5, 0xa0, 0x1a, 0xfb, 0x4a, + 0xe4, 0x1b, 0xfa, 0x0d, 0x85, 0x78, 0xb5, 0x87, 0x9a, 0x4c, 0x1d, 0x3e, 0x7b, 0x78, 0x94, 0x9a, + 0x87, 0x09, 0xd3, 0x0a, 0x75, 0x5a, 0x8a, 0xab, 0x32, 0x5c, 0x95, 0x2f, 0x7a, 0x28, 0x03, 0x51, + 0x74, 0x5e, 0x15, 0x7e, 0x5e, 0x82, 0x31, 0x4b, 0x15, 0xc8, 0x73, 0x21, 0x8b, 0x11, 0x00, 0x62, + 0x35, 0xb8, 0x16, 0xa1, 0x3c, 0x89, 0xe6, 0xa6, 0x00, 0x09, 0x24, 0x88, 0x52, 0x74, 0x46, 0x9e, + 0xb2, 0x0d, 0x0a, 0x01, 0x8d, 0xc1, 0xfe, 0x03, 0x09, 0x26, 0x04, 0x05, 0x20, 0x78, 0x5f, 0x88, + 0xd0, 0x3f, 0x13, 0xfe, 0x48, 0x90, 0x73, 0x81, 0x90, 0x9d, 0x73, 0x17, 0xe5, 0xf3, 0xbb, 0x8f, + 0x94, 0x83, 0xf7, 0xd8, 0xf6, 0xe4, 0x84, 0x20, 0xf2, 0x91, 0x81, 0x07, 0x88, 0x3b, 0xb6, 0x2d, + 0x67, 0x2c, 0x43, 0x49, 0x30, 0xda, 0x84, 0xfd, 0x6c, 0xc6, 0x07, 0x24, 0xfa, 0xbe, 0x29, 0xe6, + 0xdc, 0x31, 0x9b, 0x10, 0x62, 0xee, 0x75, 0xd1, 0x67, 0xb0, 0x98, 0x7b, 0x5e, 0x6d, 0x2a, 0x3f, + 0x38, 0x3c, 0x4a, 0x9d, 0x73, 0x9e, 0xbe, 0xb1, 0x4b, 0xf9, 0x0d, 0xf9, 0x9a, 0x87, 0x94, 0x0b, + 0xc7, 0x73, 0x38, 0x61, 0xff, 0x35, 0x49, 0xb8, 0xc0, 0x96, 0xf8, 0x0d, 0xd7, 0x23, 0xe0, 0x0c, + 0xb3, 0x17, 0xcb, 0x15, 0x27, 0xfa, 0x1a, 0x82, 0x90, 0x0c, 0xba, 0x12, 0x86, 0x10, 0xe2, 0x43, + 0xfc, 0x96, 0x04, 0xd3, 0xd4, 0xb9, 0xb6, 0x7d, 0xc6, 0x80, 0x5e, 0x8e, 0x78, 0x63, 0x31, 0x8b, + 0x60, 0x46, 0x22, 0x68, 0x5b, 0x34, 0x40, 0x98, 0x20, 0xaa, 0x09, 0x36, 0x8a, 0x9e, 0x97, 0x2f, + 0x7b, 0x50, 0xd4, 0x69, 0xd6, 0x6b, 0x3c, 0x55, 0x78, 0x58, 0x7e, 0xd3, 0xdc, 0x86, 0xe6, 0xe9, + 0x79, 0x21, 0x02, 0x30, 0x16, 0xbf, 0x8c, 0x44, 0xcb, 0xfd, 0x90, 0xb4, 0x5c, 0x4f, 0x87, 0x1e, + 0x1d, 0x4c, 0xcc, 0xef, 0x48, 0x30, 0x6d, 0xb9, 0xfd, 0x3c, 0x41, 0xa7, 0x29, 0x69, 0xd5, 0x90, + 0xc4, 0xbc, 0x9a, 0x7e, 0x29, 0x2c, 0x31, 0xf6, 0x75, 0x02, 0x26, 0xac, 0xfc, 0xf1, 0x20, 0x4c, + 0x5c, 0x58, 0x7c, 0xdb, 0x34, 0xce, 0xc7, 0x20, 0xca, 0xcb, 0x30, 0x6f, 0x1d, 0x1e, 0xa5, 0xce, + 0x5b, 0x93, 0x07, 0xc6, 0xcf, 0xec, 0xb2, 0xdd, 0x08, 0x64, 0xc2, 0x1b, 0x81, 0xff, 0x6e, 0x6e, + 0x02, 0x70, 0x20, 0xb8, 0x87, 0x22, 0x6e, 0x84, 0xbf, 0x9d, 0x9a, 0x69, 0x4e, 0x84, 0xfb, 0xac, + 0xe5, 0x56, 0xc8, 0x21, 0xc9, 0xa7, 0xef, 0x84, 0xa2, 0x48, 0xbc, 0x76, 0x9e, 0x9a, 0x08, 0x7a, + 0x05, 0x36, 0x1e, 0x9d, 0x3f, 0x94, 0x20, 0x5d, 0x56, 0x1a, 0x4a, 0x5b, 0x51, 0x99, 0xd1, 0x13, + 0x2e, 0x2e, 0x8f, 0x38, 0x4c, 0x81, 0xab, 0x3e, 0xbe, 0x71, 0x59, 0x0f, 0x49, 0xe9, 0x5a, 0x7a, + 0x35, 0xb4, 0xf0, 0x59, 0xd4, 0x65, 0x2b, 0xf4, 0x18, 0x24, 0xbd, 0x63, 0x9d, 0xde, 0xbb, 0x8e, + 0x29, 0xfe, 0x4f, 0x12, 0x4c, 0x0a, 0x1e, 0x27, 0x59, 0x82, 0x6a, 0xe8, 0xd5, 0x48, 0x77, 0xcc, + 0x0a, 0x93, 0xf1, 0x6b, 0xbd, 0x54, 0x65, 0xb3, 0xb1, 0x4d, 0x82, 0xc9, 0x82, 0xd6, 0x7d, 0x1a, + 0x93, 0x2f, 0x65, 0x7d, 0x17, 0xc1, 0xb6, 0x15, 0xd8, 0x53, 0x5e, 0xc2, 0x2f, 0x1f, 0x1e, 0xa5, + 0xa6, 0xdc, 0xe8, 0x20, 0xe0, 0x2f, 0x22, 0x39, 0x1b, 0xbc, 0x82, 0xff, 0xae, 0x04, 0x48, 0x08, + 0x88, 0xd1, 0x0b, 0x1e, 0x96, 0xa2, 0x00, 0x61, 0xf3, 0x6e, 0x34, 0xf0, 0x39, 0x71, 0x51, 0x4f, + 0xc1, 0x5b, 0xe1, 0x31, 0x59, 0x3e, 0xe7, 0x8b, 0x1e, 0xb3, 0xfc, 0x1f, 0x4b, 0x80, 0x84, 0x90, + 0x59, 0x0f, 0xd8, 0x99, 0xb5, 0x88, 0x86, 0xfd, 0xae, 0x3f, 0xf6, 0xcb, 0xe9, 0x10, 0x9c, 0x67, + 0x6e, 0xc2, 0x8c, 0x23, 0xa0, 0x46, 0x89, 0x38, 0x5d, 0xc9, 0x29, 0xfb, 0x13, 0xf0, 0x62, 0x7a, + 0x31, 0x98, 0x00, 0xfb, 0x6c, 0x8a, 0x89, 0x29, 0xff, 0xf0, 0x12, 0x23, 0xce, 0xa0, 0xdf, 0x90, + 0x00, 0x09, 0xcb, 0x9b, 0xde, 0x08, 0xf1, 0x9a, 0x43, 0xf3, 0x87, 0x47, 0xa9, 0x19, 0x2b, 0xf6, + 0x40, 0x21, 0x73, 0xdb, 0x1d, 0x17, 0x33, 0x61, 0x74, 0xf7, 0x17, 0x69, 0xfc, 0xd0, 0xeb, 0x2e, + 0x66, 0xaf, 0x10, 0xdc, 0xad, 0xe8, 0x17, 0x81, 0xd2, 0x38, 0x5c, 0x81, 0x44, 0x20, 0xce, 0x88, + 0xa8, 0xed, 0xd1, 0x38, 0x72, 0xea, 0xcc, 0x80, 0xce, 0xd0, 0x8a, 0x41, 0xb9, 0xc3, 0x18, 0x9c, + 0x71, 0xce, 0x06, 0x46, 0x64, 0xee, 0x4e, 0xaf, 0xd7, 0x94, 0x1a, 0x33, 0xc3, 0x67, 0x7a, 0x6f, + 0x80, 0xcd, 0x0f, 0x0f, 0xc3, 0xd0, 0xf9, 0x69, 0xf9, 0x95, 0x80, 0x21, 0x32, 0x6e, 0x97, 0x72, + 0x0d, 0xd8, 0xfd, 0x47, 0x09, 0xa6, 0xad, 0x28, 0x05, 0x7f, 0x2b, 0xf6, 0xcb, 0xd1, 0xf1, 0xe7, + 0xea, 0xf5, 0xf4, 0x52, 0xf4, 0x6a, 0xf2, 0x8f, 0x1d, 0x1e, 0xa5, 0xce, 0x42, 0xda, 0x95, 0x50, + 0x4b, 0x81, 0x5e, 0x96, 0x6f, 0x44, 0xa5, 0x94, 0xb9, 0x39, 0x29, 0x21, 0xb4, 0xc1, 0x13, 0xf9, + 0x4a, 0x74, 0xb4, 0x2c, 0xd0, 0xd1, 0x0b, 0x9d, 0x4a, 0x28, 0x3a, 0xef, 0xa4, 0x5f, 0x8b, 0x3c, + 0xa2, 0x42, 0x18, 0xf0, 0xb7, 0x24, 0x48, 0x39, 0x8d, 0x46, 0xef, 0x14, 0x07, 0x44, 0x48, 0x6a, + 0x64, 0x2d, 0x3e, 0xe7, 0x4a, 0x15, 0x67, 0x4b, 0x3e, 0x95, 0x39, 0x06, 0x59, 0xe8, 0x1f, 0x9a, + 0x9b, 0xaa, 0xe6, 0xd7, 0xd1, 0x21, 0x36, 0x55, 0xdd, 0xaf, 0x5e, 0x0b, 0xb6, 0x3c, 0x1e, 0x37, + 0x13, 0x92, 0xfd, 0xc7, 0x09, 0x18, 0x27, 0x27, 0x71, 0x6d, 0x6e, 0x4e, 0x5a, 0x9e, 0x66, 0xc7, + 0x71, 0x9d, 0x3e, 0xd9, 0x37, 0x24, 0xee, 0x36, 0x4d, 0xe2, 0x90, 0x5d, 0x0b, 0x8d, 0x20, 0xec, + 0xc7, 0x07, 0x74, 0x0e, 0x7a, 0xd5, 0x1b, 0xe0, 0x3c, 0x32, 0x0f, 0x32, 0x1b, 0x5c, 0x15, 0xac, + 0xf8, 0x37, 0x25, 0x18, 0xb7, 0xbe, 0xd7, 0xa4, 0xf3, 0x4c, 0x36, 0x74, 0xcf, 0xcc, 0xf7, 0x8a, + 0x00, 0x95, 0x7d, 0x09, 0xc6, 0x41, 0x15, 0x0f, 0x1d, 0xba, 0x63, 0xc5, 0xec, 0xfc, 0x7b, 0x12, + 0x8c, 0x5b, 0x27, 0xe5, 0xa3, 0x22, 0x65, 0x9e, 0x56, 0x04, 0xa4, 0x9f, 0xf6, 0x41, 0x7a, 0x21, + 0xed, 0xcb, 0x55, 0x0c, 0xf7, 0x3b, 0x12, 0x4c, 0x8a, 0x5f, 0xaa, 0x52, 0xc8, 0xa7, 0x25, 0x03, + 0x45, 0x1f, 0xb8, 0xd7, 0xd3, 0x57, 0xfc, 0xe0, 0xda, 0x7d, 0xa9, 0xef, 0x90, 0x0d, 0x85, 0x1f, + 0x12, 0xe8, 0xa2, 0xe7, 0xf4, 0x81, 0x79, 0x54, 0xa4, 0x47, 0xd8, 0x5e, 0xe6, 0xee, 0x36, 0x3d, + 0x1f, 0xc2, 0x61, 0xe4, 0x8c, 0xdc, 0x7c, 0xc6, 0x5f, 0xc9, 0xfe, 0xa7, 0x04, 0xb3, 0x82, 0xcf, + 0xc1, 0x59, 0xb3, 0xb0, 0xf7, 0xb1, 0x9f, 0xb4, 0x51, 0x7b, 0xfb, 0xf0, 0x28, 0x75, 0x11, 0x66, + 0x0d, 0xfb, 0x6d, 0xb3, 0x1d, 0xe1, 0x63, 0xc3, 0x5e, 0xd6, 0xef, 0xdf, 0x5a, 0x17, 0x19, 0x89, + 0x46, 0x70, 0x29, 0x2a, 0xc1, 0xd1, 0x84, 0xe9, 0x61, 0x24, 0xba, 0x5e, 0x42, 0x4b, 0xbe, 0x74, + 0xb9, 0x8f, 0xe7, 0xef, 0x4a, 0x30, 0x23, 0x2c, 0x5b, 0x9f, 0x8e, 0xed, 0xac, 0x1e, 0x1e, 0xa5, + 0x2e, 0x41, 0xca, 0x85, 0x34, 0xd7, 0x28, 0xca, 0x92, 0x7c, 0x3d, 0x12, 0x6d, 0x78, 0xd4, 0x7e, + 0x5f, 0x82, 0x19, 0x61, 0x51, 0x6b, 0x51, 0x76, 0x33, 0xea, 0xb8, 0x45, 0x37, 0xb9, 0x3b, 0xd1, + 0x08, 0xbc, 0x95, 0xee, 0x61, 0xf0, 0x8c, 0x18, 0x98, 0x63, 0xe5, 0x6b, 0x51, 0x7a, 0xca, 0x12, + 0xaa, 0x46, 0xa3, 0x72, 0x25, 0xfd, 0x7a, 0x74, 0x2a, 0xed, 0x26, 0x9d, 0x46, 0xfd, 0x3e, 0xde, + 0x14, 0x8b, 0x33, 0xc1, 0xfb, 0x31, 0x38, 0xeb, 0x5c, 0xe7, 0x71, 0x86, 0x77, 0x39, 0x52, 0xa0, + 0xe6, 0x84, 0xad, 0xaf, 0x7e, 0x78, 0x94, 0xca, 0xc2, 0x39, 0xd1, 0x7b, 0xb6, 0xdb, 0x2a, 0xf1, + 0xc5, 0x30, 0xca, 0x9b, 0xdb, 0xf2, 0x4d, 0x83, 0x37, 0x06, 0xf1, 0xf6, 0xfb, 0x84, 0xbd, 0x6d, + 0xf2, 0x1f, 0x4b, 0xe2, 0x2b, 0x4d, 0xa2, 0x61, 0xbe, 0xd5, 0x13, 0x43, 0xa2, 0x49, 0xc2, 0x3b, + 0xbd, 0xd2, 0x7d, 0x07, 0x7d, 0x3a, 0x2c, 0xdd, 0xee, 0x36, 0xfb, 0x4f, 0xac, 0xcf, 0x16, 0xdc, + 0xc8, 0x40, 0xb7, 0x7b, 0xa2, 0x3e, 0xba, 0x11, 0x7f, 0x72, 0x78, 0x94, 0xba, 0x01, 0xf3, 0x9e, + 0x1c, 0xa0, 0x1a, 0xe1, 0xc6, 0x02, 0x6e, 0xcd, 0x1f, 0x95, 0x05, 0x78, 0xf0, 0xbf, 0x14, 0x33, + 0xbf, 0x74, 0x38, 0x41, 0x06, 0x44, 0x37, 0xf2, 0x7f, 0xaa, 0x67, 0x06, 0x2c, 0xa7, 0x8f, 0x27, + 0x03, 0x98, 0x0b, 0x7f, 0x29, 0x06, 0xe7, 0xdd, 0x83, 0x9e, 0x16, 0x27, 0x9e, 0x86, 0x22, 0xfc, + 0xa4, 0xd4, 0x33, 0x1b, 0x36, 0xd2, 0xc5, 0x63, 0xb1, 0xc1, 0x3e, 0x37, 0x60, 0x96, 0x94, 0x7f, + 0xd4, 0x59, 0xe2, 0x08, 0xc0, 0x8e, 0xb3, 0xd3, 0x1b, 0xe6, 0xad, 0xd3, 0x37, 0x23, 0xde, 0xed, + 0x1d, 0x7a, 0x8e, 0xf0, 0xb8, 0x87, 0x5b, 0x9e, 0xa7, 0x1f, 0x70, 0xcb, 0x93, 0xd9, 0xea, 0xbe, + 0xbe, 0xeb, 0xb0, 0xe6, 0xcb, 0xbf, 0x21, 0xfd, 0x4c, 0xee, 0x2f, 0x4b, 0x68, 0x15, 0xc6, 0xac, + 0xfb, 0xcf, 0x16, 0x72, 0x9b, 0x45, 0xf9, 0x06, 0x5a, 0xdc, 0xd5, 0xf5, 0xae, 0xf6, 0x5a, 0x36, + 0xdb, 0x68, 0xea, 0xbb, 0xfb, 0x0f, 0x17, 0x6b, 0x9d, 0xbd, 0x2c, 0x46, 0x91, 0x65, 0x28, 0xb2, + 0xdd, 0x47, 0x8d, 0xac, 0x85, 0x64, 0x29, 0x7e, 0x63, 0xf1, 0x85, 0x8c, 0x14, 0x5b, 0xe2, 0x5f, + 0x6f, 0xce, 0xfe, 0x84, 0xd6, 0x69, 0x8b, 0x29, 0x0d, 0xb5, 0x5b, 0x7b, 0xcd, 0x51, 0xe6, 0x35, + 0x47, 0x99, 0xcf, 0x85, 0xec, 0x37, 0x5b, 0xed, 0x36, 0x49, 0x85, 0x87, 0xfd, 0x64, 0xb9, 0xf5, + 0xe2, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x98, 0x77, 0xb2, 0x45, 0x27, 0xbc, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/pkg/management/api/grpc/management.pb.gw.go b/pkg/management/api/grpc/management.pb.gw.go index 7e7fefb329..2da6a9ac00 100644 --- a/pkg/management/api/grpc/management.pb.gw.go +++ b/pkg/management/api/grpc/management.pb.gw.go @@ -1799,24 +1799,6 @@ func request_ManagementService_UpdatePasswordComplexityPolicy_0(ctx context.Cont return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - msg, err := client.UpdatePasswordComplexityPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err @@ -1834,49 +1816,24 @@ func local_request_ManagementService_UpdatePasswordComplexityPolicy_0(ctx contex return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - msg, err := server.UpdatePasswordComplexityPolicy(ctx, &protoReq) return msg, metadata, err } +var ( + filter_ManagementService_DeletePasswordComplexityPolicy_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + func request_ManagementService_DeletePasswordComplexityPolicy_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq PasswordComplexityPolicyID var metadata runtime.ServerMetadata - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - - protoReq.Id, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ManagementService_DeletePasswordComplexityPolicy_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } msg, err := client.DeletePasswordComplexityPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -1888,22 +1845,8 @@ func local_request_ManagementService_DeletePasswordComplexityPolicy_0(ctx contex var protoReq PasswordComplexityPolicyID var metadata runtime.ServerMetadata - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_ManagementService_DeletePasswordComplexityPolicy_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } msg, err := server.DeletePasswordComplexityPolicy(ctx, &protoReq) @@ -1975,24 +1918,6 @@ func request_ManagementService_UpdatePasswordAgePolicy_0(ctx context.Context, ma return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - msg, err := client.UpdatePasswordAgePolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err @@ -2010,49 +1935,24 @@ func local_request_ManagementService_UpdatePasswordAgePolicy_0(ctx context.Conte return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - msg, err := server.UpdatePasswordAgePolicy(ctx, &protoReq) return msg, metadata, err } +var ( + filter_ManagementService_DeletePasswordAgePolicy_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + func request_ManagementService_DeletePasswordAgePolicy_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq PasswordAgePolicyID var metadata runtime.ServerMetadata - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - - protoReq.Id, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ManagementService_DeletePasswordAgePolicy_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } msg, err := client.DeletePasswordAgePolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -2064,22 +1964,8 @@ func local_request_ManagementService_DeletePasswordAgePolicy_0(ctx context.Conte var protoReq PasswordAgePolicyID var metadata runtime.ServerMetadata - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_ManagementService_DeletePasswordAgePolicy_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } msg, err := server.DeletePasswordAgePolicy(ctx, &protoReq) @@ -2151,24 +2037,6 @@ func request_ManagementService_UpdatePasswordLockoutPolicy_0(ctx context.Context return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - msg, err := client.UpdatePasswordLockoutPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err @@ -2186,49 +2054,24 @@ func local_request_ManagementService_UpdatePasswordLockoutPolicy_0(ctx context.C return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - msg, err := server.UpdatePasswordLockoutPolicy(ctx, &protoReq) return msg, metadata, err } +var ( + filter_ManagementService_DeletePasswordLockoutPolicy_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + func request_ManagementService_DeletePasswordLockoutPolicy_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq PasswordLockoutPolicyID var metadata runtime.ServerMetadata - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - - protoReq.Id, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ManagementService_DeletePasswordLockoutPolicy_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } msg, err := client.DeletePasswordLockoutPolicy(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -2240,22 +2083,8 @@ func local_request_ManagementService_DeletePasswordLockoutPolicy_0(ctx context.C var protoReq PasswordLockoutPolicyID var metadata runtime.ServerMetadata - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_ManagementService_DeletePasswordLockoutPolicy_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } msg, err := server.DeletePasswordLockoutPolicy(ctx, &protoReq) @@ -11817,25 +11646,25 @@ var ( pattern_ManagementService_CreatePasswordComplexityPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"policies", "passwords", "complexity"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_ManagementService_UpdatePasswordComplexityPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"policies", "passwords", "complexity", "id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_ManagementService_UpdatePasswordComplexityPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"policies", "passwords", "complexity"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_ManagementService_DeletePasswordComplexityPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"policies", "passwords", "complexity", "id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_ManagementService_DeletePasswordComplexityPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"policies", "passwords", "complexity"}, "", runtime.AssumeColonVerbOpt(true))) pattern_ManagementService_GetPasswordAgePolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"policies", "passwords", "age"}, "", runtime.AssumeColonVerbOpt(true))) pattern_ManagementService_CreatePasswordAgePolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"policies", "passwords", "age"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_ManagementService_UpdatePasswordAgePolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"policies", "passwords", "age", "id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_ManagementService_UpdatePasswordAgePolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"policies", "passwords", "age"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_ManagementService_DeletePasswordAgePolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"policies", "passwords", "age", "id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_ManagementService_DeletePasswordAgePolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"policies", "passwords", "age"}, "", runtime.AssumeColonVerbOpt(true))) pattern_ManagementService_GetPasswordLockoutPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"policies", "passwords", "lockout"}, "", runtime.AssumeColonVerbOpt(true))) pattern_ManagementService_CreatePasswordLockoutPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"policies", "passwords", "lockout"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_ManagementService_UpdatePasswordLockoutPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"policies", "passwords", "lockout", "id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_ManagementService_UpdatePasswordLockoutPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"policies", "passwords", "lockout"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_ManagementService_DeletePasswordLockoutPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"policies", "passwords", "lockout", "id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_ManagementService_DeletePasswordLockoutPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"policies", "passwords", "lockout"}, "", runtime.AssumeColonVerbOpt(true))) pattern_ManagementService_GetOrgByID_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"orgs", "id"}, "", runtime.AssumeColonVerbOpt(true))) diff --git a/pkg/management/api/grpc/management.swagger.json b/pkg/management/api/grpc/management.swagger.json index 4412b37993..4908589f20 100644 --- a/pkg/management/api/grpc/management.swagger.json +++ b/pkg/management/api/grpc/management.swagger.json @@ -497,6 +497,28 @@ "ManagementService" ] }, + "delete": { + "operationId": "DeletePasswordAgePolicy", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "properties": {} + } + } + }, + "parameters": [ + { + "name": "id", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "ManagementService" + ] + }, "post": { "operationId": "CreatePasswordAgePolicy", "responses": { @@ -520,30 +542,6 @@ "tags": [ "ManagementService" ] - } - }, - "/policies/passwords/age/{id}": { - "delete": { - "operationId": "DeletePasswordAgePolicy", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "properties": {} - } - } - }, - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "ManagementService" - ] }, "put": { "operationId": "UpdatePasswordAgePolicy", @@ -556,12 +554,6 @@ } }, "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "type": "string" - }, { "name": "body", "in": "body", @@ -592,6 +584,28 @@ "ManagementService" ] }, + "delete": { + "operationId": "DeletePasswordComplexityPolicy", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "properties": {} + } + } + }, + "parameters": [ + { + "name": "id", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "ManagementService" + ] + }, "post": { "operationId": "CreatePasswordComplexityPolicy", "responses": { @@ -615,30 +629,6 @@ "tags": [ "ManagementService" ] - } - }, - "/policies/passwords/complexity/{id}": { - "delete": { - "operationId": "DeletePasswordComplexityPolicy", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "properties": {} - } - } - }, - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "ManagementService" - ] }, "put": { "operationId": "UpdatePasswordComplexityPolicy", @@ -651,12 +641,6 @@ } }, "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "type": "string" - }, { "name": "body", "in": "body", @@ -687,6 +671,28 @@ "ManagementService" ] }, + "delete": { + "operationId": "DeletePasswordLockoutPolicy", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "properties": {} + } + } + }, + "parameters": [ + { + "name": "id", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "ManagementService" + ] + }, "post": { "operationId": "CreatePasswordLockoutPolicy", "responses": { @@ -710,30 +716,6 @@ "tags": [ "ManagementService" ] - } - }, - "/policies/passwords/lockout/{id}": { - "delete": { - "operationId": "DeletePasswordLockoutPolicy", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "properties": {} - } - } - }, - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "ManagementService" - ] }, "put": { "operationId": "UpdatePasswordLockoutPolicy", @@ -746,12 +728,6 @@ } }, "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "type": "string" - }, { "name": "body", "in": "body", @@ -4261,6 +4237,10 @@ "sequence": { "type": "string", "format": "uint64" + }, + "is_default": { + "type": "boolean", + "format": "boolean" } } }, @@ -4342,6 +4322,10 @@ "sequence": { "type": "string", "format": "uint64" + }, + "is_default": { + "type": "boolean", + "format": "boolean" } } }, @@ -4435,6 +4419,10 @@ "sequence": { "type": "string", "format": "uint64" + }, + "is_default": { + "type": "boolean", + "format": "boolean" } } }, diff --git a/pkg/management/api/grpc/policy.go b/pkg/management/api/grpc/policy.go index 4a49550953..aa2932fdd6 100644 --- a/pkg/management/api/grpc/policy.go +++ b/pkg/management/api/grpc/policy.go @@ -2,54 +2,100 @@ package grpc import ( "context" + "github.com/caos/zitadel/internal/errors" "github.com/golang/protobuf/ptypes/empty" ) -func (s *Server) GetPasswordComplexityPolicy(ctx context.Context, _ *empty.Empty) (*PasswordComplexityPolicy, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-swe5v", "Not implemented") +func (s *Server) CreatePasswordComplexityPolicy(ctx context.Context, policy *PasswordComplexityPolicyCreate) (*PasswordComplexityPolicy, error) { + policyresp, err := s.policy.CreatePasswordComplexityPolicy(ctx, passwordComplexityPolicyCreateToModel(policy)) + if err != nil { + return nil, err + } + + return passwordComplexityPolicyFromModel(policyresp), nil } -func (s *Server) CreatePasswordComplexityPolicy(ctx context.Context, policy *PasswordComplexityPolicyCreate) (*PasswordComplexityPolicy, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-lo34s", "Not implemented") +func (s *Server) GetPasswordComplexityPolicy(ctx context.Context, _ *empty.Empty) (*PasswordComplexityPolicy, error) { + policy, err := s.policy.GetPasswordComplexityPolicy(ctx) + if err != nil { + return nil, err + } + + return passwordComplexityPolicyFromModel(policy), nil } func (s *Server) UpdatePasswordComplexityPolicy(ctx context.Context, policy *PasswordComplexityPolicyUpdate) (*PasswordComplexityPolicy, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-pl8fs", "Not implemented") + policyresp, err := s.policy.UpdatePasswordComplexityPolicy(ctx, passwordComplexityPolicyUpdateToModel(policy)) + if err != nil { + return nil, err + } + + return passwordComplexityPolicyFromModel(policyresp), nil } func (s *Server) DeletePasswordComplexityPolicy(ctx context.Context, ID *PasswordComplexityPolicyID) (*empty.Empty, error) { return nil, errors.ThrowUnimplemented(nil, "GRPC-skw3f", "Not implemented") } -func (s *Server) GetPasswordAgePolicy(ctx context.Context, _ *empty.Empty) (*PasswordAgePolicy, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-po9vb", "Not implemented") +func (s *Server) CreatePasswordAgePolicy(ctx context.Context, policy *PasswordAgePolicyCreate) (*PasswordAgePolicy, error) { + policyresp, err := s.policy.CreatePasswordAgePolicy(ctx, passwordAgePolicyCreateToModel(policy)) + if err != nil { + return nil, err + } + + return passwordAgePolicyFromModel(policyresp), nil } -func (s *Server) CreatePasswordAgePolicy(ctx context.Context, policy *PasswordAgePolicyCreate) (*PasswordAgePolicy, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-ldp3v", "Not implemented") +func (s *Server) GetPasswordAgePolicy(ctx context.Context, _ *empty.Empty) (*PasswordAgePolicy, error) { + policy, err := s.policy.GetPasswordAgePolicy(ctx) + if err != nil { + return nil, err + } + + return passwordAgePolicyFromModel(policy), nil } func (s *Server) UpdatePasswordAgePolicy(ctx context.Context, policy *PasswordAgePolicyUpdate) (*PasswordAgePolicy, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-ckep3", "Not implemented") + policyresp, err := s.policy.UpdatePasswordAgePolicy(ctx, passwordAgePolicyUpdateToModel(policy)) + if err != nil { + return nil, err + } + + return passwordAgePolicyFromModel(policyresp), nil } func (s *Server) DeletePasswordAgePolicy(ctx context.Context, ID *PasswordAgePolicyID) (*empty.Empty, error) { return nil, errors.ThrowUnimplemented(nil, "GRPC-plo67", "Not implemented") } -func (s *Server) GetPasswordLockoutPolicy(ctx context.Context, _ *empty.Empty) (*PasswordLockoutPolicy, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-GHkd9", "Not implemented") +func (s *Server) CreatePasswordLockoutPolicy(ctx context.Context, policy *PasswordLockoutPolicyCreate) (*PasswordLockoutPolicy, error) { + policyresp, err := s.policy.CreatePasswordLockoutPolicy(ctx, passwordLockoutPolicyCreateToModel(policy)) + if err != nil { + return nil, err + } + + return passwordLockoutPolicyFromModel(policyresp), nil } -func (s *Server) CreatePasswordLockoutPolicy(ctx context.Context, policy *PasswordLockoutPolicyCreate) (*PasswordLockoutPolicy, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-mdk3c", "Not implemented") +func (s *Server) GetPasswordLockoutPolicy(ctx context.Context, _ *empty.Empty) (*PasswordLockoutPolicy, error) { + policy, err := s.policy.GetPasswordLockoutPolicy(ctx) + if err != nil { + return nil, err + } + + return passwordLockoutPolicyFromModel(policy), nil } func (s *Server) UpdatePasswordLockoutPolicy(ctx context.Context, policy *PasswordLockoutPolicyUpdate) (*PasswordLockoutPolicy, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-8dbN4", "Not implemented") + policyresp, err := s.policy.UpdatePasswordLockoutPolicy(ctx, passwordLockoutPolicyUpdateToModel(policy)) + if err != nil { + return nil, err + } + + return passwordLockoutPolicyFromModel(policyresp), nil } func (s *Server) DeletePasswordLockoutPolicy(ctx context.Context, ID *PasswordLockoutPolicyID) (*empty.Empty, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-plV53", "Not implemented") + return nil, errors.ThrowUnimplemented(nil, "GRPC-GHkd9", "Not implemented") } diff --git a/pkg/management/api/grpc/policy_age_converter.go b/pkg/management/api/grpc/policy_age_converter.go new file mode 100644 index 0000000000..aa6dd9461d --- /dev/null +++ b/pkg/management/api/grpc/policy_age_converter.go @@ -0,0 +1,66 @@ +package grpc + +import ( + "github.com/caos/logging" + "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/policy/model" + "github.com/golang/protobuf/ptypes" +) + +func passwordAgePolicyFromModel(policy *model.PasswordAgePolicy) *PasswordAgePolicy { + creationDate, err := ptypes.TimestampProto(policy.CreationDate) + logging.Log("GRPC-6ILdB").OnError(err).Debug("unable to parse timestamp") + + changeDate, err := ptypes.TimestampProto(policy.ChangeDate) + logging.Log("GRPC-ngUzJ").OnError(err).Debug("unable to parse timestamp") + + return &PasswordAgePolicy{ + Id: policy.AggregateID, + CreationDate: creationDate, + ChangeDate: changeDate, + Sequence: policy.Sequence, + Description: policy.Description, + ExpireWarnDays: policy.ExpireWarnDays, + MaxAgeDays: policy.MaxAgeDays, + IsDefault: policy.AggregateID == "", + } +} + +func passwordAgePolicyToModel(policy *PasswordAgePolicy) *model.PasswordAgePolicy { + creationDate, err := ptypes.Timestamp(policy.CreationDate) + logging.Log("GRPC-2QSfU").OnError(err).Debug("unable to parse timestamp") + + changeDate, err := ptypes.Timestamp(policy.ChangeDate) + logging.Log("GRPC-LdU91").OnError(err).Debug("unable to parse timestamp") + + return &model.PasswordAgePolicy{ + ObjectRoot: models.ObjectRoot{ + AggregateID: policy.Id, + CreationDate: creationDate, + ChangeDate: changeDate, + Sequence: policy.Sequence, + }, + Description: policy.Description, + ExpireWarnDays: policy.ExpireWarnDays, + MaxAgeDays: policy.MaxAgeDays, + } +} + +func passwordAgePolicyCreateToModel(policy *PasswordAgePolicyCreate) *model.PasswordAgePolicy { + return &model.PasswordAgePolicy{ + Description: policy.Description, + ExpireWarnDays: policy.ExpireWarnDays, + MaxAgeDays: policy.MaxAgeDays, + } +} + +func passwordAgePolicyUpdateToModel(policy *PasswordAgePolicyUpdate) *model.PasswordAgePolicy { + return &model.PasswordAgePolicy{ + ObjectRoot: models.ObjectRoot{ + AggregateID: policy.Id, + }, + Description: policy.Description, + ExpireWarnDays: policy.ExpireWarnDays, + MaxAgeDays: policy.MaxAgeDays, + } +} diff --git a/pkg/management/api/grpc/policy_complexity_converter.go b/pkg/management/api/grpc/policy_complexity_converter.go new file mode 100644 index 0000000000..d65d372ca0 --- /dev/null +++ b/pkg/management/api/grpc/policy_complexity_converter.go @@ -0,0 +1,78 @@ +package grpc + +import ( + "github.com/caos/logging" + "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/policy/model" + "github.com/golang/protobuf/ptypes" +) + +func passwordComplexityPolicyFromModel(policy *model.PasswordComplexityPolicy) *PasswordComplexityPolicy { + creationDate, err := ptypes.TimestampProto(policy.CreationDate) + logging.Log("GRPC-cQRHE").OnError(err).Debug("unable to parse timestamp") + + changeDate, err := ptypes.TimestampProto(policy.ChangeDate) + logging.Log("GRPC-PVA1c").OnError(err).Debug("unable to parse timestamp") + + return &PasswordComplexityPolicy{ + Id: policy.AggregateID, + CreationDate: creationDate, + ChangeDate: changeDate, + Description: policy.Description, + Sequence: policy.Sequence, + MinLength: policy.MinLength, + HasLowercase: policy.HasLowercase, + HasUppercase: policy.HasUppercase, + HasNumber: policy.HasNumber, + HasSymbol: policy.HasSymbol, + IsDefault: policy.AggregateID == "", + } +} + +func passwordComplexityPolicyToModel(policy *PasswordComplexityPolicy) *model.PasswordComplexityPolicy { + creationDate, err := ptypes.Timestamp(policy.CreationDate) + logging.Log("GRPC-asmEZ").OnError(err).Debug("unable to parse timestamp") + + changeDate, err := ptypes.Timestamp(policy.ChangeDate) + logging.Log("GRPC-MCE4o").OnError(err).Debug("unable to parse timestamp") + + return &model.PasswordComplexityPolicy{ + ObjectRoot: models.ObjectRoot{ + AggregateID: policy.Id, + CreationDate: creationDate, + ChangeDate: changeDate, + Sequence: policy.Sequence, + }, + Description: policy.Description, + MinLength: policy.MinLength, + HasLowercase: policy.HasLowercase, + HasUppercase: policy.HasUppercase, + HasNumber: policy.HasNumber, + HasSymbol: policy.HasSymbol, + } +} + +func passwordComplexityPolicyCreateToModel(policy *PasswordComplexityPolicyCreate) *model.PasswordComplexityPolicy { + return &model.PasswordComplexityPolicy{ + Description: policy.Description, + MinLength: policy.MinLength, + HasLowercase: policy.HasLowercase, + HasUppercase: policy.HasUppercase, + HasNumber: policy.HasNumber, + HasSymbol: policy.HasSymbol, + } +} + +func passwordComplexityPolicyUpdateToModel(policy *PasswordComplexityPolicyUpdate) *model.PasswordComplexityPolicy { + return &model.PasswordComplexityPolicy{ + ObjectRoot: models.ObjectRoot{ + AggregateID: policy.Id, + }, + Description: policy.Description, + MinLength: policy.MinLength, + HasLowercase: policy.HasLowercase, + HasUppercase: policy.HasUppercase, + HasNumber: policy.HasNumber, + HasSymbol: policy.HasSymbol, + } +} diff --git a/pkg/management/api/grpc/policy_lockout_converter.go b/pkg/management/api/grpc/policy_lockout_converter.go new file mode 100644 index 0000000000..b05a652df5 --- /dev/null +++ b/pkg/management/api/grpc/policy_lockout_converter.go @@ -0,0 +1,67 @@ +package grpc + +import ( + "github.com/caos/logging" + "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/policy/model" + "github.com/golang/protobuf/ptypes" +) + +func passwordLockoutPolicyFromModel(policy *model.PasswordLockoutPolicy) *PasswordLockoutPolicy { + creationDate, err := ptypes.TimestampProto(policy.CreationDate) + logging.Log("GRPC-JRSbT").OnError(err).Debug("unable to parse timestamp") + + changeDate, err := ptypes.TimestampProto(policy.ChangeDate) + logging.Log("GRPC-1sizr").OnError(err).Debug("unable to parse timestamp") + + return &PasswordLockoutPolicy{ + Id: policy.AggregateID, + CreationDate: creationDate, + ChangeDate: changeDate, + Sequence: policy.Sequence, + Description: policy.Description, + MaxAttempts: policy.MaxAttempts, + ShowLockOutFailures: policy.ShowLockOutFailures, + IsDefault: policy.AggregateID == "", + } +} + +func passwordLockoutPolicyToModel(policy *PasswordLockoutPolicy) *model.PasswordLockoutPolicy { + creationDate, err := ptypes.Timestamp(policy.CreationDate) + logging.Log("GRPC-8a511").OnError(err).Debug("unable to parse timestamp") + + changeDate, err := ptypes.Timestamp(policy.ChangeDate) + logging.Log("GRPC-2rdGv").OnError(err).Debug("unable to parse timestamp") + + return &model.PasswordLockoutPolicy{ + ObjectRoot: models.ObjectRoot{ + AggregateID: policy.Id, + CreationDate: creationDate, + ChangeDate: changeDate, + Sequence: policy.Sequence, + }, + Description: policy.Description, + + MaxAttempts: policy.MaxAttempts, + ShowLockOutFailures: policy.ShowLockOutFailures, + } +} + +func passwordLockoutPolicyCreateToModel(policy *PasswordLockoutPolicyCreate) *model.PasswordLockoutPolicy { + return &model.PasswordLockoutPolicy{ + Description: policy.Description, + MaxAttempts: policy.MaxAttempts, + ShowLockOutFailures: policy.ShowLockOutFailures, + } +} + +func passwordLockoutPolicyUpdateToModel(policy *PasswordLockoutPolicyUpdate) *model.PasswordLockoutPolicy { + return &model.PasswordLockoutPolicy{ + ObjectRoot: models.ObjectRoot{ + AggregateID: policy.Id, + }, + Description: policy.Description, + MaxAttempts: policy.MaxAttempts, + ShowLockOutFailures: policy.ShowLockOutFailures, + } +} diff --git a/pkg/management/api/grpc/server.go b/pkg/management/api/grpc/server.go index 9163888a8c..7d0db9f5e8 100644 --- a/pkg/management/api/grpc/server.go +++ b/pkg/management/api/grpc/server.go @@ -15,6 +15,7 @@ var _ ManagementServiceServer = (*Server)(nil) type Server struct { port string project repository.ProjectRepository + policy repository.PolicyRepository org repository.OrgRepository orgMember repository.OrgMemberRepository user repository.UserRepository @@ -27,6 +28,7 @@ func StartServer(conf grpc_util.ServerConfig, authZ auth.Config, repo repository return &Server{ port: conf.Port, project: repo, + policy: repo, org: repo, orgMember: repo, user: repo, diff --git a/pkg/management/api/proto/management.proto b/pkg/management/api/proto/management.proto index 0dd531c192..43a80453f9 100644 --- a/pkg/management/api/proto/management.proto +++ b/pkg/management/api/proto/management.proto @@ -368,7 +368,7 @@ service ManagementService { rpc UpdatePasswordComplexityPolicy(PasswordComplexityPolicyUpdate) returns (PasswordComplexityPolicy) { option (google.api.http) = { - put: "/policies/passwords/complexity/{id}" + put: "/policies/passwords/complexity" body: "*" }; @@ -379,7 +379,7 @@ service ManagementService { rpc DeletePasswordComplexityPolicy(PasswordComplexityPolicyID) returns (google.protobuf.Empty) { option (google.api.http) = { - delete: "/policies/passwords/complexity/{id}" + delete: "/policies/passwords/complexity" }; option (caos.zitadel.utils.v1.auth_option) = { @@ -411,7 +411,7 @@ service ManagementService { rpc UpdatePasswordAgePolicy(PasswordAgePolicyUpdate) returns (PasswordAgePolicy) { option (google.api.http) = { - put: "/policies/passwords/age/{id}" + put: "/policies/passwords/age" body: "*" }; @@ -422,7 +422,7 @@ service ManagementService { rpc DeletePasswordAgePolicy(PasswordAgePolicyID) returns (google.protobuf.Empty) { option (google.api.http) = { - delete: "/policies/passwords/age/{id}" + delete: "/policies/passwords/age" }; option (caos.zitadel.utils.v1.auth_option) = { @@ -454,7 +454,7 @@ service ManagementService { rpc UpdatePasswordLockoutPolicy(PasswordLockoutPolicyUpdate) returns (PasswordLockoutPolicy) { option (google.api.http) = { - put: "/policies/passwords/lockout/{id}" + put: "/policies/passwords/lockout" body: "*" }; @@ -465,7 +465,7 @@ service ManagementService { rpc DeletePasswordLockoutPolicy(PasswordLockoutPolicyID) returns (google.protobuf.Empty) { option (google.api.http) = { - delete: "/policies/passwords/lockout/{id}" + delete: "/policies/passwords/lockout" }; option (caos.zitadel.utils.v1.auth_option) = { @@ -1532,6 +1532,7 @@ message PasswordComplexityPolicy { bool has_number = 9; bool has_symbol = 10; uint64 sequence = 11; + bool is_default = 12; } message PasswordComplexityPolicyCreate { @@ -1566,6 +1567,7 @@ message PasswordAgePolicy { uint64 max_age_days = 6; uint64 expire_warn_days = 7; uint64 sequence = 8; + bool is_default = 9; } message PasswordAgePolicyCreate { @@ -1594,6 +1596,8 @@ message PasswordLockoutPolicy { uint64 max_attempts = 6; bool show_lock_out_failures = 7; uint64 sequence = 8; + bool is_default = 9 + ; } message PasswordLockoutPolicyCreate { diff --git a/pkg/management/management.go b/pkg/management/management.go index 2c8dce65af..491b26adcd 100644 --- a/pkg/management/management.go +++ b/pkg/management/management.go @@ -2,6 +2,7 @@ package management import ( "context" + "github.com/caos/logging" "github.com/caos/zitadel/internal/api/auth" sd "github.com/caos/zitadel/internal/config/systemdefaults"