diff --git a/CHANGELOG-3.5.md b/CHANGELOG-3.5.md index ba523d094..7e90a3704 100644 --- a/CHANGELOG-3.5.md +++ b/CHANGELOG-3.5.md @@ -63,7 +63,6 @@ See [code changes](https://github.com/etcd-io/etcd/compare/v3.4.0...v3.5.0) and - Changed behavior on [existing dir permission](https://github.com/etcd-io/etcd/pull/11798). - Previously, the permission was not checked on existing data directory and the directory used for automatically generating self-signed certificates for TLS connections with clients. Now a check is added to make sure those directories, if already exist, has a desired permission of 700 on Linux and 777 on Windows. - ### `etcdctl` - Make sure [save snapshot downloads checksum for integrity checks](https://github.com/etcd-io/etcd/pull/11896). @@ -71,6 +70,7 @@ See [code changes](https://github.com/etcd-io/etcd/compare/v3.4.0...v3.5.0) and ### Security - Add [`TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256` and `TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256` to `etcd --cipher-suites`](https://github.com/etcd-io/etcd/pull/11864). +- Changed [the format of WAL entries related to auth for not keeping password as a plain text](https://github.com/etcd-io/etcd/pull/11943). ### Metrics, Monitoring diff --git a/Documentation/dev-guide/api_reference_v3.md b/Documentation/dev-guide/api_reference_v3.md index 0c19ae1a4..f2904a981 100644 --- a/Documentation/dev-guide/api_reference_v3.md +++ b/Documentation/dev-guide/api_reference_v3.md @@ -265,6 +265,7 @@ Empty field. | name | | string | | password | | string | | options | | authpb.UserAddOptions | +| hashedPassword | | string | @@ -281,7 +282,8 @@ Empty field. | Field | Description | Type | | ----- | ----------- | ---- | | name | name is the name of the user whose password is being changed. | string | -| password | password is the new password for the user. | string | +| password | password is the new password for the user. Note that this field will be removed in the API layer. | string | +| hashedPassword | hashedPassword is the new password for the user. Note that this field will be initialized in the API layer. | string | diff --git a/Documentation/dev-guide/apispec/swagger/rpc.swagger.json b/Documentation/dev-guide/apispec/swagger/rpc.swagger.json index 5a3b288a8..cdcb32c3d 100644 --- a/Documentation/dev-guide/apispec/swagger/rpc.swagger.json +++ b/Documentation/dev-guide/apispec/swagger/rpc.swagger.json @@ -17,7 +17,7 @@ "Auth" ], "summary": "Authenticate processes an authenticate request.", - "operationId": "Authenticate", + "operationId": "Auth_Authenticate", "parameters": [ { "name": "body", @@ -50,7 +50,7 @@ "Auth" ], "summary": "AuthDisable disables authentication.", - "operationId": "AuthDisable", + "operationId": "Auth_AuthDisable", "parameters": [ { "name": "body", @@ -83,7 +83,7 @@ "Auth" ], "summary": "AuthEnable enables authentication.", - "operationId": "AuthEnable", + "operationId": "Auth_AuthEnable", "parameters": [ { "name": "body", @@ -116,7 +116,7 @@ "Auth" ], "summary": "RoleAdd adds a new role. Role name cannot be empty.", - "operationId": "RoleAdd", + "operationId": "Auth_RoleAdd", "parameters": [ { "name": "body", @@ -149,7 +149,7 @@ "Auth" ], "summary": "RoleDelete deletes a specified role.", - "operationId": "RoleDelete", + "operationId": "Auth_RoleDelete", "parameters": [ { "name": "body", @@ -182,7 +182,7 @@ "Auth" ], "summary": "RoleGet gets detailed role information.", - "operationId": "RoleGet", + "operationId": "Auth_RoleGet", "parameters": [ { "name": "body", @@ -215,7 +215,7 @@ "Auth" ], "summary": "RoleGrantPermission grants a permission of a specified key or range to a specified role.", - "operationId": "RoleGrantPermission", + "operationId": "Auth_RoleGrantPermission", "parameters": [ { "name": "body", @@ -248,7 +248,7 @@ "Auth" ], "summary": "RoleList gets lists of all roles.", - "operationId": "RoleList", + "operationId": "Auth_RoleList", "parameters": [ { "name": "body", @@ -281,7 +281,7 @@ "Auth" ], "summary": "RoleRevokePermission revokes a key or range permission of a specified role.", - "operationId": "RoleRevokePermission", + "operationId": "Auth_RoleRevokePermission", "parameters": [ { "name": "body", @@ -314,7 +314,7 @@ "Auth" ], "summary": "AuthStatus displays authentication status.", - "operationId": "AuthStatus", + "operationId": "Auth_AuthStatus", "parameters": [ { "name": "body", @@ -347,7 +347,7 @@ "Auth" ], "summary": "UserAdd adds a new user. User name cannot be empty.", - "operationId": "UserAdd", + "operationId": "Auth_UserAdd", "parameters": [ { "name": "body", @@ -380,7 +380,7 @@ "Auth" ], "summary": "UserChangePassword changes the password of a specified user.", - "operationId": "UserChangePassword", + "operationId": "Auth_UserChangePassword", "parameters": [ { "name": "body", @@ -413,7 +413,7 @@ "Auth" ], "summary": "UserDelete deletes a specified user.", - "operationId": "UserDelete", + "operationId": "Auth_UserDelete", "parameters": [ { "name": "body", @@ -446,7 +446,7 @@ "Auth" ], "summary": "UserGet gets detailed user information.", - "operationId": "UserGet", + "operationId": "Auth_UserGet", "parameters": [ { "name": "body", @@ -479,7 +479,7 @@ "Auth" ], "summary": "UserGrant grants a role to a specified user.", - "operationId": "UserGrantRole", + "operationId": "Auth_UserGrantRole", "parameters": [ { "name": "body", @@ -512,7 +512,7 @@ "Auth" ], "summary": "UserList gets a list of all users.", - "operationId": "UserList", + "operationId": "Auth_UserList", "parameters": [ { "name": "body", @@ -545,7 +545,7 @@ "Auth" ], "summary": "UserRevokeRole revokes a role of specified user.", - "operationId": "UserRevokeRole", + "operationId": "Auth_UserRevokeRole", "parameters": [ { "name": "body", @@ -578,7 +578,7 @@ "Cluster" ], "summary": "MemberAdd adds a member into the cluster.", - "operationId": "MemberAdd", + "operationId": "Cluster_MemberAdd", "parameters": [ { "name": "body", @@ -611,7 +611,7 @@ "Cluster" ], "summary": "MemberList lists all the members in the cluster.", - "operationId": "MemberList", + "operationId": "Cluster_MemberList", "parameters": [ { "name": "body", @@ -644,7 +644,7 @@ "Cluster" ], "summary": "MemberPromote promotes a member from raft learner (non-voting) to raft voting member.", - "operationId": "MemberPromote", + "operationId": "Cluster_MemberPromote", "parameters": [ { "name": "body", @@ -677,7 +677,7 @@ "Cluster" ], "summary": "MemberRemove removes an existing member from the cluster.", - "operationId": "MemberRemove", + "operationId": "Cluster_MemberRemove", "parameters": [ { "name": "body", @@ -710,7 +710,7 @@ "Cluster" ], "summary": "MemberUpdate updates the member configuration.", - "operationId": "MemberUpdate", + "operationId": "Cluster_MemberUpdate", "parameters": [ { "name": "body", @@ -743,7 +743,7 @@ "KV" ], "summary": "Compact compacts the event history in the etcd key-value store. The key-value\nstore should be periodically compacted or the event history will continue to grow\nindefinitely.", - "operationId": "Compact", + "operationId": "KV_Compact", "parameters": [ { "name": "body", @@ -776,7 +776,7 @@ "KV" ], "summary": "DeleteRange deletes the given range from the key-value store.\nA delete request increments the revision of the key-value store\nand generates a delete event in the event history for every deleted key.", - "operationId": "DeleteRange", + "operationId": "KV_DeleteRange", "parameters": [ { "name": "body", @@ -809,7 +809,7 @@ "Lease" ], "summary": "LeaseLeases lists all existing leases.", - "operationId": "LeaseLeases2", + "operationId": "Lease_LeaseLeases2", "parameters": [ { "name": "body", @@ -842,7 +842,7 @@ "Lease" ], "summary": "LeaseRevoke revokes a lease. All keys attached to the lease will expire and be deleted.", - "operationId": "LeaseRevoke2", + "operationId": "Lease_LeaseRevoke2", "parameters": [ { "name": "body", @@ -875,7 +875,7 @@ "Lease" ], "summary": "LeaseTimeToLive retrieves lease information.", - "operationId": "LeaseTimeToLive2", + "operationId": "Lease_LeaseTimeToLive2", "parameters": [ { "name": "body", @@ -908,7 +908,7 @@ "KV" ], "summary": "Put puts the given key into the key-value store.\nA put request increments the revision of the key-value store\nand generates one event in the event history.", - "operationId": "Put", + "operationId": "KV_Put", "parameters": [ { "name": "body", @@ -941,7 +941,7 @@ "KV" ], "summary": "Range gets the keys in the range from the key-value store.", - "operationId": "Range", + "operationId": "KV_Range", "parameters": [ { "name": "body", @@ -974,7 +974,7 @@ "KV" ], "summary": "Txn processes multiple requests in a single transaction.\nA txn request increments the revision of the key-value store\nand generates events with the same revision for every completed request.\nIt is not allowed to modify the same key several times within one txn.", - "operationId": "Txn", + "operationId": "KV_Txn", "parameters": [ { "name": "body", @@ -1007,7 +1007,7 @@ "Lease" ], "summary": "LeaseGrant creates a lease which expires if the server does not receive a keepAlive\nwithin a given time to live period. All keys attached to the lease will be expired and\ndeleted if the lease expires. Each expired key generates a delete event in the event history.", - "operationId": "LeaseGrant", + "operationId": "Lease_LeaseGrant", "parameters": [ { "name": "body", @@ -1040,7 +1040,7 @@ "Lease" ], "summary": "LeaseKeepAlive keeps the lease alive by streaming keep alive requests from the client\nto the server and streaming keep alive responses from the server to the client.", - "operationId": "LeaseKeepAlive", + "operationId": "Lease_LeaseKeepAlive", "parameters": [ { "description": " (streaming inputs)", @@ -1083,7 +1083,7 @@ "Lease" ], "summary": "LeaseLeases lists all existing leases.", - "operationId": "LeaseLeases", + "operationId": "Lease_LeaseLeases", "parameters": [ { "name": "body", @@ -1116,7 +1116,7 @@ "Lease" ], "summary": "LeaseRevoke revokes a lease. All keys attached to the lease will expire and be deleted.", - "operationId": "LeaseRevoke", + "operationId": "Lease_LeaseRevoke", "parameters": [ { "name": "body", @@ -1149,7 +1149,7 @@ "Lease" ], "summary": "LeaseTimeToLive retrieves lease information.", - "operationId": "LeaseTimeToLive", + "operationId": "Lease_LeaseTimeToLive", "parameters": [ { "name": "body", @@ -1182,7 +1182,7 @@ "Maintenance" ], "summary": "Alarm activates, deactivates, and queries alarms regarding cluster health.", - "operationId": "Alarm", + "operationId": "Maintenance_Alarm", "parameters": [ { "name": "body", @@ -1215,7 +1215,7 @@ "Maintenance" ], "summary": "Defragment defragments a member's backend database to recover storage space.", - "operationId": "Defragment", + "operationId": "Maintenance_Defragment", "parameters": [ { "name": "body", @@ -1248,7 +1248,7 @@ "Maintenance" ], "summary": "Downgrade requests downgrade, cancel downgrade on the cluster version.", - "operationId": "Downgrade", + "operationId": "Maintenance_Downgrade", "parameters": [ { "name": "body", @@ -1281,7 +1281,7 @@ "Maintenance" ], "summary": "HashKV computes the hash of all MVCC keys up to a given revision.\nIt only iterates \"key\" bucket in backend storage.", - "operationId": "HashKV", + "operationId": "Maintenance_HashKV", "parameters": [ { "name": "body", @@ -1314,7 +1314,7 @@ "Maintenance" ], "summary": "Snapshot sends a snapshot of the entire backend from a member over a stream to a client.", - "operationId": "Snapshot", + "operationId": "Maintenance_Snapshot", "parameters": [ { "name": "body", @@ -1356,7 +1356,7 @@ "Maintenance" ], "summary": "Status gets the status of the member.", - "operationId": "Status", + "operationId": "Maintenance_Status", "parameters": [ { "name": "body", @@ -1389,7 +1389,7 @@ "Maintenance" ], "summary": "MoveLeader requests current leader node to transfer its leadership to transferee.", - "operationId": "MoveLeader", + "operationId": "Maintenance_MoveLeader", "parameters": [ { "name": "body", @@ -1422,7 +1422,7 @@ "Watch" ], "summary": "Watch watches for events happening or that have happened. Both input and output\nare streams; the input stream is for creating and canceling watchers and the output\nstream sends events. One watch RPC can watch on multiple key ranges, streaming events\nfor several watches at once. The entire event history can be watched starting from the\nlast compaction revision.", - "operationId": "Watch", + "operationId": "Watch_Watch", "parameters": [ { "description": " (streaming inputs)", @@ -1790,6 +1790,9 @@ "etcdserverpbAuthUserAddRequest": { "type": "object", "properties": { + "hashedPassword": { + "type": "string" + }, "name": { "type": "string" }, @@ -1812,12 +1815,16 @@ "etcdserverpbAuthUserChangePasswordRequest": { "type": "object", "properties": { + "hashedPassword": { + "description": "hashedPassword is the new password for the user. Note that this field will be initialized in the API layer.", + "type": "string" + }, "name": { "description": "name is the name of the user whose password is being changed.", "type": "string" }, "password": { - "description": "password is the new password for the user.", + "description": "password is the new password for the user. Note that this field will be removed in the API layer.", "type": "string" } } diff --git a/Documentation/dev-guide/apispec/swagger/v3election.swagger.json b/Documentation/dev-guide/apispec/swagger/v3election.swagger.json index ffdc5fdef..efd647ae6 100644 --- a/Documentation/dev-guide/apispec/swagger/v3election.swagger.json +++ b/Documentation/dev-guide/apispec/swagger/v3election.swagger.json @@ -14,7 +14,7 @@ "/v3/election/campaign": { "post": { "summary": "Campaign waits to acquire leadership in an election, returning a LeaderKey\nrepresenting the leadership if successful. The LeaderKey can then be used\nto issue new values on the election, transactionally guard API requests on\nleadership still being held, and resign from the election.", - "operationId": "Campaign", + "operationId": "Election_Campaign", "responses": { "200": { "description": "A successful response.", @@ -47,7 +47,7 @@ "/v3/election/leader": { "post": { "summary": "Leader returns the current election proclamation, if any.", - "operationId": "Leader", + "operationId": "Election_Leader", "responses": { "200": { "description": "A successful response.", @@ -80,7 +80,7 @@ "/v3/election/observe": { "post": { "summary": "Observe streams election proclamations in-order as made by the election's\nelected leaders.", - "operationId": "Observe", + "operationId": "Election_Observe", "responses": { "200": { "description": "A successful response.(streaming responses)", @@ -122,7 +122,7 @@ "/v3/election/proclaim": { "post": { "summary": "Proclaim updates the leader's posted value with a new value.", - "operationId": "Proclaim", + "operationId": "Election_Proclaim", "responses": { "200": { "description": "A successful response.", @@ -155,7 +155,7 @@ "/v3/election/resign": { "post": { "summary": "Resign releases election leadership so other campaigners may acquire\nleadership on the election.", - "operationId": "Resign", + "operationId": "Election_Resign", "responses": { "200": { "description": "A successful response.", diff --git a/Documentation/dev-guide/apispec/swagger/v3lock.swagger.json b/Documentation/dev-guide/apispec/swagger/v3lock.swagger.json index eb413fd31..b3692fd68 100644 --- a/Documentation/dev-guide/apispec/swagger/v3lock.swagger.json +++ b/Documentation/dev-guide/apispec/swagger/v3lock.swagger.json @@ -14,7 +14,7 @@ "/v3/lock/lock": { "post": { "summary": "Lock acquires a distributed shared lock on a given named lock.\nOn success, it will return a unique key that exists so long as the\nlock is held by the caller. This key can be used in conjunction with\ntransactions to safely ensure updates to etcd only occur while holding\nlock ownership. The lock is held until Unlock is called on the key or the\nlease associate with the owner expires.", - "operationId": "Lock", + "operationId": "Lock_Lock", "responses": { "200": { "description": "A successful response.", @@ -47,7 +47,7 @@ "/v3/lock/unlock": { "post": { "summary": "Unlock takes a key returned by Lock and releases the hold on lock. The\nnext Lock caller waiting for the lock will then be woken up and given\nownership of the lock.", - "operationId": "Unlock", + "operationId": "Lock_Unlock", "responses": { "200": { "description": "A successful response.", diff --git a/Documentation/upgrades/upgrade_3_5.md b/Documentation/upgrades/upgrade_3_5.md index feda939b6..bc176e444 100644 --- a/Documentation/upgrades/upgrade_3_5.md +++ b/Documentation/upgrades/upgrade_3_5.md @@ -14,6 +14,8 @@ Before [starting an upgrade](#upgrade-procedure), read through the rest of this **NOTE:** When [migrating from v2 with no v3 data](https://github.com/etcd-io/etcd/issues/9480), etcd server v3.2+ panics when etcd restores from existing snapshots but no v3 `ETCD_DATA_DIR/member/snap/db` file. This happens when the server had migrated from v2 with no previous v3 data. This also prevents accidental v3 data loss (e.g. `db` file might have been moved). etcd requires that post v3 migration can only happen with v3 data. Do not upgrade to newer v3 versions until v3.0 server contains v3 data. +**NOTE:** If your cluster enables auth, rolling upgrade from 3.4 or older version isn't supported because 3.5 [changes a format of WAL entries related to auth](https://github.com/etcd-io/etcd/pull/11943). + Highlighted breaking changes in 3.5. #### Deprecated `etcd_debugging_mvcc_db_total_size_in_bytes` Prometheus metrics diff --git a/auth/store.go b/auth/store.go index 7cf5dc7e1..c6d02495b 100644 --- a/auth/store.go +++ b/auth/store.go @@ -17,6 +17,7 @@ package auth import ( "bytes" "context" + "encoding/base64" "encoding/binary" "errors" "sort" @@ -186,6 +187,9 @@ type AuthStore interface { // HasRole checks that user has role HasRole(user, role string) bool + + // BcryptCost gets strength of hashing bcrypted auth password + BcryptCost() int } type TokenProvider interface { @@ -372,27 +376,19 @@ func (as *authStore) Recover(be backend.Backend) { as.enabledMu.Unlock() } +func (as *authStore) selectPassword(password string, hashedPassword string) ([]byte, error) { + if password != "" && hashedPassword == "" { + // This path is for processing log entries created by etcd whose version is older than 3.5 + return bcrypt.GenerateFromPassword([]byte(password), as.bcryptCost) + } + return base64.StdEncoding.DecodeString(hashedPassword) +} + func (as *authStore) UserAdd(r *pb.AuthUserAddRequest) (*pb.AuthUserAddResponse, error) { if len(r.Name) == 0 { return nil, ErrUserEmpty } - var hashed []byte - var err error - - noPassword := r.Options != nil && r.Options.NoPassword - if !noPassword { - hashed, err = bcrypt.GenerateFromPassword([]byte(r.Password), as.bcryptCost) - if err != nil { - as.lg.Error( - "failed to bcrypt hash password", - zap.String("user-name", r.Name), - zap.Error(err), - ) - return nil, err - } - } - tx := as.be.BatchTx() tx.Lock() defer tx.Unlock() @@ -409,9 +405,19 @@ func (as *authStore) UserAdd(r *pb.AuthUserAddRequest) (*pb.AuthUserAddResponse, } } + var password []byte + var err error + + if !options.NoPassword { + password, err = as.selectPassword(r.Password, r.HashedPassword) + if err != nil { + return nil, ErrNoPasswordUser + } + } + newUser := &authpb.User{ Name: []byte(r.Name), - Password: hashed, + Password: password, Options: options, } @@ -456,18 +462,6 @@ func (as *authStore) UserDelete(r *pb.AuthUserDeleteRequest) (*pb.AuthUserDelete } func (as *authStore) UserChangePassword(r *pb.AuthUserChangePasswordRequest) (*pb.AuthUserChangePasswordResponse, error) { - // TODO(mitake): measure the cost of bcrypt.GenerateFromPassword() - // If the cost is too high, we should move the encryption to outside of the raft - hashed, err := bcrypt.GenerateFromPassword([]byte(r.Password), as.bcryptCost) - if err != nil { - as.lg.Error( - "failed to bcrypt hash password", - zap.String("user-name", r.Name), - zap.Error(err), - ) - return nil, err - } - tx := as.be.BatchTx() tx.Lock() defer tx.Unlock() @@ -477,10 +471,20 @@ func (as *authStore) UserChangePassword(r *pb.AuthUserChangePasswordRequest) (*p return nil, ErrUserNotFound } + var password []byte + var err error + + if !user.Options.NoPassword { + password, err = as.selectPassword(r.Password, r.HashedPassword) + if err != nil { + return nil, ErrNoPasswordUser + } + } + updatedUser := &authpb.User{ Name: []byte(r.Name), Roles: user.Roles, - Password: hashed, + Password: password, Options: user.Options, } diff --git a/auth/store_test.go b/auth/store_test.go index 9f12ad632..c620cd4c1 100644 --- a/auth/store_test.go +++ b/auth/store_test.go @@ -16,6 +16,7 @@ package auth import ( "context" + "encoding/base64" "fmt" "os" "reflect" @@ -95,6 +96,11 @@ func TestNewAuthStoreBcryptCost(t *testing.T) { b.Close() } +func encodePassword(s string) string { + hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(s), bcrypt.MinCost) + return base64.StdEncoding.EncodeToString([]byte(hashedPassword)) +} + func setupAuthStore(t *testing.T) (store *authStore, teardownfunc func(t *testing.T)) { b, tPath := backend.NewDefaultTmpBackend() @@ -114,7 +120,7 @@ func setupAuthStore(t *testing.T) (store *authStore, teardownfunc func(t *testin t.Fatal(err) } - ua := &pb.AuthUserAddRequest{Name: "foo", Password: "bar", Options: &authpb.UserAddOptions{NoPassword: false}} + ua := &pb.AuthUserAddRequest{Name: "foo", HashedPassword: encodePassword("bar"), Options: &authpb.UserAddOptions{NoPassword: false}} _, err = as.UserAdd(ua) // add a non-existing user if err != nil { t.Fatal(err) @@ -129,7 +135,7 @@ func setupAuthStore(t *testing.T) (store *authStore, teardownfunc func(t *testin } func enableAuthAndCreateRoot(as *authStore) error { - _, err := as.UserAdd(&pb.AuthUserAddRequest{Name: "root", Password: "root", Options: &authpb.UserAddOptions{NoPassword: false}}) + _, err := as.UserAdd(&pb.AuthUserAddRequest{Name: "root", HashedPassword: encodePassword("root"), Options: &authpb.UserAddOptions{NoPassword: false}}) if err != nil { return err } @@ -239,7 +245,7 @@ func TestUserChangePassword(t *testing.T) { t.Fatal(err) } - _, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo", Password: "baz"}) + _, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo", HashedPassword: encodePassword("baz")}) if err != nil { t.Fatal(err) } @@ -251,7 +257,7 @@ func TestUserChangePassword(t *testing.T) { } // change a non-existing user - _, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo-test", Password: "bar"}) + _, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo-test", HashedPassword: encodePassword("bar")}) if err == nil { t.Fatalf("expected %v, got %v", ErrUserNotFound, err) } @@ -396,7 +402,7 @@ func TestListUsers(t *testing.T) { as, tearDown := setupAuthStore(t) defer tearDown(t) - ua := &pb.AuthUserAddRequest{Name: "user1", Password: "pwd1", Options: &authpb.UserAddOptions{NoPassword: false}} + ua := &pb.AuthUserAddRequest{Name: "user1", HashedPassword: encodePassword("pwd1"), Options: &authpb.UserAddOptions{NoPassword: false}} _, err := as.UserAdd(ua) // add a non-existing user if err != nil { t.Fatal(err) @@ -770,7 +776,7 @@ func TestHammerSimpleAuthenticate(t *testing.T) { // create lots of users for i := 0; i < 50; i++ { u := fmt.Sprintf("user-%d", i) - ua := &pb.AuthUserAddRequest{Name: u, Password: "123", Options: &authpb.UserAddOptions{NoPassword: false}} + ua := &pb.AuthUserAddRequest{Name: u, HashedPassword: encodePassword("123"), Options: &authpb.UserAddOptions{NoPassword: false}} if _, err := as.UserAdd(ua); err != nil { t.Fatal(err) } @@ -815,7 +821,7 @@ func TestRolesOrder(t *testing.T) { } username := "user" - _, err = as.UserAdd(&pb.AuthUserAddRequest{Name: username, Password: "pass", Options: &authpb.UserAddOptions{NoPassword: false}}) + _, err = as.UserAdd(&pb.AuthUserAddRequest{Name: username, HashedPassword: encodePassword("pass"), Options: &authpb.UserAddOptions{NoPassword: false}}) if err != nil { t.Fatal(err) } @@ -902,3 +908,45 @@ func TestUserNoPasswordAdd(t *testing.T) { t.Fatalf("expected %v, got %v", ErrAuthFailed, err) } } + +func TestUserAddWithOldLog(t *testing.T) { + as, tearDown := setupAuthStore(t) + defer tearDown(t) + + ua := &pb.AuthUserAddRequest{Name: "bar", Password: "baz", Options: &authpb.UserAddOptions{NoPassword: false}} + _, err := as.UserAdd(ua) + if err != nil { + t.Fatal(err) + } +} + +func TestUserChangePasswordWithOldLog(t *testing.T) { + as, tearDown := setupAuthStore(t) + defer tearDown(t) + + ctx1 := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(1)), AuthenticateParamSimpleTokenPrefix{}, "dummy") + _, err := as.Authenticate(ctx1, "foo", "bar") + if err != nil { + t.Fatal(err) + } + + _, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo", Password: "baz"}) + if err != nil { + t.Fatal(err) + } + + ctx2 := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(2)), AuthenticateParamSimpleTokenPrefix{}, "dummy") + _, err = as.Authenticate(ctx2, "foo", "baz") + if err != nil { + t.Fatal(err) + } + + // change a non-existing user + _, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo-test", HashedPassword: encodePassword("bar")}) + if err == nil { + t.Fatalf("expected %v, got %v", ErrUserNotFound, err) + } + if err != ErrUserNotFound { + t.Fatalf("expected %v, got %v", ErrUserNotFound, err) + } +} diff --git a/etcdserver/etcdserverpb/rpc.pb.go b/etcdserver/etcdserverpb/rpc.pb.go index a8a22ed75..a101ee715 100644 --- a/etcdserver/etcdserverpb/rpc.pb.go +++ b/etcdserver/etcdserverpb/rpc.pb.go @@ -2847,9 +2847,10 @@ func (m *AuthenticateRequest) GetPassword() string { } type AuthUserAddRequest struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` - Options *authpb.UserAddOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` + Options *authpb.UserAddOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` + HashedPassword string `protobuf:"bytes,4,opt,name=hashedPassword,proto3" json:"hashedPassword,omitempty"` } func (m *AuthUserAddRequest) Reset() { *m = AuthUserAddRequest{} } @@ -2878,6 +2879,13 @@ func (m *AuthUserAddRequest) GetOptions() *authpb.UserAddOptions { return nil } +func (m *AuthUserAddRequest) GetHashedPassword() string { + if m != nil { + return m.HashedPassword + } + return "" +} + type AuthUserGetRequest struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` } @@ -2914,8 +2922,10 @@ func (m *AuthUserDeleteRequest) GetName() string { type AuthUserChangePasswordRequest struct { // name is the name of the user whose password is being changed. Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // password is the new password for the user. + // password is the new password for the user. Note that this field will be removed in the API layer. Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` + // hashedPassword is the new password for the user. Note that this field will be initialized in the API layer. + HashedPassword string `protobuf:"bytes,3,opt,name=hashedPassword,proto3" json:"hashedPassword,omitempty"` } func (m *AuthUserChangePasswordRequest) Reset() { *m = AuthUserChangePasswordRequest{} } @@ -2939,6 +2949,13 @@ func (m *AuthUserChangePasswordRequest) GetPassword() string { return "" } +func (m *AuthUserChangePasswordRequest) GetHashedPassword() string { + if m != nil { + return m.HashedPassword + } + return "" +} + type AuthUserGrantRoleRequest struct { // user is the name of the user which should be granted a given role. User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` @@ -7927,6 +7944,12 @@ func (m *AuthUserAddRequest) MarshalTo(dAtA []byte) (int, error) { } i += n45 } + if len(m.HashedPassword) > 0 { + dAtA[i] = 0x22 + i++ + i = encodeVarintRpc(dAtA, i, uint64(len(m.HashedPassword))) + i += copy(dAtA[i:], m.HashedPassword) + } return i, nil } @@ -8005,6 +8028,12 @@ func (m *AuthUserChangePasswordRequest) MarshalTo(dAtA []byte) (int, error) { i = encodeVarintRpc(dAtA, i, uint64(len(m.Password))) i += copy(dAtA[i:], m.Password) } + if len(m.HashedPassword) > 0 { + dAtA[i] = 0x1a + i++ + i = encodeVarintRpc(dAtA, i, uint64(len(m.HashedPassword))) + i += copy(dAtA[i:], m.HashedPassword) + } return i, nil } @@ -9918,6 +9947,10 @@ func (m *AuthUserAddRequest) Size() (n int) { l = m.Options.Size() n += 1 + l + sovRpc(uint64(l)) } + l = len(m.HashedPassword) + if l > 0 { + n += 1 + l + sovRpc(uint64(l)) + } return n } @@ -9952,6 +9985,10 @@ func (m *AuthUserChangePasswordRequest) Size() (n int) { if l > 0 { n += 1 + l + sovRpc(uint64(l)) } + l = len(m.HashedPassword) + if l > 0 { + n += 1 + l + sovRpc(uint64(l)) + } return n } @@ -17831,6 +17868,35 @@ func (m *AuthUserAddRequest) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HashedPassword", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRpc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRpc + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HashedPassword = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipRpc(dAtA[iNdEx:]) @@ -18097,6 +18163,35 @@ func (m *AuthUserChangePasswordRequest) Unmarshal(dAtA []byte) error { } m.Password = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HashedPassword", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRpc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRpc + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HashedPassword = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipRpc(dAtA[iNdEx:]) @@ -20629,261 +20724,262 @@ var ( func init() { proto.RegisterFile("rpc.proto", fileDescriptorRpc) } var fileDescriptorRpc = []byte{ - // 4089 bytes of a gzipped FileDescriptorProto + // 4111 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x5b, 0x5b, 0x73, 0x1b, 0xc9, - 0x75, 0xe6, 0x00, 0xc4, 0xed, 0xe0, 0x42, 0xb0, 0x79, 0x11, 0x04, 0x49, 0x14, 0xb7, 0xb5, 0xda, - 0xe5, 0x4a, 0xbb, 0xc4, 0x9a, 0xb6, 0xb3, 0x55, 0x4a, 0xe2, 0x18, 0x22, 0xb1, 0x12, 0x97, 0x14, - 0xc1, 0x1d, 0x42, 0xda, 0x4b, 0xb9, 0xc2, 0x1a, 0x02, 0x2d, 0x72, 0x42, 0x60, 0x06, 0x9e, 0x19, - 0x40, 0xe4, 0xe6, 0xe2, 0x94, 0xcb, 0x71, 0x25, 0xaf, 0x76, 0x55, 0x2a, 0x79, 0xc8, 0x53, 0x2a, - 0xe5, 0xf2, 0x83, 0x9f, 0xf3, 0x17, 0xf2, 0x94, 0x4b, 0xe5, 0x0f, 0xa4, 0x36, 0x7e, 0x49, 0x7e, - 0x44, 0x2a, 0xd5, 0xb7, 0x99, 0x9e, 0x1b, 0x29, 0x2f, 0x76, 0xf7, 0x85, 0x9c, 0x3e, 0x7d, 0xfa, - 0x7c, 0xa7, 0x4f, 0x77, 0x9f, 0xd3, 0x7d, 0xba, 0x01, 0x25, 0x67, 0xdc, 0xdf, 0x1c, 0x3b, 0xb6, - 0x67, 0xa3, 0x0a, 0xf1, 0xfa, 0x03, 0x97, 0x38, 0x53, 0xe2, 0x8c, 0x4f, 0x9a, 0xcb, 0xa7, 0xf6, - 0xa9, 0xcd, 0x2a, 0x5a, 0xf4, 0x8b, 0xf3, 0x34, 0x6f, 0x52, 0x9e, 0xd6, 0x68, 0xda, 0xef, 0xb3, - 0x3f, 0xe3, 0x93, 0xd6, 0xf9, 0x54, 0x54, 0xdd, 0x62, 0x55, 0xc6, 0xc4, 0x3b, 0x63, 0x7f, 0xc6, - 0x27, 0xec, 0x9f, 0xa8, 0xbc, 0x7d, 0x6a, 0xdb, 0xa7, 0x43, 0xd2, 0x32, 0xc6, 0x66, 0xcb, 0xb0, - 0x2c, 0xdb, 0x33, 0x3c, 0xd3, 0xb6, 0x5c, 0x5e, 0x8b, 0xff, 0x4a, 0x83, 0x9a, 0x4e, 0xdc, 0xb1, - 0x6d, 0xb9, 0xe4, 0x29, 0x31, 0x06, 0xc4, 0x41, 0x77, 0x00, 0xfa, 0xc3, 0x89, 0xeb, 0x11, 0xe7, - 0xd8, 0x1c, 0x34, 0xb4, 0x75, 0x6d, 0x63, 0x5e, 0x2f, 0x09, 0xca, 0xee, 0x00, 0xdd, 0x82, 0xd2, - 0x88, 0x8c, 0x4e, 0x78, 0x6d, 0x86, 0xd5, 0x16, 0x39, 0x61, 0x77, 0x80, 0x9a, 0x50, 0x74, 0xc8, - 0xd4, 0x74, 0x4d, 0xdb, 0x6a, 0x64, 0xd7, 0xb5, 0x8d, 0xac, 0xee, 0x97, 0x69, 0x43, 0xc7, 0x78, - 0xe9, 0x1d, 0x7b, 0xc4, 0x19, 0x35, 0xe6, 0x79, 0x43, 0x4a, 0xe8, 0x11, 0x67, 0x84, 0x7f, 0x96, - 0x83, 0x8a, 0x6e, 0x58, 0xa7, 0x44, 0x27, 0x3f, 0x9e, 0x10, 0xd7, 0x43, 0x75, 0xc8, 0x9e, 0x93, - 0x4b, 0x06, 0x5f, 0xd1, 0xe9, 0x27, 0x6f, 0x6f, 0x9d, 0x92, 0x63, 0x62, 0x71, 0xe0, 0x0a, 0x6d, - 0x6f, 0x9d, 0x92, 0x8e, 0x35, 0x40, 0xcb, 0x90, 0x1b, 0x9a, 0x23, 0xd3, 0x13, 0xa8, 0xbc, 0x10, - 0x52, 0x67, 0x3e, 0xa2, 0xce, 0x36, 0x80, 0x6b, 0x3b, 0xde, 0xb1, 0xed, 0x0c, 0x88, 0xd3, 0xc8, - 0xad, 0x6b, 0x1b, 0xb5, 0xad, 0x37, 0x37, 0xd5, 0x81, 0xd8, 0x54, 0x15, 0xda, 0x3c, 0xb2, 0x1d, - 0xaf, 0x4b, 0x79, 0xf5, 0x92, 0x2b, 0x3f, 0xd1, 0x87, 0x50, 0x66, 0x42, 0x3c, 0xc3, 0x39, 0x25, - 0x5e, 0x23, 0xcf, 0xa4, 0xdc, 0xbf, 0x46, 0x4a, 0x8f, 0x31, 0xeb, 0x0c, 0x9e, 0x7f, 0x23, 0x0c, - 0x15, 0x97, 0x38, 0xa6, 0x31, 0x34, 0xbf, 0x30, 0x4e, 0x86, 0xa4, 0x51, 0x58, 0xd7, 0x36, 0x8a, - 0x7a, 0x88, 0x46, 0xfb, 0x7f, 0x4e, 0x2e, 0xdd, 0x63, 0xdb, 0x1a, 0x5e, 0x36, 0x8a, 0x8c, 0xa1, - 0x48, 0x09, 0x5d, 0x6b, 0x78, 0xc9, 0x06, 0xcd, 0x9e, 0x58, 0x1e, 0xaf, 0x2d, 0xb1, 0xda, 0x12, - 0xa3, 0xb0, 0xea, 0x0d, 0xa8, 0x8f, 0x4c, 0xeb, 0x78, 0x64, 0x0f, 0x8e, 0x7d, 0x83, 0x00, 0x33, - 0x48, 0x6d, 0x64, 0x5a, 0xcf, 0xec, 0x81, 0x2e, 0xcd, 0x42, 0x39, 0x8d, 0x8b, 0x30, 0x67, 0x59, - 0x70, 0x1a, 0x17, 0x2a, 0xe7, 0x26, 0x2c, 0x51, 0x99, 0x7d, 0x87, 0x18, 0x1e, 0x09, 0x98, 0x2b, - 0x8c, 0x79, 0x71, 0x64, 0x5a, 0xdb, 0xac, 0x26, 0xc4, 0x6f, 0x5c, 0xc4, 0xf8, 0xab, 0x82, 0xdf, - 0xb8, 0x08, 0xf3, 0xe3, 0x4d, 0x28, 0xf9, 0x36, 0x47, 0x45, 0x98, 0x3f, 0xe8, 0x1e, 0x74, 0xea, - 0x73, 0x08, 0x20, 0xdf, 0x3e, 0xda, 0xee, 0x1c, 0xec, 0xd4, 0x35, 0x54, 0x86, 0xc2, 0x4e, 0x87, - 0x17, 0x32, 0xf8, 0x31, 0x40, 0x60, 0x5d, 0x54, 0x80, 0xec, 0x5e, 0xe7, 0xb3, 0xfa, 0x1c, 0xe5, - 0x79, 0xd1, 0xd1, 0x8f, 0x76, 0xbb, 0x07, 0x75, 0x8d, 0x36, 0xde, 0xd6, 0x3b, 0xed, 0x5e, 0xa7, - 0x9e, 0xa1, 0x1c, 0xcf, 0xba, 0x3b, 0xf5, 0x2c, 0x2a, 0x41, 0xee, 0x45, 0x7b, 0xff, 0x79, 0xa7, - 0x3e, 0x8f, 0x7f, 0xa9, 0x41, 0x55, 0x8c, 0x17, 0x5f, 0x13, 0xe8, 0x7b, 0x90, 0x3f, 0x63, 0xeb, - 0x82, 0x4d, 0xc5, 0xf2, 0xd6, 0xed, 0xc8, 0xe0, 0x86, 0xd6, 0x8e, 0x2e, 0x78, 0x11, 0x86, 0xec, - 0xf9, 0xd4, 0x6d, 0x64, 0xd6, 0xb3, 0x1b, 0xe5, 0xad, 0xfa, 0x26, 0x5f, 0xb0, 0x9b, 0x7b, 0xe4, - 0xf2, 0x85, 0x31, 0x9c, 0x10, 0x9d, 0x56, 0x22, 0x04, 0xf3, 0x23, 0xdb, 0x21, 0x6c, 0xc6, 0x16, - 0x75, 0xf6, 0x4d, 0xa7, 0x31, 0x1b, 0x34, 0x31, 0x5b, 0x79, 0x01, 0xff, 0x5a, 0x03, 0x38, 0x9c, - 0x78, 0xe9, 0x4b, 0x63, 0x19, 0x72, 0x53, 0x2a, 0x58, 0x2c, 0x0b, 0x5e, 0x60, 0x6b, 0x82, 0x18, - 0x2e, 0xf1, 0xd7, 0x04, 0x2d, 0xa0, 0x1b, 0x50, 0x18, 0x3b, 0x64, 0x7a, 0x7c, 0x3e, 0x65, 0x20, - 0x45, 0x3d, 0x4f, 0x8b, 0x7b, 0x53, 0xf4, 0x06, 0x54, 0xcc, 0x53, 0xcb, 0x76, 0xc8, 0x31, 0x97, - 0x95, 0x63, 0xb5, 0x65, 0x4e, 0x63, 0x7a, 0x2b, 0x2c, 0x5c, 0x70, 0x5e, 0x65, 0xd9, 0xa7, 0x24, - 0x6c, 0x41, 0x99, 0xa9, 0x3a, 0x93, 0xf9, 0xde, 0x09, 0x74, 0xcc, 0xb0, 0x66, 0x71, 0x13, 0x0a, - 0xad, 0xf1, 0x8f, 0x00, 0xed, 0x90, 0x21, 0xf1, 0xc8, 0x2c, 0xde, 0x43, 0xb1, 0x49, 0x56, 0xb5, - 0x09, 0xfe, 0x85, 0x06, 0x4b, 0x21, 0xf1, 0x33, 0x75, 0xab, 0x01, 0x85, 0x01, 0x13, 0xc6, 0x35, - 0xc8, 0xea, 0xb2, 0x88, 0x1e, 0x42, 0x51, 0x28, 0xe0, 0x36, 0xb2, 0x29, 0x93, 0xa6, 0xc0, 0x75, - 0x72, 0xf1, 0xaf, 0x33, 0x50, 0x12, 0x1d, 0xed, 0x8e, 0x51, 0x1b, 0xaa, 0x0e, 0x2f, 0x1c, 0xb3, - 0xfe, 0x08, 0x8d, 0x9a, 0xe9, 0x4e, 0xe8, 0xe9, 0x9c, 0x5e, 0x11, 0x4d, 0x18, 0x19, 0xfd, 0x3e, - 0x94, 0xa5, 0x88, 0xf1, 0xc4, 0x13, 0x26, 0x6f, 0x84, 0x05, 0x04, 0xf3, 0xef, 0xe9, 0x9c, 0x0e, - 0x82, 0xfd, 0x70, 0xe2, 0xa1, 0x1e, 0x2c, 0xcb, 0xc6, 0xbc, 0x37, 0x42, 0x8d, 0x2c, 0x93, 0xb2, - 0x1e, 0x96, 0x12, 0x1f, 0xaa, 0xa7, 0x73, 0x3a, 0x12, 0xed, 0x95, 0x4a, 0x55, 0x25, 0xef, 0x82, - 0x3b, 0xef, 0x98, 0x4a, 0xbd, 0x0b, 0x2b, 0xae, 0x52, 0xef, 0xc2, 0x7a, 0x5c, 0x82, 0x82, 0x28, - 0xe1, 0x7f, 0xce, 0x00, 0xc8, 0xd1, 0xe8, 0x8e, 0xd1, 0x0e, 0xd4, 0x1c, 0x51, 0x0a, 0x59, 0xeb, - 0x56, 0xa2, 0xb5, 0xc4, 0x20, 0xce, 0xe9, 0x55, 0xd9, 0x88, 0x2b, 0xf7, 0x03, 0xa8, 0xf8, 0x52, - 0x02, 0x83, 0xdd, 0x4c, 0x30, 0x98, 0x2f, 0xa1, 0x2c, 0x1b, 0x50, 0x93, 0x7d, 0x02, 0x2b, 0x7e, - 0xfb, 0x04, 0x9b, 0xbd, 0x71, 0x85, 0xcd, 0x7c, 0x81, 0x4b, 0x52, 0x82, 0x6a, 0x35, 0x55, 0xb1, - 0xc0, 0x6c, 0x37, 0x13, 0xcc, 0x16, 0x57, 0x8c, 0x1a, 0x0e, 0x68, 0xbc, 0xe4, 0x45, 0xfc, 0x3f, - 0x59, 0x28, 0x6c, 0xdb, 0xa3, 0xb1, 0xe1, 0xd0, 0xd1, 0xc8, 0x3b, 0xc4, 0x9d, 0x0c, 0x3d, 0x66, - 0xae, 0xda, 0xd6, 0xbd, 0xb0, 0x44, 0xc1, 0x26, 0xff, 0xeb, 0x8c, 0x55, 0x17, 0x4d, 0x68, 0x63, - 0x11, 0x1e, 0x33, 0xaf, 0xd1, 0x58, 0x04, 0x47, 0xd1, 0x44, 0x2e, 0xe4, 0x6c, 0xb0, 0x90, 0x9b, - 0x50, 0x98, 0x12, 0x27, 0x08, 0xe9, 0x4f, 0xe7, 0x74, 0x49, 0x40, 0xef, 0xc0, 0x42, 0x34, 0xbc, - 0xe4, 0x04, 0x4f, 0xad, 0x1f, 0x8e, 0x46, 0xf7, 0xa0, 0x12, 0x8a, 0x71, 0x79, 0xc1, 0x57, 0x1e, - 0x29, 0x21, 0x6e, 0x55, 0xfa, 0x55, 0x1a, 0x8f, 0x2b, 0x4f, 0xe7, 0xa4, 0x67, 0x5d, 0x95, 0x9e, - 0xb5, 0x28, 0x5a, 0x09, 0xdf, 0x1a, 0x72, 0x32, 0x3f, 0x0c, 0x3b, 0x19, 0xfc, 0x43, 0xa8, 0x86, - 0x0c, 0x44, 0xe3, 0x4e, 0xe7, 0xe3, 0xe7, 0xed, 0x7d, 0x1e, 0xa4, 0x9e, 0xb0, 0xb8, 0xa4, 0xd7, - 0x35, 0x1a, 0xeb, 0xf6, 0x3b, 0x47, 0x47, 0xf5, 0x0c, 0xaa, 0x42, 0xe9, 0xa0, 0xdb, 0x3b, 0xe6, - 0x5c, 0x59, 0xfc, 0xc4, 0x97, 0x20, 0x82, 0x9c, 0x12, 0xdb, 0xe6, 0x94, 0xd8, 0xa6, 0xc9, 0xd8, - 0x96, 0x09, 0x62, 0x1b, 0x0b, 0x73, 0xfb, 0x9d, 0xf6, 0x51, 0xa7, 0x3e, 0xff, 0xb8, 0x06, 0x15, - 0x6e, 0xdf, 0xe3, 0x89, 0x45, 0x43, 0xed, 0x3f, 0x6a, 0x00, 0xc1, 0x6a, 0x42, 0x2d, 0x28, 0xf4, - 0x39, 0x4e, 0x43, 0x63, 0xce, 0x68, 0x25, 0x71, 0xc8, 0x74, 0xc9, 0x85, 0xbe, 0x03, 0x05, 0x77, - 0xd2, 0xef, 0x13, 0x57, 0x86, 0xbc, 0x1b, 0x51, 0x7f, 0x28, 0xbc, 0x95, 0x2e, 0xf9, 0x68, 0x93, - 0x97, 0x86, 0x39, 0x9c, 0xb0, 0x00, 0x78, 0x75, 0x13, 0xc1, 0x87, 0xff, 0x5e, 0x83, 0xb2, 0x32, - 0x79, 0xbf, 0xa2, 0x13, 0xbe, 0x0d, 0x25, 0xa6, 0x03, 0x19, 0x08, 0x37, 0x5c, 0xd4, 0x03, 0x02, - 0xfa, 0x3d, 0x28, 0xc9, 0x15, 0x20, 0x3d, 0x71, 0x23, 0x59, 0x6c, 0x77, 0xac, 0x07, 0xac, 0x78, - 0x0f, 0x16, 0x99, 0x55, 0xfa, 0x74, 0x73, 0x2d, 0xed, 0xa8, 0x6e, 0x3f, 0xb5, 0xc8, 0xf6, 0xb3, - 0x09, 0xc5, 0xf1, 0xd9, 0xa5, 0x6b, 0xf6, 0x8d, 0xa1, 0xd0, 0xc2, 0x2f, 0xe3, 0x8f, 0x00, 0xa9, - 0xc2, 0x66, 0xe9, 0x2e, 0xae, 0x42, 0xf9, 0xa9, 0xe1, 0x9e, 0x09, 0x95, 0xf0, 0x43, 0xa8, 0xd2, - 0xe2, 0xde, 0x8b, 0xd7, 0xd0, 0x91, 0x1d, 0x0e, 0x24, 0xf7, 0x4c, 0x36, 0x47, 0x30, 0x7f, 0x66, - 0xb8, 0x67, 0xac, 0xa3, 0x55, 0x9d, 0x7d, 0xa3, 0x77, 0xa0, 0xde, 0xe7, 0x9d, 0x3c, 0x8e, 0x1c, - 0x19, 0x16, 0x04, 0xdd, 0xdf, 0x09, 0x7e, 0x0a, 0x15, 0xde, 0x87, 0xaf, 0x5b, 0x09, 0xbc, 0x08, - 0x0b, 0x47, 0x96, 0x31, 0x76, 0xcf, 0x6c, 0x19, 0xdd, 0x68, 0xa7, 0xeb, 0x01, 0x6d, 0x26, 0xc4, - 0xb7, 0x61, 0xc1, 0x21, 0x23, 0xc3, 0xb4, 0x4c, 0xeb, 0xf4, 0xf8, 0xe4, 0xd2, 0x23, 0xae, 0x38, - 0x30, 0xd5, 0x7c, 0xf2, 0x63, 0x4a, 0xa5, 0xaa, 0x9d, 0x0c, 0xed, 0x13, 0xe1, 0xe6, 0xd8, 0x37, - 0xfe, 0x79, 0x06, 0x2a, 0x9f, 0x18, 0x5e, 0x5f, 0x0e, 0x1d, 0xda, 0x85, 0x9a, 0xef, 0xdc, 0x18, - 0x45, 0xe8, 0x12, 0x09, 0xb1, 0xac, 0x8d, 0xdc, 0x4a, 0xcb, 0xe8, 0x58, 0xed, 0xab, 0x04, 0x26, - 0xca, 0xb0, 0xfa, 0x64, 0xe8, 0x8b, 0xca, 0xa4, 0x8b, 0x62, 0x8c, 0xaa, 0x28, 0x95, 0x80, 0xba, - 0x50, 0x1f, 0x3b, 0xf6, 0xa9, 0x43, 0x5c, 0xd7, 0x17, 0xc6, 0xc3, 0x18, 0x4e, 0x10, 0x76, 0x28, - 0x58, 0x03, 0x71, 0x0b, 0xe3, 0x30, 0xe9, 0xf1, 0x42, 0xb0, 0x9f, 0xe1, 0xce, 0xe9, 0x3f, 0x32, - 0x80, 0xe2, 0x9d, 0xfa, 0x5d, 0xb7, 0x78, 0xf7, 0xa1, 0xe6, 0x7a, 0x86, 0x13, 0x9b, 0x6c, 0x55, - 0x46, 0xf5, 0x3d, 0xfe, 0xdb, 0xe0, 0x2b, 0x74, 0x6c, 0xd9, 0x9e, 0xf9, 0xf2, 0x52, 0xec, 0x92, - 0x6b, 0x92, 0x7c, 0xc0, 0xa8, 0xa8, 0x03, 0x85, 0x97, 0xe6, 0xd0, 0x23, 0x8e, 0xdb, 0xc8, 0xad, - 0x67, 0x37, 0x6a, 0x5b, 0x0f, 0xaf, 0x1b, 0x86, 0xcd, 0x0f, 0x19, 0x7f, 0xef, 0x72, 0x4c, 0x74, - 0xd9, 0x56, 0xdd, 0x79, 0xe6, 0x43, 0xbb, 0xf1, 0x9b, 0x50, 0x7c, 0x45, 0x45, 0xd0, 0x53, 0x76, - 0x81, 0x6f, 0x16, 0x59, 0x99, 0x1f, 0xb2, 0x5f, 0x3a, 0xc6, 0xe9, 0x88, 0x58, 0x9e, 0x3c, 0x07, - 0xca, 0x32, 0xbe, 0x0f, 0x10, 0xc0, 0x50, 0x97, 0x7f, 0xd0, 0x3d, 0x7c, 0xde, 0xab, 0xcf, 0xa1, - 0x0a, 0x14, 0x0f, 0xba, 0x3b, 0x9d, 0xfd, 0x0e, 0x8d, 0x0f, 0xb8, 0x25, 0x4d, 0x1a, 0x1a, 0x4b, - 0x15, 0x53, 0x0b, 0x61, 0xe2, 0x55, 0x58, 0x4e, 0x1a, 0x40, 0xba, 0x17, 0xad, 0x8a, 0x59, 0x3a, - 0xd3, 0x52, 0x51, 0xa1, 0x33, 0xe1, 0xee, 0x36, 0xa0, 0xc0, 0x67, 0xef, 0x40, 0x6c, 0xce, 0x65, - 0x91, 0x1a, 0x82, 0x4f, 0x46, 0x32, 0x10, 0xa3, 0xe4, 0x97, 0x13, 0xdd, 0x4b, 0x2e, 0xd1, 0xbd, - 0xa0, 0x7b, 0x50, 0xf5, 0x57, 0x83, 0xe1, 0x8a, 0xbd, 0x40, 0x49, 0xaf, 0xc8, 0x89, 0x4e, 0x69, - 0x21, 0xa3, 0x17, 0xc2, 0x46, 0x47, 0xf7, 0x21, 0x4f, 0xa6, 0xc4, 0xf2, 0xdc, 0x46, 0x99, 0x45, - 0x8c, 0xaa, 0xdc, 0xbb, 0x77, 0x28, 0x55, 0x17, 0x95, 0xf8, 0xfb, 0xb0, 0xc8, 0xce, 0x48, 0x4f, - 0x1c, 0xc3, 0x52, 0x0f, 0x73, 0xbd, 0xde, 0xbe, 0x30, 0x37, 0xfd, 0x44, 0x35, 0xc8, 0xec, 0xee, - 0x08, 0x23, 0x64, 0x76, 0x77, 0xf0, 0x4f, 0x35, 0x40, 0x6a, 0xbb, 0x99, 0xec, 0x1c, 0x11, 0x2e, - 0xe1, 0xb3, 0x01, 0xfc, 0x32, 0xe4, 0x88, 0xe3, 0xd8, 0x0e, 0xb3, 0x68, 0x49, 0xe7, 0x05, 0xfc, - 0xa6, 0xd0, 0x41, 0x27, 0x53, 0xfb, 0xdc, 0x5f, 0x83, 0x5c, 0x9a, 0xe6, 0xab, 0xba, 0x07, 0x4b, - 0x21, 0xae, 0x99, 0x22, 0xd7, 0x87, 0xb0, 0xc0, 0x84, 0x6d, 0x9f, 0x91, 0xfe, 0xf9, 0xd8, 0x36, - 0xad, 0x18, 0x1e, 0x1d, 0xb9, 0xc0, 0xc1, 0xd2, 0x7e, 0xf0, 0x8e, 0x55, 0x7c, 0x62, 0xaf, 0xb7, - 0x8f, 0x3f, 0x83, 0xd5, 0x88, 0x1c, 0xa9, 0xfe, 0x1f, 0x41, 0xb9, 0xef, 0x13, 0x5d, 0xb1, 0xd7, - 0xb9, 0x13, 0x56, 0x2e, 0xda, 0x54, 0x6d, 0x81, 0xbb, 0x70, 0x23, 0x26, 0x7a, 0xa6, 0x3e, 0xbf, - 0x0d, 0x2b, 0x4c, 0xe0, 0x1e, 0x21, 0xe3, 0xf6, 0xd0, 0x9c, 0xa6, 0x5a, 0x7a, 0x2c, 0x3a, 0xa5, - 0x30, 0x7e, 0xb3, 0xf3, 0x02, 0xff, 0x81, 0x40, 0xec, 0x99, 0x23, 0xd2, 0xb3, 0xf7, 0xd3, 0x75, - 0xa3, 0xd1, 0xec, 0x9c, 0x5c, 0xba, 0x62, 0x5b, 0xc3, 0xbe, 0xf1, 0x3f, 0x69, 0xc2, 0x54, 0x6a, - 0xf3, 0x6f, 0x78, 0x26, 0xaf, 0x01, 0x9c, 0xd2, 0x25, 0x43, 0x06, 0xb4, 0x82, 0x67, 0x54, 0x14, - 0x8a, 0xaf, 0x27, 0xf5, 0xdf, 0x15, 0xa1, 0xe7, 0xb2, 0x98, 0xe7, 0xec, 0x8f, 0xef, 0xe5, 0xee, - 0x40, 0x99, 0x11, 0x8e, 0x3c, 0xc3, 0x9b, 0xb8, 0xb1, 0xc1, 0xf8, 0x0b, 0x31, 0xed, 0x65, 0xa3, - 0x99, 0xfa, 0xf5, 0x1d, 0xc8, 0xb3, 0xc3, 0x84, 0xdc, 0x4a, 0xdf, 0x4c, 0x98, 0x8f, 0x5c, 0x0f, - 0x5d, 0x30, 0xe2, 0x9f, 0x6b, 0x90, 0x7f, 0xc6, 0x52, 0xb0, 0x8a, 0x6a, 0xf3, 0x72, 0x2c, 0x2c, - 0x63, 0xc4, 0x13, 0x43, 0x25, 0x9d, 0x7d, 0xb3, 0xad, 0x27, 0x21, 0xce, 0x73, 0x7d, 0x9f, 0x6f, - 0x71, 0x4b, 0xba, 0x5f, 0xa6, 0x36, 0xeb, 0x0f, 0x4d, 0x62, 0x79, 0xac, 0x76, 0x9e, 0xd5, 0x2a, - 0x14, 0xba, 0x7b, 0x36, 0xdd, 0x7d, 0x62, 0x38, 0x96, 0x48, 0x9a, 0x16, 0xf5, 0x80, 0x80, 0xf7, - 0xa1, 0xce, 0xf5, 0x68, 0x0f, 0x06, 0xca, 0x06, 0xd3, 0x47, 0xd3, 0x22, 0x68, 0x21, 0x69, 0x99, - 0xa8, 0xb4, 0x5f, 0x69, 0xb0, 0xa8, 0x88, 0x9b, 0xc9, 0xaa, 0xef, 0x42, 0x9e, 0x27, 0xa9, 0xc5, - 0x4e, 0x67, 0x39, 0xdc, 0x8a, 0xc3, 0xe8, 0x82, 0x07, 0x6d, 0x42, 0x81, 0x7f, 0xc9, 0x33, 0x40, - 0x32, 0xbb, 0x64, 0xc2, 0xf7, 0x61, 0x49, 0x90, 0xc8, 0xc8, 0x4e, 0x5a, 0x18, 0x6c, 0x30, 0xf0, - 0x9f, 0xc1, 0x72, 0x98, 0x6d, 0xa6, 0x2e, 0x29, 0x4a, 0x66, 0x5e, 0x47, 0xc9, 0xb6, 0x54, 0xf2, - 0xf9, 0x78, 0xa0, 0xec, 0xa3, 0xa2, 0x33, 0x46, 0x1d, 0xaf, 0x4c, 0x78, 0xbc, 0x82, 0x0e, 0x48, - 0x11, 0xdf, 0x6a, 0x07, 0x3e, 0x90, 0xd3, 0x61, 0xdf, 0x74, 0x7d, 0x1f, 0x8e, 0xa1, 0x32, 0x34, - 0x2d, 0x62, 0x38, 0x22, 0x73, 0xae, 0xf1, 0xcc, 0xb9, 0x4a, 0xc3, 0x5f, 0x00, 0x52, 0x1b, 0x7e, - 0xab, 0x4a, 0xbf, 0x25, 0x4d, 0x76, 0xe8, 0xd8, 0x23, 0x3b, 0xd5, 0xec, 0xf8, 0xcf, 0x61, 0x25, - 0xc2, 0xf7, 0xad, 0xaa, 0xb9, 0x04, 0x8b, 0x3b, 0x44, 0x6e, 0x68, 0xa4, 0xdb, 0xfb, 0x08, 0x90, - 0x4a, 0x9c, 0x29, 0xb2, 0xb5, 0x60, 0xf1, 0x99, 0x3d, 0xa5, 0x2e, 0x92, 0x52, 0x03, 0xdf, 0xc0, - 0xf3, 0x10, 0xbe, 0x29, 0xfc, 0x32, 0x05, 0x57, 0x1b, 0xcc, 0x04, 0xfe, 0x6f, 0x1a, 0x54, 0xda, - 0x43, 0xc3, 0x19, 0x49, 0xe0, 0x1f, 0x40, 0x9e, 0x9f, 0xae, 0x45, 0x42, 0xeb, 0xad, 0xb0, 0x18, - 0x95, 0x97, 0x17, 0xda, 0xfc, 0x2c, 0x2e, 0x5a, 0x51, 0xc5, 0xc5, 0x9d, 0xd7, 0x4e, 0xe4, 0x0e, - 0x6c, 0x07, 0xbd, 0x07, 0x39, 0x83, 0x36, 0x61, 0xa1, 0xa8, 0x16, 0xcd, 0x6b, 0x30, 0x69, 0xec, - 0x0c, 0xc0, 0xb9, 0xf0, 0xf7, 0xa0, 0xac, 0x20, 0xa0, 0x02, 0x64, 0x9f, 0x74, 0xc4, 0x86, 0xbd, - 0xbd, 0xdd, 0xdb, 0x7d, 0xc1, 0x13, 0x3a, 0x35, 0x80, 0x9d, 0x8e, 0x5f, 0xce, 0xe0, 0x4f, 0x45, - 0x2b, 0xe1, 0xf6, 0x55, 0x7d, 0xb4, 0x34, 0x7d, 0x32, 0xaf, 0xa5, 0xcf, 0x05, 0x54, 0x45, 0xf7, - 0x67, 0x0d, 0x63, 0x4c, 0x5e, 0x4a, 0x18, 0x53, 0x94, 0xd7, 0x05, 0x23, 0xfe, 0x8d, 0x06, 0xf5, - 0x1d, 0xfb, 0x95, 0x75, 0xea, 0x18, 0x03, 0x7f, 0x9d, 0x7c, 0x18, 0x19, 0xa9, 0xcd, 0x48, 0x72, - 0x34, 0xc2, 0x1f, 0x10, 0x22, 0x23, 0xd6, 0x08, 0xd2, 0x86, 0x3c, 0x16, 0xca, 0x22, 0xfe, 0x00, - 0x16, 0x22, 0x8d, 0xa8, 0xed, 0x5f, 0xb4, 0xf7, 0x77, 0x77, 0xa8, 0xad, 0x59, 0x62, 0xad, 0x73, - 0xd0, 0x7e, 0xbc, 0xdf, 0x11, 0x17, 0x48, 0xed, 0x83, 0xed, 0xce, 0x7e, 0x3d, 0x83, 0xfb, 0xb0, - 0xa8, 0xc0, 0xcf, 0x7a, 0x33, 0x90, 0xa2, 0xdd, 0x02, 0x54, 0x45, 0xb4, 0x17, 0x8b, 0xf2, 0x5f, - 0x33, 0x50, 0x93, 0x94, 0x6f, 0x06, 0x13, 0xad, 0x42, 0x7e, 0x70, 0x72, 0x64, 0x7e, 0x21, 0x6f, - 0x8e, 0x44, 0x89, 0xd2, 0x87, 0x1c, 0x87, 0x5f, 0xdf, 0x8a, 0x12, 0x0d, 0xe3, 0x8e, 0xf1, 0xd2, - 0xdb, 0xb5, 0x06, 0xe4, 0x82, 0x6d, 0x0a, 0xe6, 0xf5, 0x80, 0xc0, 0x32, 0x4c, 0xe2, 0x9a, 0x97, - 0x9d, 0xac, 0x94, 0x6b, 0x5f, 0xf4, 0x00, 0xea, 0xf4, 0xbb, 0x3d, 0x1e, 0x0f, 0x4d, 0x32, 0xe0, - 0x02, 0x0a, 0x8c, 0x27, 0x46, 0xa7, 0xe8, 0xec, 0x2c, 0xe2, 0x36, 0x8a, 0x2c, 0x2c, 0x89, 0x12, - 0x5a, 0x87, 0x32, 0xd7, 0x6f, 0xd7, 0x7a, 0xee, 0x12, 0x76, 0xf7, 0x99, 0xd5, 0x55, 0x52, 0x78, - 0x9b, 0x01, 0xd1, 0x6d, 0xc6, 0x12, 0x2c, 0xb6, 0x27, 0xde, 0x59, 0xc7, 0xa2, 0xb1, 0x42, 0x5a, - 0x79, 0x19, 0x10, 0x25, 0xee, 0x98, 0xae, 0x4a, 0x15, 0xac, 0xe1, 0x01, 0xe9, 0xc0, 0x12, 0x25, - 0x12, 0xcb, 0x33, 0xfb, 0x4a, 0x5c, 0x95, 0x3b, 0x2f, 0x2d, 0xb2, 0xf3, 0x32, 0x5c, 0xf7, 0x95, - 0xed, 0x0c, 0x84, 0xcd, 0xfd, 0x32, 0x9e, 0x72, 0xc4, 0xe7, 0x6e, 0x68, 0xf7, 0xf4, 0x3b, 0x4a, - 0x41, 0xef, 0x43, 0xc1, 0x1e, 0xb3, 0x0b, 0x7e, 0x91, 0x85, 0x59, 0xdd, 0xe4, 0x4f, 0x02, 0x36, - 0x85, 0xe0, 0x2e, 0xaf, 0xd5, 0x25, 0x1b, 0xde, 0x08, 0x70, 0x9f, 0x10, 0xef, 0x0a, 0x5c, 0xfc, - 0x10, 0x56, 0x24, 0xa7, 0xb8, 0x74, 0xb8, 0x82, 0xb9, 0x0b, 0x77, 0x24, 0xf3, 0xf6, 0x99, 0x61, - 0x9d, 0x92, 0x43, 0xa1, 0xe2, 0x57, 0xb5, 0xcf, 0x63, 0x68, 0xf8, 0x7a, 0xb2, 0x83, 0xb0, 0x3d, - 0x54, 0x15, 0x98, 0xb8, 0x62, 0xfa, 0x97, 0x74, 0xf6, 0x4d, 0x69, 0x8e, 0x3d, 0xf4, 0x77, 0xbe, - 0xf4, 0x1b, 0x6f, 0xc3, 0x4d, 0x29, 0x43, 0x1c, 0x51, 0xc3, 0x42, 0x62, 0x0a, 0x25, 0x09, 0x11, - 0x06, 0xa3, 0x4d, 0xaf, 0x1e, 0x28, 0x95, 0x33, 0x6c, 0x5a, 0x26, 0x53, 0x53, 0x64, 0xae, 0xf0, - 0x39, 0x44, 0x15, 0x53, 0x36, 0x37, 0x92, 0x4c, 0x05, 0xa8, 0x64, 0x31, 0x10, 0x94, 0x1c, 0x1b, - 0x88, 0x98, 0xe8, 0x1f, 0xc1, 0x9a, 0xaf, 0x04, 0xb5, 0xdb, 0x21, 0x71, 0x46, 0xa6, 0xeb, 0x2a, - 0x69, 0xea, 0xa4, 0x8e, 0xbf, 0x05, 0xf3, 0x63, 0x22, 0x62, 0x46, 0x79, 0x0b, 0xc9, 0x49, 0xa4, - 0x34, 0x66, 0xf5, 0x78, 0x00, 0x77, 0xa5, 0x74, 0x6e, 0xd1, 0x44, 0xf1, 0x51, 0xa5, 0x64, 0xf2, - 0x2e, 0x93, 0x92, 0xbc, 0xcb, 0x46, 0xae, 0x4e, 0x3e, 0xe2, 0x86, 0x94, 0x4b, 0x74, 0xa6, 0xbd, - 0xc0, 0x1e, 0xb7, 0xa9, 0xbf, 0xb2, 0x67, 0x12, 0xf6, 0xd7, 0x1a, 0xd7, 0xec, 0xeb, 0x72, 0xc8, - 0x84, 0xf5, 0x50, 0xde, 0x4b, 0xc8, 0x22, 0xdd, 0xe4, 0xd2, 0x01, 0xd0, 0xd5, 0xd4, 0xe5, 0xbc, - 0x1e, 0xa2, 0xe1, 0x13, 0x58, 0x0e, 0xbb, 0xa1, 0x99, 0x74, 0x59, 0x86, 0x9c, 0x67, 0x9f, 0x13, - 0x19, 0x1a, 0x78, 0x41, 0xda, 0xce, 0xf7, 0x51, 0x33, 0xd9, 0xce, 0x08, 0x84, 0xb1, 0xd5, 0x31, - 0xab, 0xbe, 0x74, 0x62, 0xc9, 0x23, 0x0b, 0x2f, 0xe0, 0x03, 0x58, 0x8d, 0x7a, 0xac, 0x99, 0x54, - 0x7e, 0xc1, 0xd7, 0x52, 0x92, 0x53, 0x9b, 0x49, 0xee, 0xc7, 0x81, 0x5f, 0x52, 0x7c, 0xdb, 0x4c, - 0x22, 0x75, 0x68, 0x26, 0xb9, 0xba, 0xaf, 0x63, 0xe9, 0xf8, 0x9e, 0x6f, 0x26, 0x61, 0x6e, 0x20, - 0x6c, 0xf6, 0xe1, 0x0f, 0xdc, 0x55, 0xf6, 0x4a, 0x77, 0x25, 0x16, 0x49, 0xe0, 0x50, 0xbf, 0x81, - 0x49, 0x27, 0x30, 0x02, 0x5f, 0x3e, 0x2b, 0x06, 0x0d, 0x67, 0x3e, 0x06, 0x2b, 0xc8, 0x89, 0xad, - 0x46, 0x80, 0x99, 0x06, 0xe3, 0x93, 0xc0, 0x8d, 0xc7, 0x82, 0xc4, 0x4c, 0x82, 0x3f, 0x85, 0xf5, - 0xf4, 0xf8, 0x30, 0x8b, 0xe4, 0x07, 0x2d, 0x28, 0xf9, 0x67, 0x17, 0xe5, 0x79, 0x58, 0x19, 0x0a, - 0x07, 0xdd, 0xa3, 0xc3, 0xf6, 0x76, 0x87, 0xbf, 0x0f, 0xdb, 0xee, 0xea, 0xfa, 0xf3, 0xc3, 0x5e, - 0x3d, 0xb3, 0xf5, 0xdb, 0x2c, 0x64, 0xf6, 0x5e, 0xa0, 0xcf, 0x20, 0xc7, 0x1f, 0x4b, 0x5c, 0xf1, - 0x42, 0xa6, 0x79, 0xd5, 0x7b, 0x10, 0x7c, 0xe3, 0xa7, 0xff, 0xf9, 0xdb, 0x5f, 0x66, 0x16, 0x71, - 0xa5, 0x35, 0xfd, 0x6e, 0xeb, 0x7c, 0xda, 0x62, 0x61, 0xea, 0x91, 0xf6, 0x00, 0x7d, 0x0c, 0xd9, - 0xc3, 0x89, 0x87, 0x52, 0x5f, 0xce, 0x34, 0xd3, 0x9f, 0x88, 0xe0, 0x15, 0x26, 0x74, 0x01, 0x83, - 0x10, 0x3a, 0x9e, 0x78, 0x54, 0xe4, 0x8f, 0xa1, 0xac, 0x3e, 0xf0, 0xb8, 0xf6, 0x39, 0x4d, 0xf3, - 0xfa, 0xc7, 0x23, 0xf8, 0x0e, 0x83, 0xba, 0x81, 0x91, 0x80, 0xe2, 0x4f, 0x50, 0xd4, 0x5e, 0xf4, - 0x2e, 0x2c, 0x94, 0xfa, 0xd8, 0xa6, 0x99, 0xfe, 0x9e, 0x24, 0xd6, 0x0b, 0xef, 0xc2, 0xa2, 0x22, - 0xff, 0x44, 0x3c, 0x25, 0xe9, 0x7b, 0xe8, 0x6e, 0xc2, 0x53, 0x02, 0xf5, 0xd2, 0xbc, 0xb9, 0x9e, - 0xce, 0x20, 0x40, 0x6e, 0x33, 0x90, 0x55, 0xbc, 0x28, 0x40, 0xfa, 0x3e, 0xcb, 0x23, 0xed, 0xc1, - 0x56, 0x1f, 0x72, 0xec, 0x42, 0x0a, 0x7d, 0x2e, 0x3f, 0x9a, 0x09, 0x37, 0x73, 0x29, 0x03, 0x1d, - 0xba, 0xca, 0xc2, 0xcb, 0x0c, 0xa8, 0x86, 0x4b, 0x14, 0x88, 0x5d, 0x47, 0x3d, 0xd2, 0x1e, 0x6c, - 0x68, 0xef, 0x6b, 0x5b, 0xbf, 0xc9, 0x41, 0x8e, 0x65, 0x62, 0xd1, 0x39, 0x40, 0x70, 0x39, 0x13, - 0xed, 0x5d, 0xec, 0xba, 0x27, 0xda, 0xbb, 0xf8, 0xbd, 0x0e, 0x6e, 0x32, 0xd0, 0x65, 0xbc, 0x40, - 0x41, 0x59, 0x82, 0xb7, 0xc5, 0x72, 0xd6, 0xd4, 0x8e, 0x7f, 0xa3, 0x89, 0x44, 0x34, 0x5f, 0x4b, - 0x28, 0x49, 0x5a, 0xe8, 0x86, 0x26, 0x3a, 0x1d, 0x12, 0x6e, 0x67, 0xf0, 0xf7, 0x19, 0x60, 0x0b, - 0xd7, 0x03, 0x40, 0x87, 0x71, 0x3c, 0xd2, 0x1e, 0x7c, 0xde, 0xc0, 0x4b, 0xc2, 0xca, 0x91, 0x1a, - 0xf4, 0x13, 0xa8, 0x85, 0x6f, 0x20, 0xd0, 0xbd, 0x04, 0xac, 0xe8, 0x45, 0x46, 0xf3, 0xcd, 0xab, - 0x99, 0x84, 0x4e, 0x6b, 0x4c, 0x27, 0x01, 0xce, 0x91, 0xcf, 0x09, 0x19, 0x1b, 0x94, 0x49, 0x8c, - 0x01, 0xfa, 0x07, 0x4d, 0x5c, 0x10, 0x05, 0x57, 0x0a, 0x28, 0x49, 0x7a, 0xec, 0xc2, 0xa2, 0x79, - 0xff, 0x1a, 0x2e, 0xa1, 0xc4, 0x1f, 0x32, 0x25, 0x3e, 0xc0, 0xcb, 0x81, 0x12, 0x9e, 0x39, 0x22, - 0x9e, 0x2d, 0xb4, 0xf8, 0xfc, 0x36, 0xbe, 0x11, 0x32, 0x4e, 0xa8, 0x36, 0x18, 0x2c, 0x7e, 0x2d, - 0x90, 0x38, 0x58, 0xa1, 0x6b, 0x86, 0xc4, 0xc1, 0x0a, 0xdf, 0x29, 0x24, 0x0d, 0x16, 0xbf, 0x04, - 0x48, 0x1a, 0x2c, 0xbf, 0x66, 0xeb, 0x7f, 0xe7, 0xa1, 0xb0, 0xcd, 0x9f, 0x70, 0x23, 0x1b, 0x4a, - 0x7e, 0x56, 0x1d, 0xad, 0x25, 0xa5, 0x05, 0x83, 0x63, 0x4d, 0xf3, 0x6e, 0x6a, 0xbd, 0x50, 0xe8, - 0x0d, 0xa6, 0xd0, 0x2d, 0xbc, 0x4a, 0x91, 0xc5, 0x2b, 0xf1, 0x16, 0xcf, 0x3d, 0xb5, 0x8c, 0xc1, - 0x80, 0x1a, 0xe2, 0x4f, 0xa1, 0xa2, 0xa6, 0xbd, 0xd1, 0x1b, 0x89, 0xa9, 0x48, 0x35, 0x73, 0xde, - 0xc4, 0x57, 0xb1, 0x08, 0xe4, 0x37, 0x19, 0xf2, 0x1a, 0xbe, 0x99, 0x80, 0xec, 0x30, 0xd6, 0x10, - 0x38, 0x4f, 0x59, 0x27, 0x83, 0x87, 0x32, 0xe2, 0xc9, 0xe0, 0xe1, 0x8c, 0xf7, 0x95, 0xe0, 0x13, - 0xc6, 0x4a, 0xc1, 0x5d, 0x80, 0x20, 0xf1, 0x8c, 0x12, 0x6d, 0xa9, 0x9c, 0xeb, 0xa2, 0xce, 0x21, - 0x9e, 0xb3, 0xc6, 0x98, 0xc1, 0x8a, 0x79, 0x17, 0x81, 0x1d, 0x9a, 0xae, 0xc7, 0x17, 0x66, 0x35, - 0x94, 0x49, 0x46, 0x89, 0xfd, 0x09, 0xa7, 0xa3, 0x9b, 0xf7, 0xae, 0xe4, 0x11, 0xe8, 0xf7, 0x19, - 0xfa, 0x5d, 0xdc, 0x4c, 0x40, 0x1f, 0x73, 0x5e, 0x3a, 0xd9, 0xfe, 0x2f, 0x0f, 0xe5, 0x67, 0x86, - 0x69, 0x79, 0xc4, 0x32, 0xac, 0x3e, 0x41, 0x27, 0x90, 0x63, 0x91, 0x3a, 0xea, 0x88, 0xd5, 0x2c, - 0x6b, 0xd4, 0x11, 0x87, 0x52, 0x90, 0x78, 0x9d, 0x01, 0x37, 0xf1, 0x0a, 0x05, 0x1e, 0x05, 0xa2, - 0x5b, 0x2c, 0x73, 0x48, 0x3b, 0xfd, 0x12, 0xf2, 0xe2, 0x72, 0x2e, 0x22, 0x28, 0x94, 0xab, 0x69, - 0xde, 0x4e, 0xae, 0x4c, 0x9a, 0xcb, 0x2a, 0x8c, 0xcb, 0xf8, 0x28, 0xce, 0x14, 0x20, 0x48, 0x89, - 0x47, 0x47, 0x34, 0x96, 0x41, 0x6f, 0xae, 0xa7, 0x33, 0x24, 0xd9, 0x54, 0xc5, 0x1c, 0xf8, 0xbc, - 0x14, 0xf7, 0x8f, 0x61, 0xfe, 0xa9, 0xe1, 0x9e, 0xa1, 0x48, 0xec, 0x55, 0x9e, 0x76, 0x35, 0x9b, - 0x49, 0x55, 0x02, 0xe5, 0x2e, 0x43, 0xb9, 0xc9, 0x5d, 0x99, 0x8a, 0x72, 0x66, 0xb8, 0x34, 0xa8, - 0xa1, 0x01, 0xe4, 0xf9, 0x4b, 0xaf, 0xa8, 0xfd, 0x42, 0xaf, 0xc5, 0xa2, 0xf6, 0x0b, 0x3f, 0x0e, - 0xbb, 0x1e, 0x65, 0x0c, 0x45, 0xf9, 0xb4, 0x0a, 0x45, 0xee, 0xd9, 0x23, 0xcf, 0xb0, 0x9a, 0x6b, - 0x69, 0xd5, 0x02, 0xeb, 0x1e, 0xc3, 0xba, 0x83, 0x1b, 0xb1, 0xb1, 0x12, 0x9c, 0x8f, 0xb4, 0x07, - 0xef, 0x6b, 0xe8, 0x27, 0x00, 0xc1, 0x2d, 0x42, 0x6c, 0x05, 0x46, 0x2f, 0x24, 0x62, 0x2b, 0x30, - 0x76, 0x01, 0x81, 0x37, 0x19, 0xee, 0x06, 0xbe, 0x17, 0xc5, 0xf5, 0x1c, 0xc3, 0x72, 0x5f, 0x12, - 0xe7, 0x3d, 0x9e, 0x14, 0x75, 0xcf, 0xcc, 0x31, 0xed, 0xb2, 0x03, 0x25, 0x3f, 0x49, 0x1c, 0xf5, - 0xb6, 0xd1, 0xe4, 0x75, 0xd4, 0xdb, 0xc6, 0xb2, 0xcb, 0x61, 0xb7, 0x13, 0x9a, 0x2d, 0x92, 0x95, - 0x2e, 0xc0, 0x5f, 0xd5, 0x61, 0x9e, 0xee, 0xba, 0xe9, 0xe6, 0x24, 0xc8, 0x9b, 0x44, 0x7b, 0x1f, - 0x4b, 0x7a, 0x46, 0x7b, 0x1f, 0x4f, 0xb9, 0x84, 0x37, 0x27, 0xec, 0x07, 0x47, 0x3c, 0x45, 0x41, - 0x7b, 0x6a, 0x43, 0x59, 0x49, 0xac, 0xa0, 0x04, 0x61, 0xe1, 0x6c, 0x6a, 0x34, 0xdc, 0x25, 0x64, - 0x65, 0xf0, 0x2d, 0x86, 0xb7, 0xc2, 0xc3, 0x1d, 0xc3, 0x1b, 0x70, 0x0e, 0x0a, 0x28, 0x7a, 0x27, - 0xd6, 0x7d, 0x42, 0xef, 0xc2, 0x6b, 0x7f, 0x3d, 0x9d, 0x21, 0xb5, 0x77, 0xc1, 0xc2, 0x7f, 0x05, - 0x15, 0x35, 0xbd, 0x82, 0x12, 0x94, 0x8f, 0x64, 0x80, 0xa3, 0x71, 0x24, 0x29, 0x3b, 0x13, 0xf6, - 0x6c, 0xfe, 0x2f, 0xb8, 0x24, 0x1b, 0x05, 0x1e, 0x42, 0x41, 0xe4, 0x5b, 0x92, 0x4c, 0x1a, 0x4e, - 0x17, 0x27, 0x99, 0x34, 0x92, 0xac, 0x09, 0xef, 0x9e, 0x19, 0x22, 0x3d, 0x52, 0xca, 0x58, 0x2d, - 0xd0, 0x9e, 0x10, 0x2f, 0x0d, 0x2d, 0xc8, 0x64, 0xa6, 0xa1, 0x29, 0xc7, 0xf9, 0x34, 0xb4, 0x53, - 0xe2, 0x09, 0x7f, 0x20, 0x8f, 0xc9, 0x28, 0x45, 0x98, 0x1a, 0x1f, 0xf1, 0x55, 0x2c, 0x49, 0x87, - 0x9b, 0x00, 0x50, 0x06, 0xc7, 0x0b, 0x80, 0x20, 0x1b, 0x14, 0xdd, 0xb1, 0x26, 0x66, 0xb7, 0xa3, - 0x3b, 0xd6, 0xe4, 0x84, 0x52, 0xd8, 0xf7, 0x05, 0xb8, 0xfc, 0x6c, 0x45, 0x91, 0x7f, 0xa1, 0x01, - 0x8a, 0x27, 0x8e, 0xd0, 0xc3, 0x64, 0xe9, 0x89, 0x39, 0xf3, 0xe6, 0xbb, 0xaf, 0xc7, 0x9c, 0x14, - 0xce, 0x02, 0x95, 0xfa, 0x8c, 0x7b, 0xfc, 0x8a, 0x2a, 0xf5, 0x97, 0x1a, 0x54, 0x43, 0x59, 0x27, - 0xf4, 0x56, 0xca, 0x98, 0x46, 0x52, 0xee, 0xcd, 0xb7, 0xaf, 0xe5, 0x4b, 0xda, 0xca, 0x2b, 0x33, - 0x40, 0x9e, 0x69, 0x7e, 0xa6, 0x41, 0x2d, 0x9c, 0xa5, 0x42, 0x29, 0xb2, 0x63, 0x29, 0xfb, 0xe6, - 0xc6, 0xf5, 0x8c, 0x57, 0x0f, 0x4f, 0x70, 0x9c, 0x19, 0x42, 0x41, 0xe4, 0xb5, 0x92, 0x26, 0x7e, - 0x38, 0xd9, 0x9f, 0x34, 0xf1, 0x23, 0x49, 0xb1, 0x84, 0x89, 0xef, 0xd8, 0x43, 0xa2, 0x2c, 0x33, - 0x91, 0xf8, 0x4a, 0x43, 0xbb, 0x7a, 0x99, 0x45, 0xb2, 0x66, 0x69, 0x68, 0xc1, 0x32, 0x93, 0x19, - 0x2f, 0x94, 0x22, 0xec, 0x9a, 0x65, 0x16, 0x4d, 0x98, 0x25, 0x2c, 0x33, 0x06, 0xa8, 0x2c, 0xb3, - 0x20, 0x37, 0x95, 0xb4, 0xcc, 0x62, 0x77, 0x17, 0x49, 0xcb, 0x2c, 0x9e, 0xde, 0x4a, 0x18, 0x47, - 0x86, 0x1b, 0x5a, 0x66, 0x4b, 0x09, 0x69, 0x2c, 0xf4, 0x6e, 0x8a, 0x11, 0x13, 0xaf, 0x44, 0x9a, - 0xef, 0xbd, 0x26, 0x77, 0xea, 0x1c, 0xe7, 0xe6, 0x97, 0x73, 0xfc, 0x6f, 0x35, 0x58, 0x4e, 0x4a, - 0x81, 0xa1, 0x14, 0x9c, 0x94, 0xab, 0x94, 0xe6, 0xe6, 0xeb, 0xb2, 0x5f, 0x6d, 0x2d, 0x7f, 0xd6, - 0x3f, 0xae, 0xff, 0xcb, 0x97, 0x6b, 0xda, 0xbf, 0x7f, 0xb9, 0xa6, 0xfd, 0xd7, 0x97, 0x6b, 0xda, - 0xdf, 0xfd, 0xf7, 0xda, 0xdc, 0x49, 0x9e, 0xfd, 0x2e, 0xf8, 0xbb, 0xff, 0x1f, 0x00, 0x00, 0xff, - 0xff, 0x96, 0xe0, 0x1c, 0xf8, 0x9e, 0x3c, 0x00, 0x00, + 0x75, 0xe6, 0x00, 0xc4, 0xed, 0xe0, 0x42, 0xb0, 0x79, 0x11, 0x04, 0x49, 0x14, 0xb7, 0xb5, 0xd2, + 0x72, 0xa5, 0x5d, 0x62, 0x4d, 0xdb, 0xd9, 0x2a, 0x25, 0x71, 0x0c, 0x91, 0x58, 0x89, 0x4b, 0x8a, + 0xe4, 0x0e, 0x21, 0xed, 0xa5, 0x5c, 0x61, 0x0d, 0x81, 0x26, 0x39, 0x21, 0x30, 0x03, 0xcf, 0x0c, + 0x20, 0x72, 0x73, 0x71, 0xca, 0xe5, 0xb8, 0x92, 0x57, 0xbb, 0x2a, 0x95, 0x3c, 0x24, 0x2f, 0xa9, + 0x94, 0xcb, 0x0f, 0x7e, 0xce, 0x5f, 0xc8, 0x53, 0x2e, 0x95, 0x3f, 0x90, 0xda, 0xf8, 0x25, 0xf9, + 0x11, 0x29, 0x57, 0xdf, 0x66, 0x7a, 0x6e, 0xa4, 0x6c, 0xac, 0xf6, 0x85, 0x9c, 0x3e, 0x7d, 0xfa, + 0x7c, 0xa7, 0x4f, 0x77, 0x9f, 0xd3, 0x7d, 0xba, 0x01, 0x25, 0x67, 0xd4, 0x5b, 0x1f, 0x39, 0xb6, + 0x67, 0xa3, 0x0a, 0xf1, 0x7a, 0x7d, 0x97, 0x38, 0x13, 0xe2, 0x8c, 0x8e, 0x9b, 0x8b, 0xa7, 0xf6, + 0xa9, 0xcd, 0x2a, 0x5a, 0xf4, 0x8b, 0xf3, 0x34, 0x6f, 0x52, 0x9e, 0xd6, 0x70, 0xd2, 0xeb, 0xb1, + 0x3f, 0xa3, 0xe3, 0xd6, 0xf9, 0x44, 0x54, 0xdd, 0x62, 0x55, 0xc6, 0xd8, 0x3b, 0x63, 0x7f, 0x46, + 0xc7, 0xec, 0x9f, 0xa8, 0xbc, 0x7d, 0x6a, 0xdb, 0xa7, 0x03, 0xd2, 0x32, 0x46, 0x66, 0xcb, 0xb0, + 0x2c, 0xdb, 0x33, 0x3c, 0xd3, 0xb6, 0x5c, 0x5e, 0x8b, 0xff, 0x4a, 0x83, 0x9a, 0x4e, 0xdc, 0x91, + 0x6d, 0xb9, 0xe4, 0x19, 0x31, 0xfa, 0xc4, 0x41, 0x77, 0x00, 0x7a, 0x83, 0xb1, 0xeb, 0x11, 0xe7, + 0xc8, 0xec, 0x37, 0xb4, 0x55, 0x6d, 0x6d, 0x56, 0x2f, 0x09, 0xca, 0x76, 0x1f, 0xdd, 0x82, 0xd2, + 0x90, 0x0c, 0x8f, 0x79, 0x6d, 0x86, 0xd5, 0x16, 0x39, 0x61, 0xbb, 0x8f, 0x9a, 0x50, 0x74, 0xc8, + 0xc4, 0x74, 0x4d, 0xdb, 0x6a, 0x64, 0x57, 0xb5, 0xb5, 0xac, 0xee, 0x97, 0x69, 0x43, 0xc7, 0x38, + 0xf1, 0x8e, 0x3c, 0xe2, 0x0c, 0x1b, 0xb3, 0xbc, 0x21, 0x25, 0x74, 0x89, 0x33, 0xc4, 0x3f, 0xc9, + 0x41, 0x45, 0x37, 0xac, 0x53, 0xa2, 0x93, 0x1f, 0x8e, 0x89, 0xeb, 0xa1, 0x3a, 0x64, 0xcf, 0xc9, + 0x25, 0x83, 0xaf, 0xe8, 0xf4, 0x93, 0xb7, 0xb7, 0x4e, 0xc9, 0x11, 0xb1, 0x38, 0x70, 0x85, 0xb6, + 0xb7, 0x4e, 0x49, 0xc7, 0xea, 0xa3, 0x45, 0xc8, 0x0d, 0xcc, 0xa1, 0xe9, 0x09, 0x54, 0x5e, 0x08, + 0xa9, 0x33, 0x1b, 0x51, 0x67, 0x13, 0xc0, 0xb5, 0x1d, 0xef, 0xc8, 0x76, 0xfa, 0xc4, 0x69, 0xe4, + 0x56, 0xb5, 0xb5, 0xda, 0xc6, 0xdb, 0xeb, 0xea, 0x40, 0xac, 0xab, 0x0a, 0xad, 0x1f, 0xda, 0x8e, + 0xb7, 0x4f, 0x79, 0xf5, 0x92, 0x2b, 0x3f, 0xd1, 0x47, 0x50, 0x66, 0x42, 0x3c, 0xc3, 0x39, 0x25, + 0x5e, 0x23, 0xcf, 0xa4, 0xdc, 0xbf, 0x46, 0x4a, 0x97, 0x31, 0xeb, 0x0c, 0x9e, 0x7f, 0x23, 0x0c, + 0x15, 0x97, 0x38, 0xa6, 0x31, 0x30, 0xbf, 0x34, 0x8e, 0x07, 0xa4, 0x51, 0x58, 0xd5, 0xd6, 0x8a, + 0x7a, 0x88, 0x46, 0xfb, 0x7f, 0x4e, 0x2e, 0xdd, 0x23, 0xdb, 0x1a, 0x5c, 0x36, 0x8a, 0x8c, 0xa1, + 0x48, 0x09, 0xfb, 0xd6, 0xe0, 0x92, 0x0d, 0x9a, 0x3d, 0xb6, 0x3c, 0x5e, 0x5b, 0x62, 0xb5, 0x25, + 0x46, 0x61, 0xd5, 0x6b, 0x50, 0x1f, 0x9a, 0xd6, 0xd1, 0xd0, 0xee, 0x1f, 0xf9, 0x06, 0x01, 0x66, + 0x90, 0xda, 0xd0, 0xb4, 0x9e, 0xdb, 0x7d, 0x5d, 0x9a, 0x85, 0x72, 0x1a, 0x17, 0x61, 0xce, 0xb2, + 0xe0, 0x34, 0x2e, 0x54, 0xce, 0x75, 0x58, 0xa0, 0x32, 0x7b, 0x0e, 0x31, 0x3c, 0x12, 0x30, 0x57, + 0x18, 0xf3, 0xfc, 0xd0, 0xb4, 0x36, 0x59, 0x4d, 0x88, 0xdf, 0xb8, 0x88, 0xf1, 0x57, 0x05, 0xbf, + 0x71, 0x11, 0xe6, 0xc7, 0xeb, 0x50, 0xf2, 0x6d, 0x8e, 0x8a, 0x30, 0xbb, 0xb7, 0xbf, 0xd7, 0xa9, + 0xcf, 0x20, 0x80, 0x7c, 0xfb, 0x70, 0xb3, 0xb3, 0xb7, 0x55, 0xd7, 0x50, 0x19, 0x0a, 0x5b, 0x1d, + 0x5e, 0xc8, 0xe0, 0x27, 0x00, 0x81, 0x75, 0x51, 0x01, 0xb2, 0x3b, 0x9d, 0xcf, 0xeb, 0x33, 0x94, + 0xe7, 0x65, 0x47, 0x3f, 0xdc, 0xde, 0xdf, 0xab, 0x6b, 0xb4, 0xf1, 0xa6, 0xde, 0x69, 0x77, 0x3b, + 0xf5, 0x0c, 0xe5, 0x78, 0xbe, 0xbf, 0x55, 0xcf, 0xa2, 0x12, 0xe4, 0x5e, 0xb6, 0x77, 0x5f, 0x74, + 0xea, 0xb3, 0xf8, 0xe7, 0x1a, 0x54, 0xc5, 0x78, 0xf1, 0x35, 0x81, 0xbe, 0x03, 0xf9, 0x33, 0xb6, + 0x2e, 0xd8, 0x54, 0x2c, 0x6f, 0xdc, 0x8e, 0x0c, 0x6e, 0x68, 0xed, 0xe8, 0x82, 0x17, 0x61, 0xc8, + 0x9e, 0x4f, 0xdc, 0x46, 0x66, 0x35, 0xbb, 0x56, 0xde, 0xa8, 0xaf, 0xf3, 0x05, 0xbb, 0xbe, 0x43, + 0x2e, 0x5f, 0x1a, 0x83, 0x31, 0xd1, 0x69, 0x25, 0x42, 0x30, 0x3b, 0xb4, 0x1d, 0xc2, 0x66, 0x6c, + 0x51, 0x67, 0xdf, 0x74, 0x1a, 0xb3, 0x41, 0x13, 0xb3, 0x95, 0x17, 0xf0, 0x2f, 0x35, 0x80, 0x83, + 0xb1, 0x97, 0xbe, 0x34, 0x16, 0x21, 0x37, 0xa1, 0x82, 0xc5, 0xb2, 0xe0, 0x05, 0xb6, 0x26, 0x88, + 0xe1, 0x12, 0x7f, 0x4d, 0xd0, 0x02, 0xba, 0x01, 0x85, 0x91, 0x43, 0x26, 0x47, 0xe7, 0x13, 0x06, + 0x52, 0xd4, 0xf3, 0xb4, 0xb8, 0x33, 0x41, 0x6f, 0x41, 0xc5, 0x3c, 0xb5, 0x6c, 0x87, 0x1c, 0x71, + 0x59, 0x39, 0x56, 0x5b, 0xe6, 0x34, 0xa6, 0xb7, 0xc2, 0xc2, 0x05, 0xe7, 0x55, 0x96, 0x5d, 0x4a, + 0xc2, 0x16, 0x94, 0x99, 0xaa, 0x53, 0x99, 0xef, 0xdd, 0x40, 0xc7, 0x0c, 0x6b, 0x16, 0x37, 0xa1, + 0xd0, 0x1a, 0xff, 0x00, 0xd0, 0x16, 0x19, 0x10, 0x8f, 0x4c, 0xe3, 0x3d, 0x14, 0x9b, 0x64, 0x55, + 0x9b, 0xe0, 0x9f, 0x69, 0xb0, 0x10, 0x12, 0x3f, 0x55, 0xb7, 0x1a, 0x50, 0xe8, 0x33, 0x61, 0x5c, + 0x83, 0xac, 0x2e, 0x8b, 0xe8, 0x11, 0x14, 0x85, 0x02, 0x6e, 0x23, 0x9b, 0x32, 0x69, 0x0a, 0x5c, + 0x27, 0x17, 0xff, 0x32, 0x03, 0x25, 0xd1, 0xd1, 0xfd, 0x11, 0x6a, 0x43, 0xd5, 0xe1, 0x85, 0x23, + 0xd6, 0x1f, 0xa1, 0x51, 0x33, 0xdd, 0x09, 0x3d, 0x9b, 0xd1, 0x2b, 0xa2, 0x09, 0x23, 0xa3, 0xdf, + 0x87, 0xb2, 0x14, 0x31, 0x1a, 0x7b, 0xc2, 0xe4, 0x8d, 0xb0, 0x80, 0x60, 0xfe, 0x3d, 0x9b, 0xd1, + 0x41, 0xb0, 0x1f, 0x8c, 0x3d, 0xd4, 0x85, 0x45, 0xd9, 0x98, 0xf7, 0x46, 0xa8, 0x91, 0x65, 0x52, + 0x56, 0xc3, 0x52, 0xe2, 0x43, 0xf5, 0x6c, 0x46, 0x47, 0xa2, 0xbd, 0x52, 0xa9, 0xaa, 0xe4, 0x5d, + 0x70, 0xe7, 0x1d, 0x53, 0xa9, 0x7b, 0x61, 0xc5, 0x55, 0xea, 0x5e, 0x58, 0x4f, 0x4a, 0x50, 0x10, + 0x25, 0xfc, 0x2f, 0x19, 0x00, 0x39, 0x1a, 0xfb, 0x23, 0xb4, 0x05, 0x35, 0x47, 0x94, 0x42, 0xd6, + 0xba, 0x95, 0x68, 0x2d, 0x31, 0x88, 0x33, 0x7a, 0x55, 0x36, 0xe2, 0xca, 0x7d, 0x0f, 0x2a, 0xbe, + 0x94, 0xc0, 0x60, 0x37, 0x13, 0x0c, 0xe6, 0x4b, 0x28, 0xcb, 0x06, 0xd4, 0x64, 0x9f, 0xc2, 0x92, + 0xdf, 0x3e, 0xc1, 0x66, 0x6f, 0x5d, 0x61, 0x33, 0x5f, 0xe0, 0x82, 0x94, 0xa0, 0x5a, 0x4d, 0x55, + 0x2c, 0x30, 0xdb, 0xcd, 0x04, 0xb3, 0xc5, 0x15, 0xa3, 0x86, 0x03, 0x1a, 0x2f, 0x79, 0x11, 0xff, + 0x6f, 0x16, 0x0a, 0x9b, 0xf6, 0x70, 0x64, 0x38, 0x74, 0x34, 0xf2, 0x0e, 0x71, 0xc7, 0x03, 0x8f, + 0x99, 0xab, 0xb6, 0x71, 0x2f, 0x2c, 0x51, 0xb0, 0xc9, 0xff, 0x3a, 0x63, 0xd5, 0x45, 0x13, 0xda, + 0x58, 0x84, 0xc7, 0xcc, 0x6b, 0x34, 0x16, 0xc1, 0x51, 0x34, 0x91, 0x0b, 0x39, 0x1b, 0x2c, 0xe4, + 0x26, 0x14, 0x26, 0xc4, 0x09, 0x42, 0xfa, 0xb3, 0x19, 0x5d, 0x12, 0xd0, 0xbb, 0x30, 0x17, 0x0d, + 0x2f, 0x39, 0xc1, 0x53, 0xeb, 0x85, 0xa3, 0xd1, 0x3d, 0xa8, 0x84, 0x62, 0x5c, 0x5e, 0xf0, 0x95, + 0x87, 0x4a, 0x88, 0x5b, 0x96, 0x7e, 0x95, 0xc6, 0xe3, 0xca, 0xb3, 0x19, 0xe9, 0x59, 0x97, 0xa5, + 0x67, 0x2d, 0x8a, 0x56, 0xc2, 0xb7, 0x86, 0x9c, 0xcc, 0xf7, 0xc3, 0x4e, 0x06, 0x7f, 0x1f, 0xaa, + 0x21, 0x03, 0xd1, 0xb8, 0xd3, 0xf9, 0xe4, 0x45, 0x7b, 0x97, 0x07, 0xa9, 0xa7, 0x2c, 0x2e, 0xe9, + 0x75, 0x8d, 0xc6, 0xba, 0xdd, 0xce, 0xe1, 0x61, 0x3d, 0x83, 0xaa, 0x50, 0xda, 0xdb, 0xef, 0x1e, + 0x71, 0xae, 0x2c, 0x7e, 0xea, 0x4b, 0x10, 0x41, 0x4e, 0x89, 0x6d, 0x33, 0x4a, 0x6c, 0xd3, 0x64, + 0x6c, 0xcb, 0x04, 0xb1, 0x8d, 0x85, 0xb9, 0xdd, 0x4e, 0xfb, 0xb0, 0x53, 0x9f, 0x7d, 0x52, 0x83, + 0x0a, 0xb7, 0xef, 0xd1, 0xd8, 0xa2, 0xa1, 0xf6, 0x9f, 0x34, 0x80, 0x60, 0x35, 0xa1, 0x16, 0x14, + 0x7a, 0x1c, 0xa7, 0xa1, 0x31, 0x67, 0xb4, 0x94, 0x38, 0x64, 0xba, 0xe4, 0x42, 0xdf, 0x82, 0x82, + 0x3b, 0xee, 0xf5, 0x88, 0x2b, 0x43, 0xde, 0x8d, 0xa8, 0x3f, 0x14, 0xde, 0x4a, 0x97, 0x7c, 0xb4, + 0xc9, 0x89, 0x61, 0x0e, 0xc6, 0x2c, 0x00, 0x5e, 0xdd, 0x44, 0xf0, 0xe1, 0xbf, 0xd7, 0xa0, 0xac, + 0x4c, 0xde, 0xdf, 0xd1, 0x09, 0xdf, 0x86, 0x12, 0xd3, 0x81, 0xf4, 0x85, 0x1b, 0x2e, 0xea, 0x01, + 0x01, 0xfd, 0x1e, 0x94, 0xe4, 0x0a, 0x90, 0x9e, 0xb8, 0x91, 0x2c, 0x76, 0x7f, 0xa4, 0x07, 0xac, + 0x78, 0x07, 0xe6, 0x99, 0x55, 0x7a, 0x74, 0x73, 0x2d, 0xed, 0xa8, 0x6e, 0x3f, 0xb5, 0xc8, 0xf6, + 0xb3, 0x09, 0xc5, 0xd1, 0xd9, 0xa5, 0x6b, 0xf6, 0x8c, 0x81, 0xd0, 0xc2, 0x2f, 0xe3, 0x8f, 0x01, + 0xa9, 0xc2, 0xa6, 0xe9, 0x2e, 0xae, 0x42, 0xf9, 0x99, 0xe1, 0x9e, 0x09, 0x95, 0xf0, 0x23, 0xa8, + 0xd2, 0xe2, 0xce, 0xcb, 0xd7, 0xd0, 0x91, 0x1d, 0x0e, 0x24, 0xf7, 0x54, 0x36, 0x47, 0x30, 0x7b, + 0x66, 0xb8, 0x67, 0xac, 0xa3, 0x55, 0x9d, 0x7d, 0xa3, 0x77, 0xa1, 0xde, 0xe3, 0x9d, 0x3c, 0x8a, + 0x1c, 0x19, 0xe6, 0x04, 0xdd, 0xdf, 0x09, 0x7e, 0x06, 0x15, 0xde, 0x87, 0xaf, 0x5b, 0x09, 0x3c, + 0x0f, 0x73, 0x87, 0x96, 0x31, 0x72, 0xcf, 0x6c, 0x19, 0xdd, 0x68, 0xa7, 0xeb, 0x01, 0x6d, 0x2a, + 0xc4, 0x77, 0x60, 0xce, 0x21, 0x43, 0xc3, 0xb4, 0x4c, 0xeb, 0xf4, 0xe8, 0xf8, 0xd2, 0x23, 0xae, + 0x38, 0x30, 0xd5, 0x7c, 0xf2, 0x13, 0x4a, 0xa5, 0xaa, 0x1d, 0x0f, 0xec, 0x63, 0xe1, 0xe6, 0xd8, + 0x37, 0xfe, 0x69, 0x06, 0x2a, 0x9f, 0x1a, 0x5e, 0x4f, 0x0e, 0x1d, 0xda, 0x86, 0x9a, 0xef, 0xdc, + 0x18, 0x45, 0xe8, 0x12, 0x09, 0xb1, 0xac, 0x8d, 0xdc, 0x4a, 0xcb, 0xe8, 0x58, 0xed, 0xa9, 0x04, + 0x26, 0xca, 0xb0, 0x7a, 0x64, 0xe0, 0x8b, 0xca, 0xa4, 0x8b, 0x62, 0x8c, 0xaa, 0x28, 0x95, 0x80, + 0xf6, 0xa1, 0x3e, 0x72, 0xec, 0x53, 0x87, 0xb8, 0xae, 0x2f, 0x8c, 0x87, 0x31, 0x9c, 0x20, 0xec, + 0x40, 0xb0, 0x06, 0xe2, 0xe6, 0x46, 0x61, 0xd2, 0x93, 0xb9, 0x60, 0x3f, 0xc3, 0x9d, 0xd3, 0x7f, + 0x66, 0x00, 0xc5, 0x3b, 0xf5, 0xdb, 0x6e, 0xf1, 0xee, 0x43, 0xcd, 0xf5, 0x0c, 0x27, 0x36, 0xd9, + 0xaa, 0x8c, 0xea, 0x7b, 0xfc, 0x77, 0xc0, 0x57, 0xe8, 0xc8, 0xb2, 0x3d, 0xf3, 0xe4, 0x52, 0xec, + 0x92, 0x6b, 0x92, 0xbc, 0xc7, 0xa8, 0xa8, 0x03, 0x85, 0x13, 0x73, 0xe0, 0x11, 0xc7, 0x6d, 0xe4, + 0x56, 0xb3, 0x6b, 0xb5, 0x8d, 0x47, 0xd7, 0x0d, 0xc3, 0xfa, 0x47, 0x8c, 0xbf, 0x7b, 0x39, 0x22, + 0xba, 0x6c, 0xab, 0xee, 0x3c, 0xf3, 0xa1, 0xdd, 0xf8, 0x4d, 0x28, 0xbe, 0xa2, 0x22, 0xe8, 0x29, + 0xbb, 0xc0, 0x37, 0x8b, 0xac, 0xcc, 0x0f, 0xd9, 0x27, 0x8e, 0x71, 0x3a, 0x24, 0x96, 0x27, 0xcf, + 0x81, 0xb2, 0x8c, 0xef, 0x03, 0x04, 0x30, 0xd4, 0xe5, 0xef, 0xed, 0x1f, 0xbc, 0xe8, 0xd6, 0x67, + 0x50, 0x05, 0x8a, 0x7b, 0xfb, 0x5b, 0x9d, 0xdd, 0x0e, 0x8d, 0x0f, 0xb8, 0x25, 0x4d, 0x1a, 0x1a, + 0x4b, 0x15, 0x53, 0x0b, 0x61, 0xe2, 0x65, 0x58, 0x4c, 0x1a, 0x40, 0xba, 0x17, 0xad, 0x8a, 0x59, + 0x3a, 0xd5, 0x52, 0x51, 0xa1, 0x33, 0xe1, 0xee, 0x36, 0xa0, 0xc0, 0x67, 0x6f, 0x5f, 0x6c, 0xce, + 0x65, 0x91, 0x1a, 0x82, 0x4f, 0x46, 0xd2, 0x17, 0xa3, 0xe4, 0x97, 0x13, 0xdd, 0x4b, 0x2e, 0xd1, + 0xbd, 0xa0, 0x7b, 0x50, 0xf5, 0x57, 0x83, 0xe1, 0x8a, 0xbd, 0x40, 0x49, 0xaf, 0xc8, 0x89, 0x4e, + 0x69, 0x21, 0xa3, 0x17, 0xc2, 0x46, 0x47, 0xf7, 0x21, 0x4f, 0x26, 0xc4, 0xf2, 0xdc, 0x46, 0x99, + 0x45, 0x8c, 0xaa, 0xdc, 0xbb, 0x77, 0x28, 0x55, 0x17, 0x95, 0xf8, 0xbb, 0x30, 0xcf, 0xce, 0x48, + 0x4f, 0x1d, 0xc3, 0x52, 0x0f, 0x73, 0xdd, 0xee, 0xae, 0x30, 0x37, 0xfd, 0x44, 0x35, 0xc8, 0x6c, + 0x6f, 0x09, 0x23, 0x64, 0xb6, 0xb7, 0xf0, 0x8f, 0x35, 0x40, 0x6a, 0xbb, 0xa9, 0xec, 0x1c, 0x11, + 0x2e, 0xe1, 0xb3, 0x01, 0xfc, 0x22, 0xe4, 0x88, 0xe3, 0xd8, 0x0e, 0xb3, 0x68, 0x49, 0xe7, 0x05, + 0xfc, 0xb6, 0xd0, 0x41, 0x27, 0x13, 0xfb, 0xdc, 0x5f, 0x83, 0x5c, 0x9a, 0xe6, 0xab, 0xba, 0x03, + 0x0b, 0x21, 0xae, 0xa9, 0x22, 0xd7, 0x47, 0x30, 0xc7, 0x84, 0x6d, 0x9e, 0x91, 0xde, 0xf9, 0xc8, + 0x36, 0xad, 0x18, 0x1e, 0x1d, 0xb9, 0xc0, 0xc1, 0xd2, 0x7e, 0xf0, 0x8e, 0x55, 0x7c, 0x62, 0xb7, + 0xbb, 0x8b, 0x3f, 0x87, 0xe5, 0x88, 0x1c, 0xa9, 0xfe, 0x1f, 0x41, 0xb9, 0xe7, 0x13, 0x5d, 0xb1, + 0xd7, 0xb9, 0x13, 0x56, 0x2e, 0xda, 0x54, 0x6d, 0x81, 0xf7, 0xe1, 0x46, 0x4c, 0xf4, 0x54, 0x7d, + 0x7e, 0x07, 0x96, 0x98, 0xc0, 0x1d, 0x42, 0x46, 0xed, 0x81, 0x39, 0x49, 0xb5, 0xf4, 0x48, 0x74, + 0x4a, 0x61, 0x7c, 0xb3, 0xf3, 0x02, 0xff, 0x81, 0x40, 0xec, 0x9a, 0x43, 0xd2, 0xb5, 0x77, 0xd3, + 0x75, 0xa3, 0xd1, 0xec, 0x9c, 0x5c, 0xba, 0x62, 0x5b, 0xc3, 0xbe, 0xf1, 0x3f, 0x6b, 0xc2, 0x54, + 0x6a, 0xf3, 0x37, 0x3c, 0x93, 0x57, 0x00, 0x4e, 0xe9, 0x92, 0x21, 0x7d, 0x5a, 0xc1, 0x33, 0x2a, + 0x0a, 0xc5, 0xd7, 0x93, 0xfa, 0xef, 0x8a, 0xd0, 0x73, 0x51, 0xcc, 0x73, 0xf6, 0xc7, 0xf7, 0x72, + 0x77, 0xa0, 0xcc, 0x08, 0x87, 0x9e, 0xe1, 0x8d, 0xdd, 0xd8, 0x60, 0xfc, 0x85, 0x98, 0xf6, 0xb2, + 0xd1, 0x54, 0xfd, 0xfa, 0x16, 0xe4, 0xd9, 0x61, 0x42, 0x6e, 0xa5, 0x6f, 0x26, 0xcc, 0x47, 0xae, + 0x87, 0x2e, 0x18, 0xf1, 0x4f, 0x35, 0xc8, 0x3f, 0x67, 0x29, 0x58, 0x45, 0xb5, 0x59, 0x39, 0x16, + 0x96, 0x31, 0xe4, 0x89, 0xa1, 0x92, 0xce, 0xbe, 0xd9, 0xd6, 0x93, 0x10, 0xe7, 0x85, 0xbe, 0xcb, + 0xb7, 0xb8, 0x25, 0xdd, 0x2f, 0x53, 0x9b, 0xf5, 0x06, 0x26, 0xb1, 0x3c, 0x56, 0x3b, 0xcb, 0x6a, + 0x15, 0x0a, 0xdd, 0x3d, 0x9b, 0xee, 0x2e, 0x31, 0x1c, 0x4b, 0x24, 0x4d, 0x8b, 0x7a, 0x40, 0xc0, + 0xbb, 0x50, 0xe7, 0x7a, 0xb4, 0xfb, 0x7d, 0x65, 0x83, 0xe9, 0xa3, 0x69, 0x11, 0xb4, 0x90, 0xb4, + 0x4c, 0x54, 0xda, 0x2f, 0x34, 0x98, 0x57, 0xc4, 0x4d, 0x65, 0xd5, 0xf7, 0x20, 0xcf, 0x93, 0xd4, + 0x62, 0xa7, 0xb3, 0x18, 0x6e, 0xc5, 0x61, 0x74, 0xc1, 0x83, 0xd6, 0xa1, 0xc0, 0xbf, 0xe4, 0x19, + 0x20, 0x99, 0x5d, 0x32, 0xe1, 0xfb, 0xb0, 0x20, 0x48, 0x64, 0x68, 0x27, 0x2d, 0x0c, 0x36, 0x18, + 0xf8, 0xcf, 0x60, 0x31, 0xcc, 0x36, 0x55, 0x97, 0x14, 0x25, 0x33, 0xaf, 0xa3, 0x64, 0x5b, 0x2a, + 0xf9, 0x62, 0xd4, 0x57, 0xf6, 0x51, 0xd1, 0x19, 0xa3, 0x8e, 0x57, 0x26, 0x3c, 0x5e, 0x41, 0x07, + 0xa4, 0x88, 0x6f, 0xb4, 0x03, 0x1f, 0xca, 0xe9, 0xb0, 0x6b, 0xba, 0xbe, 0x0f, 0xc7, 0x50, 0x19, + 0x98, 0x16, 0x31, 0x1c, 0x91, 0x39, 0xd7, 0x78, 0xe6, 0x5c, 0xa5, 0xe1, 0x2f, 0x01, 0xa9, 0x0d, + 0xbf, 0x51, 0xa5, 0x1f, 0x48, 0x93, 0x1d, 0x38, 0xf6, 0xd0, 0x4e, 0x35, 0x3b, 0xfe, 0x73, 0x58, + 0x8a, 0xf0, 0x7d, 0xa3, 0x6a, 0x2e, 0xc0, 0xfc, 0x16, 0x91, 0x1b, 0x1a, 0xe9, 0xf6, 0x3e, 0x06, + 0xa4, 0x12, 0xa7, 0x8a, 0x6c, 0x2d, 0x98, 0x7f, 0x6e, 0x4f, 0xa8, 0x8b, 0xa4, 0xd4, 0xc0, 0x37, + 0xf0, 0x3c, 0x84, 0x6f, 0x0a, 0xbf, 0x4c, 0xc1, 0xd5, 0x06, 0x53, 0x81, 0xff, 0xbb, 0x06, 0x95, + 0xf6, 0xc0, 0x70, 0x86, 0x12, 0xf8, 0x7b, 0x90, 0xe7, 0xa7, 0x6b, 0x91, 0xd0, 0x7a, 0x10, 0x16, + 0xa3, 0xf2, 0xf2, 0x42, 0x9b, 0x9f, 0xc5, 0x45, 0x2b, 0xaa, 0xb8, 0xb8, 0xf3, 0xda, 0x8a, 0xdc, + 0x81, 0x6d, 0xa1, 0xf7, 0x21, 0x67, 0xd0, 0x26, 0x2c, 0x14, 0xd5, 0xa2, 0x79, 0x0d, 0x26, 0x8d, + 0x9d, 0x01, 0x38, 0x17, 0xfe, 0x0e, 0x94, 0x15, 0x04, 0x54, 0x80, 0xec, 0xd3, 0x8e, 0xd8, 0xb0, + 0xb7, 0x37, 0xbb, 0xdb, 0x2f, 0x79, 0x42, 0xa7, 0x06, 0xb0, 0xd5, 0xf1, 0xcb, 0x19, 0xfc, 0x99, + 0x68, 0x25, 0xdc, 0xbe, 0xaa, 0x8f, 0x96, 0xa6, 0x4f, 0xe6, 0xb5, 0xf4, 0xb9, 0x80, 0xaa, 0xe8, + 0xfe, 0xb4, 0x61, 0x8c, 0xc9, 0x4b, 0x09, 0x63, 0x8a, 0xf2, 0xba, 0x60, 0xc4, 0xbf, 0xd2, 0xa0, + 0xbe, 0x65, 0xbf, 0xb2, 0x4e, 0x1d, 0xa3, 0xef, 0xaf, 0x93, 0x8f, 0x22, 0x23, 0xb5, 0x1e, 0x49, + 0x8e, 0x46, 0xf8, 0x03, 0x42, 0x64, 0xc4, 0x1a, 0x41, 0xda, 0x90, 0xc7, 0x42, 0x59, 0xc4, 0x1f, + 0xc2, 0x5c, 0xa4, 0x11, 0xb5, 0xfd, 0xcb, 0xf6, 0xee, 0xf6, 0x16, 0xb5, 0x35, 0x4b, 0xac, 0x75, + 0xf6, 0xda, 0x4f, 0x76, 0x3b, 0xe2, 0x02, 0xa9, 0xbd, 0xb7, 0xd9, 0xd9, 0xad, 0x67, 0x70, 0x0f, + 0xe6, 0x15, 0xf8, 0x69, 0x6f, 0x06, 0x52, 0xb4, 0x9b, 0x83, 0xaa, 0x88, 0xf6, 0x62, 0x51, 0xfe, + 0x5b, 0x06, 0x6a, 0x92, 0xf2, 0x66, 0x30, 0xd1, 0x32, 0xe4, 0xfb, 0xc7, 0x87, 0xe6, 0x97, 0xf2, + 0xe6, 0x48, 0x94, 0x28, 0x7d, 0xc0, 0x71, 0xf8, 0xf5, 0xad, 0x28, 0xd1, 0x30, 0xee, 0x18, 0x27, + 0xde, 0xb6, 0xd5, 0x27, 0x17, 0x6c, 0x53, 0x30, 0xab, 0x07, 0x04, 0x96, 0x61, 0x12, 0xd7, 0xbc, + 0xec, 0x64, 0xa5, 0x5c, 0xfb, 0xa2, 0x87, 0x50, 0xa7, 0xdf, 0xed, 0xd1, 0x68, 0x60, 0x92, 0x3e, + 0x17, 0x50, 0x60, 0x3c, 0x31, 0x3a, 0x45, 0x67, 0x67, 0x11, 0xb7, 0x51, 0x64, 0x61, 0x49, 0x94, + 0xd0, 0x2a, 0x94, 0xb9, 0x7e, 0xdb, 0xd6, 0x0b, 0x97, 0xb0, 0xbb, 0xcf, 0xac, 0xae, 0x92, 0xc2, + 0xdb, 0x0c, 0x88, 0x6e, 0x33, 0x16, 0x60, 0xbe, 0x3d, 0xf6, 0xce, 0x3a, 0x16, 0x8d, 0x15, 0xd2, + 0xca, 0x8b, 0x80, 0x28, 0x71, 0xcb, 0x74, 0x55, 0xaa, 0x60, 0x0d, 0x0f, 0x48, 0x07, 0x16, 0x28, + 0x91, 0x58, 0x9e, 0xd9, 0x53, 0xe2, 0xaa, 0xdc, 0x79, 0x69, 0x91, 0x9d, 0x97, 0xe1, 0xba, 0xaf, + 0x6c, 0xa7, 0x2f, 0x6c, 0xee, 0x97, 0xf1, 0x3f, 0x6a, 0x1c, 0xf2, 0x85, 0x1b, 0xda, 0x3e, 0xfd, + 0x96, 0x62, 0xd0, 0x07, 0x50, 0xb0, 0x47, 0xec, 0x86, 0x5f, 0xa4, 0x61, 0x96, 0xd7, 0xf9, 0x9b, + 0x80, 0x75, 0x21, 0x78, 0x9f, 0xd7, 0xea, 0x92, 0x0d, 0x3d, 0x80, 0xda, 0x99, 0xe1, 0x9e, 0x91, + 0xfe, 0x81, 0x94, 0xc9, 0x4f, 0x7e, 0x11, 0x2a, 0x5e, 0x0b, 0xf4, 0x7b, 0x4a, 0xbc, 0x2b, 0xf4, + 0xc3, 0x8f, 0x60, 0x49, 0x72, 0x8a, 0xdb, 0x89, 0x2b, 0x98, 0x5f, 0xc1, 0x1d, 0xc9, 0xbc, 0x79, + 0x66, 0x58, 0xa7, 0x44, 0x02, 0xfe, 0xae, 0x16, 0x88, 0xf7, 0x27, 0x9b, 0xd8, 0x9f, 0x27, 0xd0, + 0xf0, 0xfb, 0xc3, 0x4e, 0xd6, 0xf6, 0x40, 0x55, 0x74, 0xec, 0x8a, 0xf5, 0x54, 0xd2, 0xd9, 0x37, + 0xa5, 0x39, 0xf6, 0xc0, 0xdf, 0x4a, 0xd3, 0x6f, 0xbc, 0x09, 0x37, 0xa5, 0x0c, 0x71, 0xe6, 0x0d, + 0x0b, 0x89, 0x29, 0x9e, 0x24, 0x44, 0x18, 0x96, 0x36, 0xbd, 0x7a, 0xe0, 0x55, 0xce, 0xf0, 0x10, + 0x30, 0x99, 0x9a, 0x22, 0x73, 0x89, 0x4f, 0x4a, 0xaa, 0x98, 0xb2, 0x5b, 0x92, 0x64, 0x2a, 0x40, + 0x25, 0x8b, 0x01, 0xa3, 0xe4, 0xd8, 0x80, 0xc5, 0x44, 0xff, 0x00, 0x56, 0x7c, 0x25, 0xa8, 0xdd, + 0x0e, 0x88, 0x33, 0x34, 0x5d, 0x57, 0xc9, 0x7b, 0x27, 0x75, 0xfc, 0x01, 0xcc, 0x8e, 0x88, 0x08, + 0x42, 0xe5, 0x0d, 0x24, 0x27, 0xa5, 0xd2, 0x98, 0xd5, 0xe3, 0x3e, 0xdc, 0x95, 0xd2, 0xb9, 0x45, + 0x13, 0xc5, 0x47, 0x95, 0x92, 0xd9, 0xc0, 0x4c, 0x4a, 0x36, 0x30, 0x1b, 0xb9, 0x8b, 0xf9, 0x98, + 0x1b, 0x52, 0xae, 0xf9, 0xa9, 0x36, 0x17, 0x3b, 0xdc, 0xa6, 0xbe, 0xab, 0x98, 0x4a, 0xd8, 0x5f, + 0x0b, 0x2f, 0xf0, 0x75, 0x79, 0x78, 0xc2, 0x7a, 0x28, 0x2f, 0x3a, 0x64, 0x91, 0xee, 0x9a, 0xe9, + 0x00, 0xe8, 0x6a, 0x2e, 0x74, 0x56, 0x0f, 0xd1, 0xf0, 0x31, 0x2c, 0x86, 0xfd, 0xda, 0x54, 0xba, + 0x2c, 0x42, 0xce, 0xb3, 0xcf, 0x89, 0x8c, 0x35, 0xbc, 0x20, 0x6d, 0xe7, 0xfb, 0xbc, 0xa9, 0x6c, + 0x67, 0x04, 0xc2, 0xd8, 0xea, 0x98, 0x56, 0x5f, 0x3a, 0xb1, 0xe4, 0x19, 0x88, 0x17, 0xf0, 0x1e, + 0x2c, 0x47, 0x3d, 0xdb, 0x54, 0x2a, 0xbf, 0xe4, 0x6b, 0x29, 0xc9, 0xf9, 0x4d, 0x25, 0xf7, 0x93, + 0xc0, 0x2f, 0x29, 0xbe, 0x6d, 0x2a, 0x91, 0x3a, 0x34, 0x93, 0x5c, 0xdd, 0xd7, 0xb1, 0x74, 0x7c, + 0xcf, 0x37, 0x95, 0x30, 0x37, 0x10, 0x36, 0xfd, 0xf0, 0x07, 0xee, 0x2a, 0x7b, 0xa5, 0xbb, 0x12, + 0x8b, 0x24, 0x70, 0xa8, 0x6f, 0x60, 0xd2, 0x09, 0x8c, 0xc0, 0x97, 0x4f, 0x8b, 0x41, 0xc3, 0x99, + 0x8f, 0xc1, 0x0a, 0x72, 0x62, 0xab, 0x11, 0x60, 0xaa, 0xc1, 0xf8, 0x34, 0x70, 0xe3, 0xb1, 0x20, + 0x31, 0x95, 0xe0, 0xcf, 0x60, 0x35, 0x3d, 0x3e, 0x4c, 0x23, 0xf9, 0x61, 0x0b, 0x4a, 0xfe, 0x61, + 0x48, 0x79, 0x6f, 0x56, 0x86, 0xc2, 0xde, 0xfe, 0xe1, 0x41, 0x7b, 0xb3, 0xc3, 0x1f, 0x9c, 0x6d, + 0xee, 0xeb, 0xfa, 0x8b, 0x83, 0x6e, 0x3d, 0xb3, 0xf1, 0xeb, 0x2c, 0x64, 0x76, 0x5e, 0xa2, 0xcf, + 0x21, 0xc7, 0x5f, 0x5f, 0x5c, 0xf1, 0xe4, 0xa6, 0x79, 0xd5, 0x03, 0x13, 0x7c, 0xe3, 0xc7, 0xff, + 0xf5, 0xeb, 0x9f, 0x67, 0xe6, 0x71, 0xa5, 0x35, 0xf9, 0x76, 0xeb, 0x7c, 0xd2, 0x62, 0x61, 0xea, + 0xb1, 0xf6, 0x10, 0x7d, 0x02, 0xd9, 0x83, 0xb1, 0x87, 0x52, 0x9f, 0xe2, 0x34, 0xd3, 0xdf, 0x9c, + 0xe0, 0x25, 0x26, 0x74, 0x0e, 0x83, 0x10, 0x3a, 0x1a, 0x7b, 0x54, 0xe4, 0x0f, 0xa1, 0xac, 0xbe, + 0x18, 0xb9, 0xf6, 0x7d, 0x4e, 0xf3, 0xfa, 0xd7, 0x28, 0xf8, 0x0e, 0x83, 0xba, 0x81, 0x91, 0x80, + 0xe2, 0x6f, 0x5a, 0xd4, 0x5e, 0x74, 0x2f, 0x2c, 0x94, 0xfa, 0x7a, 0xa7, 0x99, 0xfe, 0x40, 0x25, + 0xd6, 0x0b, 0xef, 0xc2, 0xa2, 0x22, 0xff, 0x44, 0xbc, 0x4d, 0xe9, 0x79, 0xe8, 0x6e, 0xc2, 0xdb, + 0x04, 0xf5, 0x16, 0xbe, 0xb9, 0x9a, 0xce, 0x20, 0x40, 0x6e, 0x33, 0x90, 0x65, 0x3c, 0x2f, 0x40, + 0x7a, 0x3e, 0xcb, 0x63, 0xed, 0xe1, 0x46, 0x0f, 0x72, 0xec, 0x86, 0x0b, 0x7d, 0x21, 0x3f, 0x9a, + 0x09, 0x57, 0x7d, 0x29, 0x03, 0x1d, 0xba, 0x1b, 0xc3, 0x8b, 0x0c, 0xa8, 0x86, 0x4b, 0x14, 0x88, + 0xdd, 0x6f, 0x3d, 0xd6, 0x1e, 0xae, 0x69, 0x1f, 0x68, 0x1b, 0xbf, 0xca, 0x41, 0x8e, 0xa5, 0x76, + 0xd1, 0x39, 0x40, 0x70, 0xdb, 0x13, 0xed, 0x5d, 0xec, 0xfe, 0x28, 0xda, 0xbb, 0xf8, 0x45, 0x11, + 0x6e, 0x32, 0xd0, 0x45, 0x3c, 0x47, 0x41, 0x59, 0xc6, 0xb8, 0xc5, 0x92, 0xe0, 0xd4, 0x8e, 0x7f, + 0xa3, 0x89, 0xcc, 0x36, 0x5f, 0x4b, 0x28, 0x49, 0x5a, 0xe8, 0xca, 0x27, 0x3a, 0x1d, 0x12, 0xae, + 0x7b, 0xf0, 0x77, 0x19, 0x60, 0x0b, 0xd7, 0x03, 0x40, 0x87, 0x71, 0x3c, 0xd6, 0x1e, 0x7e, 0xd1, + 0xc0, 0x0b, 0xc2, 0xca, 0x91, 0x1a, 0xf4, 0x23, 0xa8, 0x85, 0xaf, 0x34, 0xd0, 0xbd, 0x04, 0xac, + 0xe8, 0xcd, 0x48, 0xf3, 0xed, 0xab, 0x99, 0x84, 0x4e, 0x2b, 0x4c, 0x27, 0x01, 0xce, 0x91, 0xcf, + 0x09, 0x19, 0x19, 0x94, 0x49, 0x8c, 0x01, 0xfa, 0x07, 0x4d, 0xdc, 0x38, 0x05, 0x77, 0x14, 0x28, + 0x49, 0x7a, 0xec, 0x06, 0xa4, 0x79, 0xff, 0x1a, 0x2e, 0xa1, 0xc4, 0x1f, 0x32, 0x25, 0x3e, 0xc4, + 0x8b, 0x81, 0x12, 0x9e, 0x39, 0x24, 0x9e, 0x2d, 0xb4, 0xf8, 0xe2, 0x36, 0xbe, 0x11, 0x32, 0x4e, + 0xa8, 0x36, 0x18, 0x2c, 0x7e, 0xcf, 0x90, 0x38, 0x58, 0xa1, 0x7b, 0x8b, 0xc4, 0xc1, 0x0a, 0x5f, + 0x52, 0x24, 0x0d, 0x16, 0xbf, 0x55, 0x48, 0x1a, 0x2c, 0xbf, 0x66, 0xe3, 0xff, 0x66, 0xa1, 0xb0, + 0xc9, 0xdf, 0x84, 0x23, 0x1b, 0x4a, 0x7e, 0x9a, 0x1e, 0xad, 0x24, 0xe5, 0x19, 0x83, 0x63, 0x4d, + 0xf3, 0x6e, 0x6a, 0xbd, 0x50, 0xe8, 0x2d, 0xa6, 0xd0, 0x2d, 0xbc, 0x4c, 0x91, 0xc5, 0xb3, 0xf3, + 0x16, 0x4f, 0x66, 0xb5, 0x8c, 0x7e, 0x9f, 0x1a, 0xe2, 0x4f, 0xa1, 0xa2, 0xe6, 0xd1, 0xd1, 0x5b, + 0x89, 0xb9, 0x4d, 0x35, 0x15, 0xdf, 0xc4, 0x57, 0xb1, 0x08, 0xe4, 0xb7, 0x19, 0xf2, 0x0a, 0xbe, + 0x99, 0x80, 0xec, 0x30, 0xd6, 0x10, 0x38, 0xcf, 0x81, 0x27, 0x83, 0x87, 0x52, 0xec, 0xc9, 0xe0, + 0xe1, 0x14, 0xfa, 0x95, 0xe0, 0x63, 0xc6, 0x4a, 0xc1, 0x5d, 0x80, 0x20, 0x93, 0x8d, 0x12, 0x6d, + 0xa9, 0x9c, 0xeb, 0xa2, 0xce, 0x21, 0x9e, 0x04, 0xc7, 0x98, 0xc1, 0x8a, 0x79, 0x17, 0x81, 0x1d, + 0x98, 0xae, 0xc7, 0x17, 0x66, 0x35, 0x94, 0x9a, 0x46, 0x89, 0xfd, 0x09, 0xe7, 0xb7, 0x9b, 0xf7, + 0xae, 0xe4, 0x11, 0xe8, 0xf7, 0x19, 0xfa, 0x5d, 0xdc, 0x4c, 0x40, 0x1f, 0x71, 0x5e, 0x3a, 0xd9, + 0xfe, 0x3f, 0x0f, 0xe5, 0xe7, 0x86, 0x69, 0x79, 0xc4, 0x32, 0xac, 0x1e, 0x41, 0xc7, 0x90, 0x63, + 0x91, 0x3a, 0xea, 0x88, 0xd5, 0xb4, 0x6d, 0xd4, 0x11, 0x87, 0x72, 0x9a, 0x78, 0x95, 0x01, 0x37, + 0xf1, 0x12, 0x05, 0x1e, 0x06, 0xa2, 0x5b, 0x2c, 0x15, 0x49, 0x3b, 0x7d, 0x02, 0x79, 0x71, 0xdb, + 0x17, 0x11, 0x14, 0x4a, 0xfe, 0x34, 0x6f, 0x27, 0x57, 0x26, 0xcd, 0x65, 0x15, 0xc6, 0x65, 0x7c, + 0x14, 0x67, 0x02, 0x10, 0xe4, 0xd8, 0xa3, 0x23, 0x1a, 0x4b, 0xc9, 0x37, 0x57, 0xd3, 0x19, 0x92, + 0x6c, 0xaa, 0x62, 0xf6, 0x7d, 0x5e, 0x8a, 0xfb, 0xc7, 0x30, 0xfb, 0xcc, 0x70, 0xcf, 0x50, 0x24, + 0xf6, 0x2a, 0x6f, 0xc5, 0x9a, 0xcd, 0xa4, 0x2a, 0x81, 0x72, 0x97, 0xa1, 0xdc, 0xe4, 0xae, 0x4c, + 0x45, 0x39, 0x33, 0x5c, 0x1a, 0xd4, 0x50, 0x1f, 0xf2, 0xfc, 0xe9, 0x58, 0xd4, 0x7e, 0xa1, 0xe7, + 0x67, 0x51, 0xfb, 0x85, 0x5f, 0x9b, 0x5d, 0x8f, 0x32, 0x82, 0xa2, 0x7c, 0xab, 0x85, 0x22, 0x17, + 0xf7, 0x91, 0x77, 0x5d, 0xcd, 0x95, 0xb4, 0x6a, 0x81, 0x75, 0x8f, 0x61, 0xdd, 0xc1, 0x8d, 0xd8, + 0x58, 0x09, 0xce, 0xc7, 0xda, 0xc3, 0x0f, 0x34, 0xf4, 0x23, 0x80, 0xe0, 0x5a, 0x22, 0xb6, 0x02, + 0xa3, 0x37, 0x1c, 0xb1, 0x15, 0x18, 0xbb, 0xd1, 0xc0, 0xeb, 0x0c, 0x77, 0x0d, 0xdf, 0x8b, 0xe2, + 0x7a, 0x8e, 0x61, 0xb9, 0x27, 0xc4, 0x79, 0x9f, 0x67, 0x59, 0xdd, 0x33, 0x73, 0x44, 0xbb, 0xec, + 0x40, 0xc9, 0xcf, 0x3a, 0x47, 0xbd, 0x6d, 0x34, 0x1b, 0x1e, 0xf5, 0xb6, 0xb1, 0x74, 0x75, 0xd8, + 0xed, 0x84, 0x66, 0x8b, 0x64, 0xa5, 0x0b, 0xf0, 0x17, 0x75, 0x98, 0xa5, 0xbb, 0x6e, 0xba, 0x39, + 0x09, 0xf2, 0x26, 0xd1, 0xde, 0xc7, 0xb2, 0xa8, 0xd1, 0xde, 0xc7, 0x53, 0x2e, 0xe1, 0xcd, 0x09, + 0xfb, 0x05, 0x13, 0x4f, 0x51, 0xd0, 0x9e, 0xda, 0x50, 0x56, 0x12, 0x2b, 0x28, 0x41, 0x58, 0x38, + 0x3d, 0x1b, 0x0d, 0x77, 0x09, 0x59, 0x19, 0x7c, 0x8b, 0xe1, 0x2d, 0xf1, 0x70, 0xc7, 0xf0, 0xfa, + 0x9c, 0x83, 0x02, 0x8a, 0xde, 0x89, 0x75, 0x9f, 0xd0, 0xbb, 0xf0, 0xda, 0x5f, 0x4d, 0x67, 0x48, + 0xed, 0x5d, 0xb0, 0xf0, 0x5f, 0x41, 0x45, 0x4d, 0xaf, 0xa0, 0x04, 0xe5, 0x23, 0x29, 0xe5, 0x68, + 0x1c, 0x49, 0xca, 0xce, 0x84, 0x3d, 0x9b, 0xff, 0x93, 0x30, 0xc9, 0x46, 0x81, 0x07, 0x50, 0x10, + 0xf9, 0x96, 0x24, 0x93, 0x86, 0xd3, 0xcf, 0x49, 0x26, 0x8d, 0x24, 0x6b, 0xc2, 0xbb, 0x67, 0x86, + 0x48, 0x8f, 0x94, 0x32, 0x56, 0x0b, 0xb4, 0xa7, 0xc4, 0x4b, 0x43, 0x0b, 0x32, 0x99, 0x69, 0x68, + 0xca, 0x71, 0x3e, 0x0d, 0xed, 0x94, 0x78, 0xc2, 0x1f, 0xc8, 0x63, 0x32, 0x4a, 0x11, 0xa6, 0xc6, + 0x47, 0x7c, 0x15, 0x4b, 0xd2, 0xe1, 0x26, 0x00, 0x94, 0xc1, 0xf1, 0x02, 0x20, 0xc8, 0x06, 0x45, + 0x77, 0xac, 0x89, 0x59, 0xf0, 0xe8, 0x8e, 0x35, 0x39, 0xa1, 0x14, 0xf6, 0x7d, 0x01, 0x2e, 0x3f, + 0x5b, 0x51, 0xe4, 0x9f, 0x69, 0x80, 0xe2, 0x89, 0x23, 0xf4, 0x28, 0x59, 0x7a, 0x62, 0x6e, 0xbd, + 0xf9, 0xde, 0xeb, 0x31, 0x27, 0x85, 0xb3, 0x40, 0xa5, 0x1e, 0xe3, 0x1e, 0xbd, 0xa2, 0x4a, 0xfd, + 0xa5, 0x06, 0xd5, 0x50, 0xd6, 0x09, 0x3d, 0x48, 0x19, 0xd3, 0x48, 0xca, 0xbd, 0xf9, 0xce, 0xb5, + 0x7c, 0x49, 0x5b, 0x79, 0x65, 0x06, 0xc8, 0x33, 0xcd, 0x4f, 0x34, 0xa8, 0x85, 0xb3, 0x54, 0x28, + 0x45, 0x76, 0x2c, 0x65, 0xdf, 0x5c, 0xbb, 0x9e, 0xf1, 0xea, 0xe1, 0x09, 0x8e, 0x33, 0x03, 0x28, + 0x88, 0xbc, 0x56, 0xd2, 0xc4, 0x0f, 0x27, 0xfb, 0x93, 0x26, 0x7e, 0x24, 0x29, 0x96, 0x30, 0xf1, + 0x1d, 0x7b, 0x40, 0x94, 0x65, 0x26, 0x12, 0x5f, 0x69, 0x68, 0x57, 0x2f, 0xb3, 0x48, 0xd6, 0x2c, + 0x0d, 0x2d, 0x58, 0x66, 0x32, 0xe3, 0x85, 0x52, 0x84, 0x5d, 0xb3, 0xcc, 0xa2, 0x09, 0xb3, 0x84, + 0x65, 0xc6, 0x00, 0x95, 0x65, 0x16, 0xe4, 0xa6, 0x92, 0x96, 0x59, 0xec, 0xee, 0x22, 0x69, 0x99, + 0xc5, 0xd3, 0x5b, 0x09, 0xe3, 0xc8, 0x70, 0x43, 0xcb, 0x6c, 0x21, 0x21, 0x8d, 0x85, 0xde, 0x4b, + 0x31, 0x62, 0xe2, 0x95, 0x48, 0xf3, 0xfd, 0xd7, 0xe4, 0x4e, 0x9d, 0xe3, 0xdc, 0xfc, 0x72, 0x8e, + 0xff, 0xad, 0x06, 0x8b, 0x49, 0x29, 0x30, 0x94, 0x82, 0x93, 0x72, 0x95, 0xd2, 0x5c, 0x7f, 0x5d, + 0xf6, 0xab, 0xad, 0xe5, 0xcf, 0xfa, 0x27, 0xf5, 0x7f, 0xfd, 0x6a, 0x45, 0xfb, 0x8f, 0xaf, 0x56, + 0xb4, 0xff, 0xfe, 0x6a, 0x45, 0xfb, 0xbb, 0xff, 0x59, 0x99, 0x39, 0xce, 0xb3, 0x1f, 0x1a, 0x7f, + 0xfb, 0x37, 0x01, 0x00, 0x00, 0xff, 0xff, 0x7a, 0xd4, 0x63, 0xa4, 0xef, 0x3c, 0x00, 0x00, } diff --git a/etcdserver/etcdserverpb/rpc.proto b/etcdserver/etcdserverpb/rpc.proto index f670c471b..1c27bafae 100644 --- a/etcdserver/etcdserverpb/rpc.proto +++ b/etcdserver/etcdserverpb/rpc.proto @@ -1050,6 +1050,7 @@ message AuthUserAddRequest { string name = 1; string password = 2; authpb.UserAddOptions options = 3; + string hashedPassword = 4; } message AuthUserGetRequest { @@ -1064,8 +1065,10 @@ message AuthUserDeleteRequest { message AuthUserChangePasswordRequest { // name is the name of the user whose password is being changed. string name = 1; - // password is the new password for the user. + // password is the new password for the user. Note that this field will be removed in the API layer. string password = 2; + // hashedPassword is the new password for the user. Note that this field will be initialized in the API layer. + string hashedPassword = 3; } message AuthUserGrantRoleRequest { diff --git a/etcdserver/v3_server.go b/etcdserver/v3_server.go index b580f4334..e96f9660d 100644 --- a/etcdserver/v3_server.go +++ b/etcdserver/v3_server.go @@ -17,6 +17,7 @@ package etcdserver import ( "bytes" "context" + "encoding/base64" "encoding/binary" "time" @@ -32,6 +33,7 @@ import ( "github.com/gogo/protobuf/proto" "go.uber.org/zap" + "golang.org/x/crypto/bcrypt" ) const ( @@ -464,6 +466,15 @@ func (s *EtcdServer) Authenticate(ctx context.Context, r *pb.AuthenticateRequest } func (s *EtcdServer) UserAdd(ctx context.Context, r *pb.AuthUserAddRequest) (*pb.AuthUserAddResponse, error) { + if r.Options == nil || !r.Options.NoPassword { + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(r.Password), s.authStore.BcryptCost()) + if err != nil { + return nil, err + } + r.HashedPassword = base64.StdEncoding.EncodeToString(hashedPassword) + r.Password = "" + } + resp, err := s.raftRequest(ctx, pb.InternalRaftRequest{AuthUserAdd: r}) if err != nil { return nil, err @@ -480,6 +491,15 @@ func (s *EtcdServer) UserDelete(ctx context.Context, r *pb.AuthUserDeleteRequest } func (s *EtcdServer) UserChangePassword(ctx context.Context, r *pb.AuthUserChangePasswordRequest) (*pb.AuthUserChangePasswordResponse, error) { + if r.Password != "" { + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(r.Password), s.authStore.BcryptCost()) + if err != nil { + return nil, err + } + r.HashedPassword = base64.StdEncoding.EncodeToString(hashedPassword) + r.Password = "" + } + resp, err := s.raftRequest(ctx, pb.InternalRaftRequest{AuthUserChangePassword: r}) if err != nil { return nil, err