From 6366b2da2012ac3bbdd897f8555a28e7af78b101 Mon Sep 17 00:00:00 2001 From: Radu Berinde Date: Fri, 30 Jul 2021 13:18:42 -0700 Subject: [PATCH 1/3] sql: add tenant_usage system table Add the system table described in the RFC (#66436). The table is only created for the system tenant. Release note: None --- .../settings/settings-for-tenants.txt | 2 +- docs/generated/settings/settings.html | 2 +- pkg/ccl/backupccl/system_schema.go | 3 + pkg/cli/testdata/doctor/test_examine_cluster | 2 +- pkg/cli/testdata/zip/partial1 | 9 +- pkg/cli/testdata/zip/partial1_excluded | 9 +- pkg/cli/testdata/zip/partial2 | 9 +- pkg/cli/testdata/zip/specialnames | 3 +- pkg/cli/testdata/zip/testzip | 6 +- pkg/cli/testdata/zip/testzip_concurrent | 25 +++- pkg/clusterversion/cockroach_versions.go | 6 + pkg/clusterversion/key_string.go | 5 +- pkg/keys/constants.go | 1 + pkg/migration/migrations/BUILD.bazel | 1 + pkg/migration/migrations/migrations.go | 5 + pkg/migration/migrations/tenant_usage.go | 32 +++++ pkg/sql/catalog/bootstrap/metadata.go | 4 + pkg/sql/catalog/descpb/privilege.go | 1 + pkg/sql/catalog/systemschema/system.go | 134 +++++++++++++++++- .../logictest/testdata/logic_test/grant_table | 15 ++ .../testdata/logic_test/information_schema | 47 ++++++ .../logictest/testdata/logic_test/pg_catalog | 3 + pkg/sql/logictest/testdata/logic_test/ranges | 6 +- .../logictest/testdata/logic_test/show_source | 2 + pkg/sql/logictest/testdata/logic_test/system | 12 ++ .../testdata/logic_test/system_namespace | 1 + .../testdata/autocommit_nonmetamorphic | 118 +++++++-------- pkg/sql/opt/exec/execbuilder/testdata/delete | 6 +- .../testdata/show_trace_nonmetamorphic | 24 ++-- pkg/sql/pgwire/pgwire_test.go | 2 +- pkg/sql/tests/system_table_test.go | 1 + pkg/sql/tests/testdata/initial_keys | 7 +- 32 files changed, 402 insertions(+), 101 deletions(-) create mode 100644 pkg/migration/migrations/tenant_usage.go diff --git a/docs/generated/settings/settings-for-tenants.txt b/docs/generated/settings/settings-for-tenants.txt index d051be575d07..fa94521e72e2 100644 --- a/docs/generated/settings/settings-for-tenants.txt +++ b/docs/generated/settings/settings-for-tenants.txt @@ -144,4 +144,4 @@ trace.datadog.project string CockroachDB the project under which traces will be trace.debug.enable boolean false if set, traces for recent requests can be seen at https:///debug/requests trace.lightstep.token string if set, traces go to Lightstep using this token trace.zipkin.collector string if set, traces go to the given Zipkin instance (example: '127.0.0.1:9411'). Only one tracer can be configured at a time. -version version 21.1-118 set the active cluster version in the format '.' +version version 21.1-120 set the active cluster version in the format '.' diff --git a/docs/generated/settings/settings.html b/docs/generated/settings/settings.html index 485517fef82c..dcb646366245 100644 --- a/docs/generated/settings/settings.html +++ b/docs/generated/settings/settings.html @@ -148,6 +148,6 @@ trace.debug.enablebooleanfalseif set, traces for recent requests can be seen at https:///debug/requests trace.lightstep.tokenstringif set, traces go to Lightstep using this token trace.zipkin.collectorstringif set, traces go to the given Zipkin instance (example: '127.0.0.1:9411'). Only one tracer can be configured at a time. -versionversion21.1-118set the active cluster version in the format '.' +versionversion21.1-120set the active cluster version in the format '.' diff --git a/pkg/ccl/backupccl/system_schema.go b/pkg/ccl/backupccl/system_schema.go index baa3880569f6..8680e30dbbbe 100644 --- a/pkg/ccl/backupccl/system_schema.go +++ b/pkg/ccl/backupccl/system_schema.go @@ -346,6 +346,9 @@ var systemTableBackupConfiguration = map[string]systemBackupConfiguration{ systemschema.DatabaseRoleSettingsTable.GetName(): { shouldIncludeInClusterBackup: optInToClusterBackup, }, + systemschema.TenantUsageTable.GetName(): { + shouldIncludeInClusterBackup: optOutOfClusterBackup, + }, } // GetSystemTablesToIncludeInClusterBackup returns a set of system table names that diff --git a/pkg/cli/testdata/doctor/test_examine_cluster b/pkg/cli/testdata/doctor/test_examine_cluster index 8cadb5ccbcf1..c61d66b54006 100644 --- a/pkg/cli/testdata/doctor/test_examine_cluster +++ b/pkg/cli/testdata/doctor/test_examine_cluster @@ -1,7 +1,7 @@ debug doctor examine cluster ---- debug doctor examine cluster -Examining 38 descriptors and 39 namespace entries... +Examining 39 descriptors and 40 namespace entries... ParentID 50, ParentSchemaID 29: relation "foo" (53): expected matching namespace entry, found none Examining 3 jobs... ERROR: validation failed diff --git a/pkg/cli/testdata/zip/partial1 b/pkg/cli/testdata/zip/partial1 index 85ce79df3a98..90036423f077 100644 --- a/pkg/cli/testdata/zip/partial1 +++ b/pkg/cli/testdata/zip/partial1 @@ -66,7 +66,7 @@ debug zip --concurrency=1 --cpu-profile-duration=0s /dev/null [node 1] 1 log file ... [node 1] [log file ... [node 1] requesting ranges... received response... done -[node 1] 40 ranges found +[node 1] 41 ranges found [node 1] writing range 1... converting to JSON... writing binary output: debug/nodes/1/ranges/1.json... done [node 1] writing range 2... converting to JSON... writing binary output: debug/nodes/1/ranges/2.json... done [node 1] writing range 3... converting to JSON... writing binary output: debug/nodes/1/ranges/3.json... done @@ -107,6 +107,7 @@ debug zip --concurrency=1 --cpu-profile-duration=0s /dev/null [node 1] writing range 38... converting to JSON... writing binary output: debug/nodes/1/ranges/38.json... done [node 1] writing range 39... converting to JSON... writing binary output: debug/nodes/1/ranges/39.json... done [node 1] writing range 40... converting to JSON... writing binary output: debug/nodes/1/ranges/40.json... done +[node 1] writing range 41... converting to JSON... writing binary output: debug/nodes/1/ranges/41.json... done [node 2] node status... converting to JSON... writing binary output: debug/nodes/2/status.json... done [node 2] using SQL connection URL: postgresql://... [node 2] retrieving SQL data for crdb_internal.feature_usage... writing output: debug/nodes/2/crdb_internal.feature_usage.txt... @@ -225,7 +226,7 @@ debug zip --concurrency=1 --cpu-profile-duration=0s /dev/null [node 3] 1 log file ... [node 3] [log file ... [node 3] requesting ranges... received response... done -[node 3] 40 ranges found +[node 3] 41 ranges found [node 3] writing range 1... converting to JSON... writing binary output: debug/nodes/3/ranges/1.json... done [node 3] writing range 2... converting to JSON... writing binary output: debug/nodes/3/ranges/2.json... done [node 3] writing range 3... converting to JSON... writing binary output: debug/nodes/3/ranges/3.json... done @@ -266,6 +267,7 @@ debug zip --concurrency=1 --cpu-profile-duration=0s /dev/null [node 3] writing range 38... converting to JSON... writing binary output: debug/nodes/3/ranges/38.json... done [node 3] writing range 39... converting to JSON... writing binary output: debug/nodes/3/ranges/39.json... done [node 3] writing range 40... converting to JSON... writing binary output: debug/nodes/3/ranges/40.json... done +[node 3] writing range 41... converting to JSON... writing binary output: debug/nodes/3/ranges/41.json... done [cluster] doctor examining cluster...... writing binary output: debug/reports/doctor.txt... done [cluster] requesting list of SQL databases... received response... done [cluster] 3 databases found @@ -274,7 +276,7 @@ debug zip --concurrency=1 --cpu-profile-duration=0s /dev/null [cluster] [database: postgres] requesting database details... received response... converting to JSON... writing binary output: debug/schema/postgres@details.json... done [cluster] [database: postgres] 0 tables found [cluster] [database: system] requesting database details... received response... converting to JSON... writing binary output: debug/schema/system@details.json... done -[cluster] [database: system] 33 tables found +[cluster] [database: system] 34 tables found [cluster] [database: system] [table: public.comments] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_comments.json... done [cluster] [database: system] [table: public.database_role_settings] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_database_role_settings.json... done [cluster] [database: system] [table: public.descriptor] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_descriptor.json... done @@ -302,6 +304,7 @@ debug zip --concurrency=1 --cpu-profile-duration=0s /dev/null [cluster] [database: system] [table: public.statement_diagnostics_requests] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_statement_diagnostics_requests.json... done [cluster] [database: system] [table: public.statement_statistics] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_statement_statistics.json... done [cluster] [database: system] [table: public.table_statistics] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_table_statistics.json... done +[cluster] [database: system] [table: public.tenant_usage] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_tenant_usage.json... done [cluster] [database: system] [table: public.tenants] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_tenants.json... done [cluster] [database: system] [table: public.transaction_statistics] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_transaction_statistics.json... done [cluster] [database: system] [table: public.ui] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_ui.json... done diff --git a/pkg/cli/testdata/zip/partial1_excluded b/pkg/cli/testdata/zip/partial1_excluded index c8081f6f253c..34d1bcf664d8 100644 --- a/pkg/cli/testdata/zip/partial1_excluded +++ b/pkg/cli/testdata/zip/partial1_excluded @@ -66,7 +66,7 @@ debug zip /dev/null --concurrency=1 --exclude-nodes=2 --cpu-profile-duration=0 [node 1] 1 log file ... [node 1] [log file ... [node 1] requesting ranges... received response... done -[node 1] 40 ranges found +[node 1] 41 ranges found [node 1] writing range 1... converting to JSON... writing binary output: debug/nodes/1/ranges/1.json... done [node 1] writing range 2... converting to JSON... writing binary output: debug/nodes/1/ranges/2.json... done [node 1] writing range 3... converting to JSON... writing binary output: debug/nodes/1/ranges/3.json... done @@ -107,6 +107,7 @@ debug zip /dev/null --concurrency=1 --exclude-nodes=2 --cpu-profile-duration=0 [node 1] writing range 38... converting to JSON... writing binary output: debug/nodes/1/ranges/38.json... done [node 1] writing range 39... converting to JSON... writing binary output: debug/nodes/1/ranges/39.json... done [node 1] writing range 40... converting to JSON... writing binary output: debug/nodes/1/ranges/40.json... done +[node 1] writing range 41... converting to JSON... writing binary output: debug/nodes/1/ranges/41.json... done [node 2] skipping node... writing binary output: debug/nodes/2.skipped... done [node 3] node status... converting to JSON... writing binary output: debug/nodes/3/status.json... done [node 3] using SQL connection URL: postgresql://... @@ -143,7 +144,7 @@ debug zip /dev/null --concurrency=1 --exclude-nodes=2 --cpu-profile-duration=0 [node 3] 1 log file ... [node 3] [log file ... [node 3] requesting ranges... received response... done -[node 3] 40 ranges found +[node 3] 41 ranges found [node 3] writing range 1... converting to JSON... writing binary output: debug/nodes/3/ranges/1.json... done [node 3] writing range 2... converting to JSON... writing binary output: debug/nodes/3/ranges/2.json... done [node 3] writing range 3... converting to JSON... writing binary output: debug/nodes/3/ranges/3.json... done @@ -184,6 +185,7 @@ debug zip /dev/null --concurrency=1 --exclude-nodes=2 --cpu-profile-duration=0 [node 3] writing range 38... converting to JSON... writing binary output: debug/nodes/3/ranges/38.json... done [node 3] writing range 39... converting to JSON... writing binary output: debug/nodes/3/ranges/39.json... done [node 3] writing range 40... converting to JSON... writing binary output: debug/nodes/3/ranges/40.json... done +[node 3] writing range 41... converting to JSON... writing binary output: debug/nodes/3/ranges/41.json... done [cluster] doctor examining cluster...... writing binary output: debug/reports/doctor.txt... done [cluster] requesting list of SQL databases... received response... done [cluster] 3 databases found @@ -192,7 +194,7 @@ debug zip /dev/null --concurrency=1 --exclude-nodes=2 --cpu-profile-duration=0 [cluster] [database: postgres] requesting database details... received response... converting to JSON... writing binary output: debug/schema/postgres@details.json... done [cluster] [database: postgres] 0 tables found [cluster] [database: system] requesting database details... received response... converting to JSON... writing binary output: debug/schema/system@details.json... done -[cluster] [database: system] 33 tables found +[cluster] [database: system] 34 tables found [cluster] [database: system] [table: public.comments] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_comments.json... done [cluster] [database: system] [table: public.database_role_settings] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_database_role_settings.json... done [cluster] [database: system] [table: public.descriptor] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_descriptor.json... done @@ -220,6 +222,7 @@ debug zip /dev/null --concurrency=1 --exclude-nodes=2 --cpu-profile-duration=0 [cluster] [database: system] [table: public.statement_diagnostics_requests] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_statement_diagnostics_requests.json... done [cluster] [database: system] [table: public.statement_statistics] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_statement_statistics.json... done [cluster] [database: system] [table: public.table_statistics] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_table_statistics.json... done +[cluster] [database: system] [table: public.tenant_usage] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_tenant_usage.json... done [cluster] [database: system] [table: public.tenants] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_tenants.json... done [cluster] [database: system] [table: public.transaction_statistics] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_transaction_statistics.json... done [cluster] [database: system] [table: public.ui] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_ui.json... done diff --git a/pkg/cli/testdata/zip/partial2 b/pkg/cli/testdata/zip/partial2 index 2b59dac7a74c..ddc1533ba0f5 100644 --- a/pkg/cli/testdata/zip/partial2 +++ b/pkg/cli/testdata/zip/partial2 @@ -66,7 +66,7 @@ debug zip --concurrency=1 --cpu-profile-duration=0 /dev/null [node 1] 1 log file ... [node 1] [log file ... [node 1] requesting ranges... received response... done -[node 1] 40 ranges found +[node 1] 41 ranges found [node 1] writing range 1... converting to JSON... writing binary output: debug/nodes/1/ranges/1.json... done [node 1] writing range 2... converting to JSON... writing binary output: debug/nodes/1/ranges/2.json... done [node 1] writing range 3... converting to JSON... writing binary output: debug/nodes/1/ranges/3.json... done @@ -107,6 +107,7 @@ debug zip --concurrency=1 --cpu-profile-duration=0 /dev/null [node 1] writing range 38... converting to JSON... writing binary output: debug/nodes/1/ranges/38.json... done [node 1] writing range 39... converting to JSON... writing binary output: debug/nodes/1/ranges/39.json... done [node 1] writing range 40... converting to JSON... writing binary output: debug/nodes/1/ranges/40.json... done +[node 1] writing range 41... converting to JSON... writing binary output: debug/nodes/1/ranges/41.json... done [node 3] node status... converting to JSON... writing binary output: debug/nodes/3/status.json... done [node 3] using SQL connection URL: postgresql://... [node 3] retrieving SQL data for crdb_internal.feature_usage... writing output: debug/nodes/3/crdb_internal.feature_usage.txt... done @@ -142,7 +143,7 @@ debug zip --concurrency=1 --cpu-profile-duration=0 /dev/null [node 3] 1 log file ... [node 3] [log file ... [node 3] requesting ranges... received response... done -[node 3] 40 ranges found +[node 3] 41 ranges found [node 3] writing range 1... converting to JSON... writing binary output: debug/nodes/3/ranges/1.json... done [node 3] writing range 2... converting to JSON... writing binary output: debug/nodes/3/ranges/2.json... done [node 3] writing range 3... converting to JSON... writing binary output: debug/nodes/3/ranges/3.json... done @@ -183,6 +184,7 @@ debug zip --concurrency=1 --cpu-profile-duration=0 /dev/null [node 3] writing range 38... converting to JSON... writing binary output: debug/nodes/3/ranges/38.json... done [node 3] writing range 39... converting to JSON... writing binary output: debug/nodes/3/ranges/39.json... done [node 3] writing range 40... converting to JSON... writing binary output: debug/nodes/3/ranges/40.json... done +[node 3] writing range 41... converting to JSON... writing binary output: debug/nodes/3/ranges/41.json... done [cluster] doctor examining cluster...... writing binary output: debug/reports/doctor.txt... done [cluster] requesting list of SQL databases... received response... done [cluster] 3 databases found @@ -191,7 +193,7 @@ debug zip --concurrency=1 --cpu-profile-duration=0 /dev/null [cluster] [database: postgres] requesting database details... received response... converting to JSON... writing binary output: debug/schema/postgres@details.json... done [cluster] [database: postgres] 0 tables found [cluster] [database: system] requesting database details... received response... converting to JSON... writing binary output: debug/schema/system@details.json... done -[cluster] [database: system] 33 tables found +[cluster] [database: system] 34 tables found [cluster] [database: system] [table: public.comments] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_comments.json... done [cluster] [database: system] [table: public.database_role_settings] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_database_role_settings.json... done [cluster] [database: system] [table: public.descriptor] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_descriptor.json... done @@ -219,6 +221,7 @@ debug zip --concurrency=1 --cpu-profile-duration=0 /dev/null [cluster] [database: system] [table: public.statement_diagnostics_requests] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_statement_diagnostics_requests.json... done [cluster] [database: system] [table: public.statement_statistics] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_statement_statistics.json... done [cluster] [database: system] [table: public.table_statistics] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_table_statistics.json... done +[cluster] [database: system] [table: public.tenant_usage] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_tenant_usage.json... done [cluster] [database: system] [table: public.tenants] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_tenants.json... done [cluster] [database: system] [table: public.transaction_statistics] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_transaction_statistics.json... done [cluster] [database: system] [table: public.ui] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_ui.json... done diff --git a/pkg/cli/testdata/zip/specialnames b/pkg/cli/testdata/zip/specialnames index 91bab7c75f95..a979be0655fb 100644 --- a/pkg/cli/testdata/zip/specialnames +++ b/pkg/cli/testdata/zip/specialnames @@ -23,7 +23,7 @@ zip [cluster] [database: postgres] requesting database details... received response... converting to JSON... writing binary output: debug/schema/postgres@details.json... done [cluster] [database: postgres] 0 tables found [cluster] [database: system] requesting database details... received response... converting to JSON... writing binary output: debug/schema/system-1@details.json... done -[cluster] [database: system] 33 tables found +[cluster] [database: system] 34 tables found [cluster] [database: system] [table: public.comments] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system-1/public_comments.json... done [cluster] [database: system] [table: public.database_role_settings] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system-1/public_database_role_settings.json... done [cluster] [database: system] [table: public.descriptor] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system-1/public_descriptor.json... done @@ -51,6 +51,7 @@ zip [cluster] [database: system] [table: public.statement_diagnostics_requests] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system-1/public_statement_diagnostics_requests.json... done [cluster] [database: system] [table: public.statement_statistics] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system-1/public_statement_statistics.json... done [cluster] [database: system] [table: public.table_statistics] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system-1/public_table_statistics.json... done +[cluster] [database: system] [table: public.tenant_usage] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system-1/public_tenant_usage.json... done [cluster] [database: system] [table: public.tenants] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system-1/public_tenants.json... done [cluster] [database: system] [table: public.transaction_statistics] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system-1/public_transaction_statistics.json... done [cluster] [database: system] [table: public.ui] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system-1/public_ui.json... done diff --git a/pkg/cli/testdata/zip/testzip b/pkg/cli/testdata/zip/testzip index fd9be93dab47..da5197f348b8 100644 --- a/pkg/cli/testdata/zip/testzip +++ b/pkg/cli/testdata/zip/testzip @@ -66,7 +66,7 @@ debug zip --concurrency=1 --cpu-profile-duration=1s /dev/null [node 1] requesting log file ... [node 1] 0 log file ... [node 1] requesting ranges... received response... done -[node 1] 40 ranges found +[node 1] 41 ranges found [node 1] writing range 1... converting to JSON... writing binary output: debug/nodes/1/ranges/1.json... done [node 1] writing range 2... converting to JSON... writing binary output: debug/nodes/1/ranges/2.json... done [node 1] writing range 3... converting to JSON... writing binary output: debug/nodes/1/ranges/3.json... done @@ -107,6 +107,7 @@ debug zip --concurrency=1 --cpu-profile-duration=1s /dev/null [node 1] writing range 38... converting to JSON... writing binary output: debug/nodes/1/ranges/38.json... done [node 1] writing range 39... converting to JSON... writing binary output: debug/nodes/1/ranges/39.json... done [node 1] writing range 40... converting to JSON... writing binary output: debug/nodes/1/ranges/40.json... done +[node 1] writing range 41... converting to JSON... writing binary output: debug/nodes/1/ranges/41.json... done [cluster] doctor examining cluster...... writing binary output: debug/reports/doctor.txt... done [cluster] requesting list of SQL databases... received response... done [cluster] 3 databases found @@ -115,7 +116,7 @@ debug zip --concurrency=1 --cpu-profile-duration=1s /dev/null [cluster] [database: postgres] requesting database details... received response... converting to JSON... writing binary output: debug/schema/postgres@details.json... done [cluster] [database: postgres] 0 tables found [cluster] [database: system] requesting database details... received response... converting to JSON... writing binary output: debug/schema/system@details.json... done -[cluster] [database: system] 33 tables found +[cluster] [database: system] 34 tables found [cluster] [database: system] [table: public.comments] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_comments.json... done [cluster] [database: system] [table: public.database_role_settings] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_database_role_settings.json... done [cluster] [database: system] [table: public.descriptor] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_descriptor.json... done @@ -143,6 +144,7 @@ debug zip --concurrency=1 --cpu-profile-duration=1s /dev/null [cluster] [database: system] [table: public.statement_diagnostics_requests] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_statement_diagnostics_requests.json... done [cluster] [database: system] [table: public.statement_statistics] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_statement_statistics.json... done [cluster] [database: system] [table: public.table_statistics] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_table_statistics.json... done +[cluster] [database: system] [table: public.tenant_usage] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_tenant_usage.json... done [cluster] [database: system] [table: public.tenants] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_tenants.json... done [cluster] [database: system] [table: public.transaction_statistics] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_transaction_statistics.json... done [cluster] [database: system] [table: public.ui] requesting table details... received response... converting to JSON... writing binary output: debug/schema/system/public_ui.json... done diff --git a/pkg/cli/testdata/zip/testzip_concurrent b/pkg/cli/testdata/zip/testzip_concurrent index 44e90a1a5e8d..6328465446fd 100644 --- a/pkg/cli/testdata/zip/testzip_concurrent +++ b/pkg/cli/testdata/zip/testzip_concurrent @@ -13,7 +13,7 @@ zip [cluster] [database: postgres] requesting database details: done [cluster] [database: postgres] requesting database details: received response... [cluster] [database: postgres] requesting database details: writing binary output: debug/schema/postgres@details.json... -[cluster] [database: system] 33 tables found +[cluster] [database: system] 34 tables found [cluster] [database: system] [table: public.comments] requesting table details... [cluster] [database: system] [table: public.comments] requesting table details: converting to JSON... [cluster] [database: system] [table: public.comments] requesting table details: done @@ -149,6 +149,11 @@ zip [cluster] [database: system] [table: public.table_statistics] requesting table details: done [cluster] [database: system] [table: public.table_statistics] requesting table details: received response... [cluster] [database: system] [table: public.table_statistics] requesting table details: writing binary output: debug/schema/system/public_table_statistics.json... +[cluster] [database: system] [table: public.tenant_usage] requesting table details... +[cluster] [database: system] [table: public.tenant_usage] requesting table details: converting to JSON... +[cluster] [database: system] [table: public.tenant_usage] requesting table details: done +[cluster] [database: system] [table: public.tenant_usage] requesting table details: received response... +[cluster] [database: system] [table: public.tenant_usage] requesting table details: writing binary output: debug/schema/system/public_tenant_usage.json... [cluster] [database: system] [table: public.tenants] requesting table details... [cluster] [database: system] [table: public.tenants] requesting table details: converting to JSON... [cluster] [database: system] [table: public.tenants] requesting table details: done @@ -296,7 +301,7 @@ zip [cluster] using SQL address: ... [cluster] using SQL address: ... [node 1] 1 log file ... -[node 1] 40 ranges found +[node 1] 41 ranges found [node 1] [log file ... [node 1] [log file ... [node 1] [log file ... @@ -536,6 +541,10 @@ zip [node 1] writing range 40: converting to JSON... [node 1] writing range 40: done [node 1] writing range 40: writing binary output: debug/nodes/1/ranges/40.json... +[node 1] writing range 41... +[node 1] writing range 41: converting to JSON... +[node 1] writing range 41: done +[node 1] writing range 41: writing binary output: debug/nodes/1/ranges/41.json... [node 1] writing range 4: converting to JSON... [node 1] writing range 4: done [node 1] writing range 4: writing binary output: debug/nodes/1/ranges/4.json... @@ -560,7 +569,7 @@ zip [node 1] writing range 9: done [node 1] writing range 9: writing binary output: debug/nodes/1/ranges/9.json... [node 2] 1 log file ... -[node 2] 40 ranges found +[node 2] 41 ranges found [node 2] [log file ... [node 2] [log file ... [node 2] [log file ... @@ -800,6 +809,10 @@ zip [node 2] writing range 40: converting to JSON... [node 2] writing range 40: done [node 2] writing range 40: writing binary output: debug/nodes/2/ranges/40.json... +[node 2] writing range 41... +[node 2] writing range 41: converting to JSON... +[node 2] writing range 41: done +[node 2] writing range 41: writing binary output: debug/nodes/2/ranges/41.json... [node 2] writing range 4: converting to JSON... [node 2] writing range 4: done [node 2] writing range 4: writing binary output: debug/nodes/2/ranges/4.json... @@ -824,7 +837,7 @@ zip [node 2] writing range 9: done [node 2] writing range 9: writing binary output: debug/nodes/2/ranges/9.json... [node 3] 1 log file ... -[node 3] 40 ranges found +[node 3] 41 ranges found [node 3] [log file ... [node 3] [log file ... [node 3] [log file ... @@ -1064,6 +1077,10 @@ zip [node 3] writing range 40: converting to JSON... [node 3] writing range 40: done [node 3] writing range 40: writing binary output: debug/nodes/3/ranges/40.json... +[node 3] writing range 41... +[node 3] writing range 41: converting to JSON... +[node 3] writing range 41: done +[node 3] writing range 41: writing binary output: debug/nodes/3/ranges/41.json... [node 3] writing range 4: converting to JSON... [node 3] writing range 4: done [node 3] writing range 4: writing binary output: debug/nodes/3/ranges/4.json... diff --git a/pkg/clusterversion/cockroach_versions.go b/pkg/clusterversion/cockroach_versions.go index 49771b3562a9..f63b46c1231b 100644 --- a/pkg/clusterversion/cockroach_versions.go +++ b/pkg/clusterversion/cockroach_versions.go @@ -264,6 +264,8 @@ const ( // DatabaseRoleSettings adds the system table for storing per-user and // per-role default session settings. DatabaseRoleSettings + // TenantUsageTable adds the system table for tracking tenant usage. + TenantUsageTable // Step (1): Add new versions here. ) @@ -421,6 +423,10 @@ var versionsSingleton = keyedVersions{ Key: DatabaseRoleSettings, Version: roachpb.Version{Major: 21, Minor: 1, Internal: 118}, }, + { + Key: TenantUsageTable, + Version: roachpb.Version{Major: 21, Minor: 1, Internal: 120}, + }, // Step (2): Add new versions here. } diff --git a/pkg/clusterversion/key_string.go b/pkg/clusterversion/key_string.go index 8d2fdc888409..42a0a34bf6d6 100644 --- a/pkg/clusterversion/key_string.go +++ b/pkg/clusterversion/key_string.go @@ -38,11 +38,12 @@ func _() { _ = x[FixDescriptors-27] _ = x[SQLStatsTable-28] _ = x[DatabaseRoleSettings-29] + _ = x[TenantUsageTable-30] } -const _Key_name = "Start20_2NodeMembershipStatusMinPasswordLengthAbortSpanBytesCreateLoginPrivilegeHBAForNonTLSV20_2Start21_1CPutInlineReplicaVersionsreplacedTruncatedAndRangeAppliedStateMigrationreplacedPostTruncatedAndRangeAppliedStateMigrationTruncatedAndRangeAppliedStateMigrationPostTruncatedAndRangeAppliedStateMigrationSeparatedIntentsTracingVerbosityIndependentSemanticsClosedTimestampsRaftTransportPriorReadSummariesNonVotingReplicasV21_1Start21_1PLUSStart21_2JoinTokensTableAcquisitionTypeInLeaseHistorySerializeViewUDTsExpressionIndexesDeleteDeprecatedNamespaceTableDescriptorMigrationFixDescriptorsSQLStatsTableDatabaseRoleSettings" +const _Key_name = "Start20_2NodeMembershipStatusMinPasswordLengthAbortSpanBytesCreateLoginPrivilegeHBAForNonTLSV20_2Start21_1CPutInlineReplicaVersionsreplacedTruncatedAndRangeAppliedStateMigrationreplacedPostTruncatedAndRangeAppliedStateMigrationTruncatedAndRangeAppliedStateMigrationPostTruncatedAndRangeAppliedStateMigrationSeparatedIntentsTracingVerbosityIndependentSemanticsClosedTimestampsRaftTransportPriorReadSummariesNonVotingReplicasV21_1Start21_1PLUSStart21_2JoinTokensTableAcquisitionTypeInLeaseHistorySerializeViewUDTsExpressionIndexesDeleteDeprecatedNamespaceTableDescriptorMigrationFixDescriptorsSQLStatsTableDatabaseRoleSettingsTenantUsageTable" -var _Key_index = [...]uint16{0, 9, 29, 46, 60, 80, 92, 97, 106, 116, 131, 177, 227, 265, 307, 323, 359, 388, 406, 423, 428, 441, 450, 465, 494, 511, 528, 577, 591, 604, 624} +var _Key_index = [...]uint16{0, 9, 29, 46, 60, 80, 92, 97, 106, 116, 131, 177, 227, 265, 307, 323, 359, 388, 406, 423, 428, 441, 450, 465, 494, 511, 528, 577, 591, 604, 624, 640} func (i Key) String() string { if i < 0 || i >= Key(len(_Key_index)-1) { diff --git a/pkg/keys/constants.go b/pkg/keys/constants.go index a747f914e239..177e85eba05a 100644 --- a/pkg/keys/constants.go +++ b/pkg/keys/constants.go @@ -408,6 +408,7 @@ const ( StatementStatisticsTableID = 42 TransactionStatisticsTableID = 43 DatabaseRoleSettingsTableID = 44 + TenantUsageTableID = 45 // CommentType is type for system.comments DatabaseCommentType = 0 diff --git a/pkg/migration/migrations/BUILD.bazel b/pkg/migration/migrations/BUILD.bazel index ce51026c597e..cf58c748ac10 100644 --- a/pkg/migration/migrations/BUILD.bazel +++ b/pkg/migration/migrations/BUILD.bazel @@ -9,6 +9,7 @@ go_library( "join_tokens.go", "migrations.go", "sql_stats.go", + "tenant_usage.go", "truncated_state.go", ], importpath = "github.com/cockroachdb/cockroach/pkg/migration/migrations", diff --git a/pkg/migration/migrations/migrations.go b/pkg/migration/migrations/migrations.go index 640eaed8cfd2..a8adc5ae9bfa 100644 --- a/pkg/migration/migrations/migrations.go +++ b/pkg/migration/migrations/migrations.go @@ -72,6 +72,11 @@ var migrations = []migration.Migration{ toCV(clusterversion.DatabaseRoleSettings), databaseRoleSettingsTableMigration, ), + migration.NewTenantMigration( + "add the systems.tenant_usage table", + toCV(clusterversion.TenantUsageTable), + tenantUsageTableMigration, + ), } func init() { diff --git a/pkg/migration/migrations/tenant_usage.go b/pkg/migration/migrations/tenant_usage.go new file mode 100644 index 000000000000..63ce883e5592 --- /dev/null +++ b/pkg/migration/migrations/tenant_usage.go @@ -0,0 +1,32 @@ +// Copyright 2021 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package migrations + +import ( + "context" + + "github.com/cockroachdb/cockroach/pkg/clusterversion" + "github.com/cockroachdb/cockroach/pkg/migration" + "github.com/cockroachdb/cockroach/pkg/sql/catalog/systemschema" + "github.com/cockroachdb/cockroach/pkg/startupmigrations" +) + +func tenantUsageTableMigration( + ctx context.Context, _ clusterversion.ClusterVersion, d migration.TenantDeps, +) error { + // Only create the table on the system tenant. + if !d.Codec.ForSystemTenant() { + return nil + } + return startupmigrations.CreateSystemTable( + ctx, d.DB, d.Codec, d.Settings, systemschema.TenantUsageTable, + ) +} diff --git a/pkg/sql/catalog/bootstrap/metadata.go b/pkg/sql/catalog/bootstrap/metadata.go index 9839e9057cc9..eeec3f00394e 100644 --- a/pkg/sql/catalog/bootstrap/metadata.go +++ b/pkg/sql/catalog/bootstrap/metadata.go @@ -328,6 +328,10 @@ func addSystemDescriptorsToSchema(target *MetadataSchema) { target.AddDescriptor(keys.SystemDatabaseID, systemschema.StatementStatisticsTable) target.AddDescriptor(keys.SystemDatabaseID, systemschema.TransactionStatisticsTable) target.AddDescriptor(keys.SystemDatabaseID, systemschema.DatabaseRoleSettingsTable) + + if target.codec.ForSystemTenant() { + target.AddDescriptor(keys.SystemDatabaseID, systemschema.TenantUsageTable) + } } // addSplitIDs adds a split point for each of the PseudoTableIDs to the supplied diff --git a/pkg/sql/catalog/descpb/privilege.go b/pkg/sql/catalog/descpb/privilege.go index 5c2091b93b92..c1f27a7bc131 100644 --- a/pkg/sql/catalog/descpb/privilege.go +++ b/pkg/sql/catalog/descpb/privilege.go @@ -560,6 +560,7 @@ var SystemAllowedPrivileges = map[ID]privilege.List{ keys.StatementStatisticsTableID: privilege.ReadData, keys.TransactionStatisticsTableID: privilege.ReadData, keys.DatabaseRoleSettingsTableID: privilege.ReadWriteData, + keys.TenantUsageTableID: privilege.ReadWriteData, } // SetOwner sets the owner of the privilege descriptor to the provided string. diff --git a/pkg/sql/catalog/systemschema/system.go b/pkg/sql/catalog/systemschema/system.go index 319387f3ae3c..7ec6bc07a947 100644 --- a/pkg/sql/catalog/systemschema/system.go +++ b/pkg/sql/catalog/systemschema/system.go @@ -450,6 +450,75 @@ CREATE TABLE system.database_role_settings ( settings ) );` + + TenantUsageTableSchema = ` +CREATE TABLE system.tenant_usage ( + tenant_id INT NOT NULL, + + -- For each tenant, there is a special row with instance_id = 0 which contains + -- per-tenant stat. Each SQL instance (pod) also has its own row with + -- per-instance state. + instance_id INT NOT NULL, + + -- next_instance_id identifies the next live instance ID, with the smallest ID + -- larger than this instance_id (or 0 if there is no such ID). + -- We are overlaying a circular linked list of all live instances, with + -- instance 0 acting as a sentinel (always the head of the list). + next_instance_id INT NOT NULL, + + -- ------------------------------------------------------------------- + -- The following fields are used only for the per-tenant state, when + -- instance_id = 0. + -- ------------------------------------------------------------------- + + -- Bucket configuration. + ru_burst_limit FLOAT, + ru_refill_rate FLOAT, + + -- Current amount of RUs in the bucket. + ru_current FLOAT, + + -- Current sum of the shares values for all instances. + current_share_sum FLOAT, + + -- Cumulative usage statistics. + total_ru_usage FLOAT, + total_read_requests INT, + total_read_bytes INT, + total_write_requests INT, + total_write_bytes INT, + total_sql_pod_cpu_seconds FLOAT, -- TODO: Maybe milliseconds and INT8? + + -- ------------------------------------------------------------- + -- The following fields are used for per-instance state, when + -- instance_id != 0. + -- -------------------------------------------------------------- + + -- The lease is a unique identifier for this instance, necessary because + -- instance IDs can be reused. + instance_lease BYTES, + + -- Last request sequence number. These numbers are provided by the + -- instance and are monotonically increasing; used to detect duplicate + -- requests and provide idempotency. + instance_seq INT, + + -- Current shares value for this instance. + instance_shares FLOAT, + + -- Time when we last heard from this instance. + instance_last_update TIMESTAMP, + + FAMILY "primary" ( + tenant_id, instance_id, next_instance_id, + ru_burst_limit, ru_refill_rate, ru_current, current_share_sum, + total_ru_usage, total_read_requests, total_read_bytes, total_write_requests, + total_write_bytes, total_sql_pod_cpu_seconds, + instance_lease, instance_seq, instance_shares, instance_last_update + ), + + PRIMARY KEY (tenant_id, instance_id) +)` ) func pk(name string) descpb.IndexDescriptor { @@ -531,7 +600,7 @@ var ( {Name: "primary", ID: 0, ColumnNames: []string{"parentID", "parentSchemaID", "name"}, ColumnIDs: []descpb.ColumnID{1, 2, 3}}, {Name: "fam_4_id", ID: catconstants.NamespaceTableFamilyID, ColumnNames: []string{"id"}, ColumnIDs: []descpb.ColumnID{4}, DefaultColumnID: 4}, }, - NextFamilyID: 5, + NextFamilyID: catconstants.NamespaceTableFamilyID + 1, PrimaryIndex: descpb.IndexDescriptor{ Name: "primary", ID: catconstants.NamespaceTablePrimaryIndexID, @@ -2113,6 +2182,69 @@ var ( FormatVersion: descpb.InterleavedFormatVersion, NextMutationID: 1, }) + // TenantUsageTable is the descriptor for the tenant_usage table. It is used + // to coordinate throttling of tenant SQL pods and to track consumption. + TenantUsageTable = makeTable(descpb.TableDescriptor{ + Name: "tenant_usage", + ID: keys.TenantUsageTableID, + ParentID: keys.SystemDatabaseID, + UnexposedParentSchemaID: keys.PublicSchemaID, + Version: 1, + Columns: []descpb.ColumnDescriptor{ + {Name: "tenant_id", ID: 1, Type: types.Int, Nullable: false}, + {Name: "instance_id", ID: 2, Type: types.Int, Nullable: false}, + {Name: "next_instance_id", ID: 3, Type: types.Int, Nullable: false}, + {Name: "ru_burst_limit", ID: 4, Type: types.Float, Nullable: true}, + {Name: "ru_refill_rate", ID: 5, Type: types.Float, Nullable: true}, + {Name: "ru_current", ID: 6, Type: types.Float, Nullable: true}, + {Name: "current_share_sum", ID: 7, Type: types.Float, Nullable: true}, + {Name: "total_ru_usage", ID: 8, Type: types.Float, Nullable: true}, + {Name: "total_read_requests", ID: 9, Type: types.Int, Nullable: true}, + {Name: "total_read_bytes", ID: 10, Type: types.Int, Nullable: true}, + {Name: "total_write_requests", ID: 11, Type: types.Int, Nullable: true}, + {Name: "total_write_bytes", ID: 12, Type: types.Int, Nullable: true}, + {Name: "total_sql_pod_cpu_seconds", ID: 13, Type: types.Float, Nullable: true}, + {Name: "instance_lease", ID: 14, Type: types.Bytes, Nullable: true}, + {Name: "instance_seq", ID: 15, Type: types.Int, Nullable: true}, + {Name: "instance_shares", ID: 16, Type: types.Float, Nullable: true}, + {Name: "instance_last_update", ID: 17, Type: types.Timestamp, Nullable: true}, + }, + NextColumnID: 18, + Families: []descpb.ColumnFamilyDescriptor{ + { + Name: "primary", + ID: 0, + ColumnNames: []string{ + "tenant_id", "instance_id", "next_instance_id", + "ru_burst_limit", "ru_refill_rate", "ru_current", "current_share_sum", + "total_ru_usage", "total_read_requests", "total_read_bytes", "total_write_requests", + "total_write_bytes", "total_sql_pod_cpu_seconds", + "instance_lease", "instance_seq", "instance_shares", "instance_last_update", + }, + ColumnIDs: []descpb.ColumnID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, + DefaultColumnID: 0, + }, + }, + NextFamilyID: 1, + PrimaryIndex: descpb.IndexDescriptor{ + Name: tabledesc.PrimaryKeyIndexName, + ID: 1, + Unique: true, + KeyColumnNames: []string{"tenant_id", "instance_id"}, + KeyColumnDirections: []descpb.IndexDescriptor_Direction{ + descpb.IndexDescriptor_ASC, + descpb.IndexDescriptor_ASC, + }, + KeyColumnIDs: []descpb.ColumnID{1, 2}, + Version: descpb.StrictIndexColumnIDGuaranteesVersion, + }, + NextIndexID: 2, + Privileges: descpb.NewCustomSuperuserPrivilegeDescriptor( + descpb.SystemAllowedPrivileges[keys.TenantUsageTableID], security.NodeUserName(), + ), + FormatVersion: descpb.InterleavedFormatVersion, + NextMutationID: 1, + }) ) // newCommentPrivilegeDescriptor returns a privilege descriptor for comment table diff --git a/pkg/sql/logictest/testdata/logic_test/grant_table b/pkg/sql/logictest/testdata/logic_test/grant_table index 403aa5788e80..5b234e04c3a4 100644 --- a/pkg/sql/logictest/testdata/logic_test/grant_table +++ b/pkg/sql/logictest/testdata/logic_test/grant_table @@ -912,6 +912,16 @@ system public join_tokens root GRANT system public join_tokens root INSERT system public join_tokens root SELECT system public join_tokens root UPDATE +system public tenant_usage admin DELETE +system public tenant_usage admin GRANT +system public tenant_usage admin INSERT +system public tenant_usage admin SELECT +system public tenant_usage admin UPDATE +system public tenant_usage root DELETE +system public tenant_usage root GRANT +system public tenant_usage root INSERT +system public tenant_usage root SELECT +system public tenant_usage root UPDATE system public statement_statistics admin GRANT system public statement_statistics admin SELECT system public statement_statistics root GRANT @@ -1411,6 +1421,11 @@ system public table_statistics root GRA system public table_statistics root INSERT system public table_statistics root SELECT system public table_statistics root UPDATE +system public tenant_usage root DELETE +system public tenant_usage root GRANT +system public tenant_usage root INSERT +system public tenant_usage root SELECT +system public tenant_usage root UPDATE system public tenants root GRANT system public tenants root SELECT system public transaction_statistics root GRANT diff --git a/pkg/sql/logictest/testdata/logic_test/information_schema b/pkg/sql/logictest/testdata/logic_test/information_schema index 863061ceaff0..e8248aed93eb 100644 --- a/pkg/sql/logictest/testdata/logic_test/information_schema +++ b/pkg/sql/logictest/testdata/logic_test/information_schema @@ -1347,6 +1347,7 @@ system public join_tokens BASE T system public statement_statistics BASE TABLE YES 1 system public transaction_statistics BASE TABLE YES 1 system public database_role_settings BASE TABLE YES 1 +system public tenant_usage BASE TABLE YES 1 statement ok ALTER TABLE other_db.xyz ADD COLUMN j INT @@ -1549,6 +1550,10 @@ system public 630200280_20_6_not_null system public 630200280_20_7_not_null system public table_statistics CHECK NO NO system public 630200280_20_8_not_null system public table_statistics CHECK NO NO system public primary system public table_statistics PRIMARY KEY NO NO +system public 630200280_45_1_not_null system public tenant_usage CHECK NO NO +system public 630200280_45_2_not_null system public tenant_usage CHECK NO NO +system public 630200280_45_3_not_null system public tenant_usage CHECK NO NO +system public primary system public tenant_usage PRIMARY KEY NO NO system public 630200280_8_1_not_null system public tenants CHECK NO NO system public 630200280_8_2_not_null system public tenants CHECK NO NO system public primary system public tenants PRIMARY KEY NO NO @@ -1724,6 +1729,9 @@ system public 630200280_43_8_not_null system public 630200280_44_1_not_null database_id IS NOT NULL system public 630200280_44_2_not_null role_name IS NOT NULL system public 630200280_44_3_not_null settings IS NOT NULL +system public 630200280_45_1_not_null tenant_id IS NOT NULL +system public 630200280_45_2_not_null instance_id IS NOT NULL +system public 630200280_45_3_not_null next_instance_id IS NOT NULL system public 630200280_4_1_not_null username IS NOT NULL system public 630200280_4_3_not_null isRole IS NOT NULL system public 630200280_5_1_not_null id IS NOT NULL @@ -1799,6 +1807,8 @@ system public statement_statistics node_id system public statement_statistics plan_hash system public primary system public table_statistics statisticID system public primary system public table_statistics tableID system public primary +system public tenant_usage instance_id system public primary +system public tenant_usage tenant_id system public primary system public tenants id system public primary system public transaction_statistics aggregated_ts system public primary system public transaction_statistics app_name system public primary @@ -2054,6 +2064,23 @@ system public table_statistics nullCount system public table_statistics rowCount 6 system public table_statistics statisticID 2 system public table_statistics tableID 1 +system public tenant_usage current_share_sum 7 +system public tenant_usage instance_id 2 +system public tenant_usage instance_last_update 17 +system public tenant_usage instance_lease 14 +system public tenant_usage instance_seq 15 +system public tenant_usage instance_shares 16 +system public tenant_usage next_instance_id 3 +system public tenant_usage ru_burst_limit 4 +system public tenant_usage ru_current 6 +system public tenant_usage ru_refill_rate 5 +system public tenant_usage tenant_id 1 +system public tenant_usage total_read_bytes 10 +system public tenant_usage total_read_requests 9 +system public tenant_usage total_ru_usage 8 +system public tenant_usage total_sql_pod_cpu_seconds 13 +system public tenant_usage total_write_bytes 12 +system public tenant_usage total_write_requests 11 system public tenants active 2 system public tenants id 1 system public tenants info 3 @@ -3055,6 +3082,16 @@ NULL root system public table_statistics NULL root system public table_statistics INSERT NULL NO NULL root system public table_statistics SELECT NULL YES NULL root system public table_statistics UPDATE NULL NO +NULL admin system public tenant_usage DELETE NULL NO +NULL admin system public tenant_usage GRANT NULL NO +NULL admin system public tenant_usage INSERT NULL NO +NULL admin system public tenant_usage SELECT NULL YES +NULL admin system public tenant_usage UPDATE NULL NO +NULL root system public tenant_usage DELETE NULL NO +NULL root system public tenant_usage GRANT NULL NO +NULL root system public tenant_usage INSERT NULL NO +NULL root system public tenant_usage SELECT NULL YES +NULL root system public tenant_usage UPDATE NULL NO NULL admin system public tenants GRANT NULL NO NULL admin system public tenants SELECT NULL YES NULL root system public tenants GRANT NULL NO @@ -3668,6 +3705,16 @@ NULL root system public database_role_settings NULL root system public database_role_settings INSERT NULL NO NULL root system public database_role_settings SELECT NULL YES NULL root system public database_role_settings UPDATE NULL NO +NULL admin system public tenant_usage DELETE NULL NO +NULL admin system public tenant_usage GRANT NULL NO +NULL admin system public tenant_usage INSERT NULL NO +NULL admin system public tenant_usage SELECT NULL YES +NULL admin system public tenant_usage UPDATE NULL NO +NULL root system public tenant_usage DELETE NULL NO +NULL root system public tenant_usage GRANT NULL NO +NULL root system public tenant_usage INSERT NULL NO +NULL root system public tenant_usage SELECT NULL YES +NULL root system public tenant_usage UPDATE NULL NO statement ok CREATE TABLE other_db.xyz (i INT) diff --git a/pkg/sql/logictest/testdata/logic_test/pg_catalog b/pkg/sql/logictest/testdata/logic_test/pg_catalog index 440aeeca9e6e..0bb9275b747c 100644 --- a/pkg/sql/logictest/testdata/logic_test/pg_catalog +++ b/pkg/sql/logictest/testdata/logic_test/pg_catalog @@ -1053,6 +1053,7 @@ indexrelid indrelid indnatts indisunique indisprimary indisexclusion indim 3752917847 27 2 true true false true false true false false true false 1 2 0 0 0 0 2 2 NULL NULL 2 3966258450 14 1 true true false true false true false false true false 1 3403232968 0 2 NULL NULL 1 4012654114 30 3 true true false true false true false false true false 1 2 3 0 0 3403232968 0 0 0 2 2 2 NULL NULL 3 +4133203393 45 2 true true false true false true false false true false 1 2 0 0 0 0 2 2 NULL NULL 2 4225994721 13 2 true true false true false true false false true false 1 7 0 0 0 0 2 2 NULL NULL 2 # From #26504 @@ -1145,6 +1146,8 @@ indexrelid operator_argument_type_oid operator_argument_position 4012654114 0 1 4012654114 0 2 4012654114 0 3 +4133203393 0 1 +4133203393 0 2 4225994721 0 1 4225994721 0 2 diff --git a/pkg/sql/logictest/testdata/logic_test/ranges b/pkg/sql/logictest/testdata/logic_test/ranges index a2da624e9d47..58627d6147f5 100644 --- a/pkg/sql/logictest/testdata/logic_test/ranges +++ b/pkg/sql/logictest/testdata/logic_test/ranges @@ -314,7 +314,8 @@ start_key start_pretty end_key [177] /Table/41 [178] /Table/42 system join_tokens · {1} 1 [178] /Table/42 [179] /Table/43 system statement_statistics · {1} 1 [179] /Table/43 [180] /Table/44 system transaction_statistics · {1} 1 -[180] /Table/44 [189 137] /Table/53/1 system database_role_settings · {1} 1 +[180] /Table/44 [181] /Table/45 system database_role_settings · {1} 1 +[181] /Table/45 [189 137] /Table/53/1 system tenant_usage · {1} 1 [189 137] /Table/53/1 [189 137 137] /Table/53/1/1 test t · {1} 1 [189 137 137] /Table/53/1/1 [189 137 141 137] /Table/53/1/5/1 test t · {3,4} 3 [189 137 141 137] /Table/53/1/5/1 [189 137 141 138] /Table/53/1/5/2 test t · {1,2,3} 1 @@ -377,7 +378,8 @@ start_key start_pretty end_key [177] /Table/41 [178] /Table/42 system join_tokens · {1} 1 [178] /Table/42 [179] /Table/43 system statement_statistics · {1} 1 [179] /Table/43 [180] /Table/44 system transaction_statistics · {1} 1 -[180] /Table/44 [189 137] /Table/53/1 system database_role_settings · {1} 1 +[180] /Table/44 [181] /Table/45 system database_role_settings · {1} 1 +[181] /Table/45 [189 137] /Table/53/1 system tenant_usage · {1} 1 [189 137] /Table/53/1 [189 137 137] /Table/53/1/1 test t · {1} 1 [189 137 137] /Table/53/1/1 [189 137 141 137] /Table/53/1/5/1 test t · {3,4} 3 [189 137 141 137] /Table/53/1/5/1 [189 137 141 138] /Table/53/1/5/2 test t · {1,2,3} 1 diff --git a/pkg/sql/logictest/testdata/logic_test/show_source b/pkg/sql/logictest/testdata/logic_test/show_source index 1ad62a3b9185..3c244b033dc5 100644 --- a/pkg/sql/logictest/testdata/logic_test/show_source +++ b/pkg/sql/logictest/testdata/logic_test/show_source @@ -206,6 +206,7 @@ SELECT * FROM [SHOW TABLES FROM system] ---- schema_name table_name type owner estimated_row_count locality public descriptor table NULL 0 NULL +public tenant_usage table NULL 0 NULL public database_role_settings table NULL 0 NULL public transaction_statistics table NULL 0 NULL public statement_statistics table NULL 0 NULL @@ -244,6 +245,7 @@ SELECT * FROM [SHOW TABLES FROM system WITH COMMENT] ---- schema_name table_name type owner estimated_row_count locality comment public descriptor table NULL 0 NULL · +public tenant_usage table NULL 0 NULL · public database_role_settings table NULL 0 NULL · public transaction_statistics table NULL 0 NULL · public statement_statistics table NULL 0 NULL · diff --git a/pkg/sql/logictest/testdata/logic_test/system b/pkg/sql/logictest/testdata/logic_test/system index 7d9da72541c8..a1355bacab53 100644 --- a/pkg/sql/logictest/testdata/logic_test/system +++ b/pkg/sql/logictest/testdata/logic_test/system @@ -37,6 +37,7 @@ public statement_diagnostics table NULL 0 NULL public statement_diagnostics_requests table NULL 0 NULL public statement_statistics table NULL 0 NULL public table_statistics table NULL 0 NULL +public tenant_usage table NULL 0 NULL public tenants table NULL 0 NULL public transaction_statistics table NULL 0 NULL public ui table NULL 0 NULL @@ -81,6 +82,7 @@ SELECT id FROM system.descriptor 42 43 44 +45 50 51 52 @@ -440,6 +442,16 @@ system public table_statistics root GRANT system public table_statistics root INSERT system public table_statistics root SELECT system public table_statistics root UPDATE +system public tenant_usage admin DELETE +system public tenant_usage admin GRANT +system public tenant_usage admin INSERT +system public tenant_usage admin SELECT +system public tenant_usage admin UPDATE +system public tenant_usage root DELETE +system public tenant_usage root GRANT +system public tenant_usage root INSERT +system public tenant_usage root SELECT +system public tenant_usage root UPDATE system public tenants admin GRANT system public tenants admin SELECT system public tenants root GRANT diff --git a/pkg/sql/logictest/testdata/logic_test/system_namespace b/pkg/sql/logictest/testdata/logic_test/system_namespace index 8ce993eb61fc..76904b2027d9 100644 --- a/pkg/sql/logictest/testdata/logic_test/system_namespace +++ b/pkg/sql/logictest/testdata/logic_test/system_namespace @@ -39,6 +39,7 @@ SELECT * FROM system.namespace 1 29 statement_diagnostics_requests 35 1 29 statement_statistics 42 1 29 table_statistics 20 +1 29 tenant_usage 45 1 29 tenants 8 1 29 transaction_statistics 43 1 29 ui 14 diff --git a/pkg/sql/opt/exec/execbuilder/testdata/autocommit_nonmetamorphic b/pkg/sql/opt/exec/execbuilder/testdata/autocommit_nonmetamorphic index 07bde0f6aa75..804fe1208e83 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/autocommit_nonmetamorphic +++ b/pkg/sql/opt/exec/execbuilder/testdata/autocommit_nonmetamorphic @@ -41,7 +41,7 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r40: sending batch 1 CPut, 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 1 CPut, 1 EndTxn to (n1,s1):1 # Multi-row insert should auto-commit. query B @@ -62,7 +62,7 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r40: sending batch 2 CPut, 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 2 CPut, 1 EndTxn to (n1,s1):1 # No auto-commit inside a transaction. statement ok @@ -86,7 +86,7 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r40: sending batch 2 CPut to (n1,s1):1 +dist sender send r41: sending batch 2 CPut to (n1,s1):1 statement ok ROLLBACK @@ -110,7 +110,7 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r40: sending batch 2 CPut, 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 2 CPut, 1 EndTxn to (n1,s1):1 # TODO(radu): allow non-side-effecting projections. query B @@ -132,8 +132,8 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%QueryTxn%' AND operation NOT LIKE '%async%' ---- -dist sender send r40: sending batch 2 CPut to (n1,s1):1 -dist sender send r40: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 2 CPut to (n1,s1):1 +dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 # Insert with RETURNING statement with side-effects should not auto-commit. # In this case division can (in principle) error out. @@ -156,8 +156,8 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%QueryTxn%' AND operation NOT LIKE '%async%' ---- -dist sender send r40: sending batch 2 CPut to (n1,s1):1 -dist sender send r40: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 2 CPut to (n1,s1):1 +dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 # Another way to test the scenario above: generate an error and ensure that the # mutation was not committed. @@ -192,7 +192,7 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r40: sending batch 1 Put, 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 1 Put, 1 EndTxn to (n1,s1):1 # Multi-row upsert should auto-commit. query B @@ -213,7 +213,7 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r40: sending batch 2 Put, 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 2 Put, 1 EndTxn to (n1,s1):1 # No auto-commit inside a transaction. statement ok @@ -237,7 +237,7 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r40: sending batch 2 Put to (n1,s1):1 +dist sender send r41: sending batch 2 Put to (n1,s1):1 statement ok ROLLBACK @@ -261,7 +261,7 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r40: sending batch 2 Put, 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 2 Put, 1 EndTxn to (n1,s1):1 # TODO(radu): allow non-side-effecting projections. query B @@ -283,8 +283,8 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%QueryTxn%' AND operation NOT LIKE '%async%' ---- -dist sender send r40: sending batch 2 Put to (n1,s1):1 -dist sender send r40: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 2 Put to (n1,s1):1 +dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 # Upsert with RETURNING statement with side-effects should not auto-commit. # In this case division can (in principle) error out. @@ -307,8 +307,8 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%QueryTxn%' AND operation NOT LIKE '%async%' ---- -dist sender send r40: sending batch 2 Put to (n1,s1):1 -dist sender send r40: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 2 Put to (n1,s1):1 +dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 # Another way to test the scenario above: generate an error and ensure that the # mutation was not committed. @@ -343,8 +343,8 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r40: sending batch 1 Scan to (n1,s1):1 -dist sender send r40: sending batch 2 Put, 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 1 Scan to (n1,s1):1 +dist sender send r41: sending batch 2 Put, 1 EndTxn to (n1,s1):1 # No auto-commit inside a transaction. statement ok @@ -368,8 +368,8 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r40: sending batch 1 Scan to (n1,s1):1 -dist sender send r40: sending batch 2 Put to (n1,s1):1 +dist sender send r41: sending batch 1 Scan to (n1,s1):1 +dist sender send r41: sending batch 2 Put to (n1,s1):1 statement ok ROLLBACK @@ -393,8 +393,8 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r40: sending batch 1 Scan to (n1,s1):1 -dist sender send r40: sending batch 2 Put, 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 1 Scan to (n1,s1):1 +dist sender send r41: sending batch 2 Put, 1 EndTxn to (n1,s1):1 # TODO(radu): allow non-side-effecting projections. query B @@ -416,9 +416,9 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%QueryTxn%' AND operation NOT LIKE '%async%' ---- -dist sender send r40: sending batch 1 Scan to (n1,s1):1 -dist sender send r40: sending batch 2 Put to (n1,s1):1 -dist sender send r40: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 1 Scan to (n1,s1):1 +dist sender send r41: sending batch 2 Put to (n1,s1):1 +dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 # Update with RETURNING statement with side-effects should not auto-commit. # In this case division can (in principle) error out. @@ -441,9 +441,9 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%QueryTxn%' AND operation NOT LIKE '%async%' ---- -dist sender send r40: sending batch 1 Scan to (n1,s1):1 -dist sender send r40: sending batch 2 Put to (n1,s1):1 -dist sender send r40: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 1 Scan to (n1,s1):1 +dist sender send r41: sending batch 2 Put to (n1,s1):1 +dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 # Another way to test the scenario above: generate an error and ensure that the # mutation was not committed. @@ -478,7 +478,7 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r40: sending batch 1 DelRng, 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 1 DelRng, 1 EndTxn to (n1,s1):1 # Multi-row delete should auto-commit. query B @@ -499,7 +499,7 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r40: sending batch 1 DelRng, 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 1 DelRng, 1 EndTxn to (n1,s1):1 # No auto-commit inside a transaction. statement ok @@ -523,7 +523,7 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r40: sending batch 1 DelRng to (n1,s1):1 +dist sender send r41: sending batch 1 DelRng to (n1,s1):1 statement ok ROLLBACK @@ -547,8 +547,8 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r40: sending batch 1 Scan to (n1,s1):1 -dist sender send r40: sending batch 2 Del, 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 1 Scan to (n1,s1):1 +dist sender send r41: sending batch 2 Del, 1 EndTxn to (n1,s1):1 # TODO(radu): allow non-side-effecting projections. query B @@ -570,9 +570,9 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%QueryTxn%' AND operation NOT LIKE '%async%' ---- -dist sender send r40: sending batch 1 Scan to (n1,s1):1 -dist sender send r40: sending batch 2 Del to (n1,s1):1 -dist sender send r40: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 1 Scan to (n1,s1):1 +dist sender send r41: sending batch 2 Del to (n1,s1):1 +dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 # Insert with RETURNING statement with side-effects should not auto-commit. # In this case division can (in principle) error out. @@ -595,9 +595,9 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%QueryTxn%' AND operation NOT LIKE '%async%' ---- -dist sender send r40: sending batch 1 Scan to (n1,s1):1 -dist sender send r40: sending batch 2 Del to (n1,s1):1 -dist sender send r40: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 1 Scan to (n1,s1):1 +dist sender send r41: sending batch 2 Del to (n1,s1):1 +dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 statement ok INSERT INTO ab VALUES (12, 0); @@ -644,9 +644,9 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%QueryTxn%' AND operation NOT LIKE '%async%' ---- -dist sender send r40: sending batch 2 CPut to (n1,s1):1 -dist sender send r40: sending batch 2 Get to (n1,s1):1 -dist sender send r40: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 2 CPut to (n1,s1):1 +dist sender send r41: sending batch 2 Get to (n1,s1):1 +dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 query B SELECT count(*) > 0 FROM [ @@ -667,10 +667,10 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%QueryTxn%' AND operation NOT LIKE '%async%' ---- -dist sender send r40: sending batch 1 Scan to (n1,s1):1 -dist sender send r40: sending batch 1 Put to (n1,s1):1 -dist sender send r40: sending batch 1 Scan to (n1,s1):1 -dist sender send r40: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 1 Scan to (n1,s1):1 +dist sender send r41: sending batch 1 Put to (n1,s1):1 +dist sender send r41: sending batch 1 Scan to (n1,s1):1 +dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 query B SELECT count(*) > 0 FROM [ @@ -692,10 +692,10 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%QueryTxn%' AND operation NOT LIKE '%async%' ---- -dist sender send r40: sending batch 1 Get to (n1,s1):1 -dist sender send r40: sending batch 1 Del to (n1,s1):1 -dist sender send r40: sending batch 1 Scan to (n1,s1):1 -dist sender send r40: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 1 Get to (n1,s1):1 +dist sender send r41: sending batch 1 Del to (n1,s1):1 +dist sender send r41: sending batch 1 Scan to (n1,s1):1 +dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 # Test with a single cascade, which should use autocommit. statement ok @@ -719,9 +719,9 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%QueryTxn%' AND operation NOT LIKE '%async%' ---- -dist sender send r40: sending batch 1 DelRng to (n1,s1):1 -dist sender send r40: sending batch 1 Scan to (n1,s1):1 -dist sender send r40: sending batch 1 Del, 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 1 DelRng to (n1,s1):1 +dist sender send r41: sending batch 1 Scan to (n1,s1):1 +dist sender send r41: sending batch 1 Del, 1 EndTxn to (n1,s1):1 # ----------------------- # Multiple mutation tests @@ -749,9 +749,9 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%QueryTxn%' AND operation NOT LIKE '%async%' ---- -dist sender send r40: sending batch 2 CPut to (n1,s1):1 -dist sender send r40: sending batch 2 CPut to (n1,s1):1 -dist sender send r40: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 2 CPut to (n1,s1):1 +dist sender send r41: sending batch 2 CPut to (n1,s1):1 +dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 query B SELECT count(*) > 0 FROM [ @@ -774,6 +774,6 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%QueryTxn%' AND operation NOT LIKE '%async%' ---- -dist sender send r40: sending batch 2 CPut to (n1,s1):1 -dist sender send r40: sending batch 2 CPut to (n1,s1):1 -dist sender send r40: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 2 CPut to (n1,s1):1 +dist sender send r41: sending batch 2 CPut to (n1,s1):1 +dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 diff --git a/pkg/sql/opt/exec/execbuilder/testdata/delete b/pkg/sql/opt/exec/execbuilder/testdata/delete index ba9c146cea33..8a13ad74d631 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/delete +++ b/pkg/sql/opt/exec/execbuilder/testdata/delete @@ -231,9 +231,9 @@ SELECT operation, message FROM [SHOW KV TRACE FOR SESSION] WHERE message LIKE '%DelRange%' OR message LIKE '%DelRng%' ---- batch flow coordinator DelRange /Table/57/1 - /Table/57/2 -dist sender send r40: sending batch 1 DelRng to (n1,s1):1 +dist sender send r41: sending batch 1 DelRng to (n1,s1):1 batch flow coordinator DelRange /Table/57/1/601/0 - /Table/57/2 -dist sender send r40: sending batch 1 DelRng to (n1,s1):1 +dist sender send r41: sending batch 1 DelRng to (n1,s1):1 # Ensure that DelRange requests are autocommitted when DELETE FROM happens on a # chunk of fewer than 600 keys. @@ -249,7 +249,7 @@ SELECT operation, message FROM [SHOW KV TRACE FOR SESSION] WHERE message LIKE '%DelRange%' OR message LIKE '%sending batch%' ---- batch flow coordinator DelRange /Table/57/1/5 - /Table/57/1/5/# -dist sender send r40: sending batch 1 DelRng, 1 EndTxn to (n1,s1):1 +dist sender send r41: sending batch 1 DelRng, 1 EndTxn to (n1,s1):1 # Test use of fast path when there are interleaved tables. diff --git a/pkg/sql/opt/exec/execbuilder/testdata/show_trace_nonmetamorphic b/pkg/sql/opt/exec/execbuilder/testdata/show_trace_nonmetamorphic index 5d4ff63fa2d8..ec0a1460a750 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/show_trace_nonmetamorphic +++ b/pkg/sql/opt/exec/execbuilder/testdata/show_trace_nonmetamorphic @@ -238,7 +238,7 @@ SET tracing = on; INSERT INTO t.kv3 (k, v) VALUES (1,1); SET tracing = off query T SELECT message FROM [SHOW TRACE FOR SESSION] WHERE message LIKE e'%1 CPut, 1 EndTxn%' AND message NOT LIKE e'%proposing command%' ---- -r41: sending batch 1 CPut, 1 EndTxn to (n1,s1):1 +r42: sending batch 1 CPut, 1 EndTxn to (n1,s1):1 node received request: 1 CPut, 1 EndTxn # Check that we can run set tracing regardless of the current tracing state. @@ -314,9 +314,9 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r41: sending batch 1 CPut to (n1,s1):1 -dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 -dist sender send r41: sending batch 2 CPut, 1 EndTxn to (n1,s1):1 +dist sender send r42: sending batch 1 CPut to (n1,s1):1 +dist sender send r42: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r42: sending batch 2 CPut, 1 EndTxn to (n1,s1):1 # Make another session trace. statement ok @@ -345,9 +345,9 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r41: sending batch 4 CPut, 1 EndTxn to (n1,s1):1 -dist sender send r41: sending batch 5 CPut to (n1,s1):1 -dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r42: sending batch 4 CPut, 1 EndTxn to (n1,s1):1 +dist sender send r42: sending batch 5 CPut to (n1,s1):1 +dist sender send r42: sending batch 1 EndTxn to (n1,s1):1 # make a table with some big strings in it. statement ok @@ -366,8 +366,8 @@ WHERE message LIKE '%r$rangeid: sending batch%' AND message NOT LIKE '%PushTxn%' AND message NOT LIKE '%QueryTxn%' ---- -dist sender send r41: sending batch 6 CPut to (n1,s1):1 -dist sender send r41: sending batch 6 CPut to (n1,s1):1 -dist sender send r41: sending batch 6 CPut to (n1,s1):1 -dist sender send r41: sending batch 6 CPut to (n1,s1):1 -dist sender send r41: sending batch 1 EndTxn to (n1,s1):1 +dist sender send r42: sending batch 6 CPut to (n1,s1):1 +dist sender send r42: sending batch 6 CPut to (n1,s1):1 +dist sender send r42: sending batch 6 CPut to (n1,s1):1 +dist sender send r42: sending batch 6 CPut to (n1,s1):1 +dist sender send r42: sending batch 1 EndTxn to (n1,s1):1 diff --git a/pkg/sql/pgwire/pgwire_test.go b/pkg/sql/pgwire/pgwire_test.go index 6208c10fe5ea..662a7c6ab8b2 100644 --- a/pkg/sql/pgwire/pgwire_test.go +++ b/pkg/sql/pgwire/pgwire_test.go @@ -561,7 +561,7 @@ func TestPGPreparedQuery(t *testing.T) { Results("users", "primary", false, 3, "isRole", "N/A", true, false), }}, {"SHOW TABLES FROM system", []preparedQueryTest{ - baseTest.Results("public", "comments", "table", gosql.NullString{}, 0, gosql.NullString{}).Others(32), + baseTest.Results("public", "comments", "table", gosql.NullString{}, 0, gosql.NullString{}).Others(33), }}, {"SHOW SCHEMAS FROM system", []preparedQueryTest{ baseTest.Results("crdb_internal", gosql.NullString{}).Others(4), diff --git a/pkg/sql/tests/system_table_test.go b/pkg/sql/tests/system_table_test.go index 424280af097e..03652c947e68 100644 --- a/pkg/sql/tests/system_table_test.go +++ b/pkg/sql/tests/system_table_test.go @@ -195,6 +195,7 @@ func TestSystemTableLiterals(t *testing.T) { {keys.StatementStatisticsTableID, systemschema.StatementStatisticsTableSchema, systemschema.StatementStatisticsTable}, {keys.TransactionStatisticsTableID, systemschema.TransactionStatisticsTableSchema, systemschema.TransactionStatisticsTable}, {keys.DatabaseRoleSettingsTableID, systemschema.DatabaseRoleSettingsTableSchema, systemschema.DatabaseRoleSettingsTable}, + {keys.TenantUsageTableID, systemschema.TenantUsageTableSchema, systemschema.TenantUsageTable}, } { privs := *test.pkg.GetPrivileges() gen, err := sql.CreateTestTableDescriptor( diff --git a/pkg/sql/tests/testdata/initial_keys b/pkg/sql/tests/testdata/initial_keys index 854db955ff30..cbdac67df188 100644 --- a/pkg/sql/tests/testdata/initial_keys +++ b/pkg/sql/tests/testdata/initial_keys @@ -1,6 +1,6 @@ initial-keys tenant=system ---- -77 keys: +79 keys: /System/"desc-idgen" /Table/3/1/1/2/1 /Table/3/1/3/2/1 @@ -36,6 +36,7 @@ initial-keys tenant=system /Table/3/1/42/2/1 /Table/3/1/43/2/1 /Table/3/1/44/2/1 + /Table/3/1/45/2/1 /Table/5/1/0/2/1 /Table/5/1/1/2/1 /Table/5/1/16/2/1 @@ -72,13 +73,14 @@ initial-keys tenant=system /NamespaceTable/30/1/1/29/"statement_diagnostics_requests"/4/1 /NamespaceTable/30/1/1/29/"statement_statistics"/4/1 /NamespaceTable/30/1/1/29/"table_statistics"/4/1 + /NamespaceTable/30/1/1/29/"tenant_usage"/4/1 /NamespaceTable/30/1/1/29/"tenants"/4/1 /NamespaceTable/30/1/1/29/"transaction_statistics"/4/1 /NamespaceTable/30/1/1/29/"ui"/4/1 /NamespaceTable/30/1/1/29/"users"/4/1 /NamespaceTable/30/1/1/29/"web_sessions"/4/1 /NamespaceTable/30/1/1/29/"zones"/4/1 -34 splits: +35 splits: /Table/11 /Table/12 /Table/13 @@ -113,6 +115,7 @@ initial-keys tenant=system /Table/42 /Table/43 /Table/44 + /Table/45 initial-keys tenant=5 ---- From c0f5a3da120c0f0ff2d4d9ab3a7d0f054812a3c4 Mon Sep 17 00:00:00 2001 From: Radu Berinde Date: Fri, 30 Jul 2021 13:18:42 -0700 Subject: [PATCH 2/3] tenantcostserver: use the tenant_usage system table This change implements most of the interaction with the tenant_usage system table, with the exception of dead instances detection and clean-up. We currently tolerate an empty table, but it would be cleaner to initialize the tenant state (instance_id=0 row) at tenant creation time (+ implement a migration). I will explore this in a future change, when we add some configurable defaults for the refill rate etc. Release note: None --- .../tenantcostclient/tenant_side.go | 2 + .../tenantcostserver/BUILD.bazel | 5 + .../tenantcostserver/configure.go | 6 +- .../tenantcostserver/server_test.go | 218 +++- .../tenantcostserver/system_table.go | 530 ++++++++ .../tenantcostserver/testdata/configure | 40 + .../tenantcostserver/testdata/instances | 73 ++ .../tenantcostserver/testdata/metrics | 45 +- .../tenantcostserver/token_bucket.go | 99 +- pkg/roachpb/api.pb.go | 1137 +++++++++-------- pkg/roachpb/api.proto | 12 +- 11 files changed, 1508 insertions(+), 659 deletions(-) create mode 100644 pkg/ccl/multitenantccl/tenantcostserver/system_table.go create mode 100644 pkg/ccl/multitenantccl/tenantcostserver/testdata/configure create mode 100644 pkg/ccl/multitenantccl/tenantcostserver/testdata/instances diff --git a/pkg/ccl/multitenantccl/tenantcostclient/tenant_side.go b/pkg/ccl/multitenantccl/tenantcostclient/tenant_side.go index 69268d7acb52..e1e9d33d8a71 100644 --- a/pkg/ccl/multitenantccl/tenantcostclient/tenant_side.go +++ b/pkg/ccl/multitenantccl/tenantcostclient/tenant_side.go @@ -62,6 +62,8 @@ func (c *tenantSideCostController) mainLoop(ctx context.Context, stopper *stop.S case <-ticker.C: req := roachpb.TokenBucketRequest{ TenantID: c.tenantID.ToUint64(), + // TODO(radu): populate instance ID. + InstanceID: 1, ConsumptionSinceLastRequest: roachpb.TokenBucketRequest_Consumption{ // Report a dummy 1 RU consumption each time. RU: 1, diff --git a/pkg/ccl/multitenantccl/tenantcostserver/BUILD.bazel b/pkg/ccl/multitenantccl/tenantcostserver/BUILD.bazel index 1016e5da9686..116894b61c3d 100644 --- a/pkg/ccl/multitenantccl/tenantcostserver/BUILD.bazel +++ b/pkg/ccl/multitenantccl/tenantcostserver/BUILD.bazel @@ -6,11 +6,13 @@ go_library( "configure.go", "metrics.go", "server.go", + "system_table.go", "token_bucket.go", ], importpath = "github.com/cockroachdb/cockroach/pkg/ccl/multitenantccl/tenantcostserver", visibility = ["//visibility:public"], deps = [ + "//pkg/base", "//pkg/ccl/multitenantccl/tenantcostserver/tenanttokenbucket", "//pkg/kv", "//pkg/multitenant", @@ -21,6 +23,7 @@ go_library( "//pkg/sql/pgwire/pgerror", "//pkg/sql/sem/tree", "//pkg/sql/sessiondata", + "//pkg/util", "//pkg/util/metric", "//pkg/util/metric/aggmetric", "//pkg/util/syncutil", @@ -39,6 +42,8 @@ go_test( deps = [ ":tenantcostserver", "//pkg/base", + "//pkg/kv", + "//pkg/multitenant", "//pkg/roachpb:with-mocks", "//pkg/security", "//pkg/security/securitytest", diff --git a/pkg/ccl/multitenantccl/tenantcostserver/configure.go b/pkg/ccl/multitenantccl/tenantcostserver/configure.go index 5ec28039ee10..1392e44fe4ab 100644 --- a/pkg/ccl/multitenantccl/tenantcostserver/configure.go +++ b/pkg/ccl/multitenantccl/tenantcostserver/configure.go @@ -47,16 +47,16 @@ func (s *instance) ReconfigureTokenBucket( if active := *row[0].(*tree.DBool); !active { return errors.Errorf("tenant %q is not active", tenantID) } - state, err := readTenantUsageState(ctx, s.executor, txn, tenantID) + h := makeSysTableHelper(ctx, s.executor, txn, tenantID) + state, err := h.readTenantState() if err != nil { return err } - state.Seq++ state.Bucket.Reconfigure( availableRU, refillRate, maxBurstRU, asOf, asOfConsumedRequestUnits, timeutil.Now(), state.Consumption.RU, ) - if err := updateTenantUsageState(ctx, s.executor, txn, tenantID, state); err != nil { + if err := h.updateTenantState(state); err != nil { return err } return nil diff --git a/pkg/ccl/multitenantccl/tenantcostserver/server_test.go b/pkg/ccl/multitenantccl/tenantcostserver/server_test.go index 823c659534a1..efce1fc7ec6d 100644 --- a/pkg/ccl/multitenantccl/tenantcostserver/server_test.go +++ b/pkg/ccl/multitenantccl/tenantcostserver/server_test.go @@ -10,12 +10,16 @@ package tenantcostserver_test import ( "context" + gosql "database/sql" "fmt" "regexp" "strconv" "testing" "github.com/cockroachdb/cockroach/pkg/base" + "github.com/cockroachdb/cockroach/pkg/ccl/multitenantccl/tenantcostserver" + "github.com/cockroachdb/cockroach/pkg/kv" + "github.com/cockroachdb/cockroach/pkg/multitenant" "github.com/cockroachdb/cockroach/pkg/roachpb" "github.com/cockroachdb/cockroach/pkg/server" "github.com/cockroachdb/cockroach/pkg/sql" @@ -37,78 +41,154 @@ func TestDataDriven(t *testing.T) { datadriven.Walk(t, "testdata", func(t *testing.T, path string) { defer leaktest.AfterTest(t)() - // Set up a server that we use only for the system tables. - ctx := context.Background() - s, db, kvDB := serverutils.StartServer(t, base.TestServerArgs{}) - defer s.Stopper().Stop(ctx) - r := sqlutils.MakeSQLRunner(db) - - tenantUsage := server.NewTenantUsageServer(kvDB, s.InternalExecutor().(*sql.InternalExecutor)) - metricsReg := metric.NewRegistry() - metricsReg.AddMetricStruct(tenantUsage.Metrics()) + var ts testState + ts.start(t) + defer ts.stop() datadriven.RunTest(t, path, func(t *testing.T, d *datadriven.TestData) string { - switch d.Cmd { - case "create-tenant": - if len(d.CmdArgs) != 1 { - d.Fatalf(t, "expected tenant number") - } - r.Exec(t, fmt.Sprintf("SELECT crdb_internal.create_tenant(%s)", d.CmdArgs[0].Key)) - return "" - - case "token-bucket-request": - if len(d.CmdArgs) != 1 { - d.Fatalf(t, "expected tenant number") - } - tenantID, err := strconv.Atoi(d.CmdArgs[0].Key) - if err != nil { - d.Fatalf(t, "%v", err) - } - var args struct { - Consumption struct { - RU float64 `yaml:"ru"` - ReadReq uint64 `yaml:"read_req"` - ReadBytes uint64 `yaml:"read_bytes"` - WriteReq uint64 `yaml:"write_req"` - WriteBytes uint64 `yaml:"write_bytes"` - SQLPodsCPUUsage float64 `yaml:"sql_pods_cpu_usage"` - } - } - if err := yaml.UnmarshalStrict([]byte(d.Input), &args); err != nil { - d.Fatalf(t, "failed to parse request yaml: %v", err) - } - req := roachpb.TokenBucketRequest{ - TenantID: uint64(tenantID), - ConsumptionSinceLastRequest: roachpb.TokenBucketRequest_Consumption{ - RU: args.Consumption.RU, - ReadRequests: args.Consumption.ReadReq, - ReadBytes: args.Consumption.ReadBytes, - WriteRequests: args.Consumption.WriteReq, - WriteBytes: args.Consumption.WriteBytes, - SQLPodCPUSeconds: args.Consumption.SQLPodsCPUUsage, - }, - } - res := tenantUsage.TokenBucketRequest(ctx, roachpb.MakeTenantID(uint64(tenantID)), &req) - if res.Error != (errors.EncodedError{}) { - return fmt.Sprintf("error: %v", errors.DecodeError(context.Background(), res.Error)) - } - return "" - - case "metrics": - re, err := regexp.Compile(d.Input) - if err != nil { - d.Fatalf(t, "failed to compile pattern: %v", err) - } - str, err := metrictestutils.GetMetricsText(metricsReg, re) - if err != nil { - d.Fatalf(t, "failed to scrape metrics: %v", err) - } - return str - - default: - d.Fatalf(t, "unknown command %q", d.Cmd) - return "" + fn, ok := testStateCommands[d.Cmd] + if !ok { + d.Fatalf(t, "unknown command %s", d.Cmd) } + return fn(&ts, t, d) }) }) } + +type testState struct { + s serverutils.TestServerInterface + db *gosql.DB + kvDB *kv.DB + r *sqlutils.SQLRunner + tenantUsage multitenant.TenantUsageServer + metricsReg *metric.Registry +} + +func (ts *testState) start(t *testing.T) { + // Set up a server that we use only for the system tables. + ts.s, ts.db, ts.kvDB = serverutils.StartServer(t, base.TestServerArgs{}) + ts.r = sqlutils.MakeSQLRunner(ts.db) + + ts.tenantUsage = server.NewTenantUsageServer(ts.kvDB, ts.s.InternalExecutor().(*sql.InternalExecutor)) + ts.metricsReg = metric.NewRegistry() + ts.metricsReg.AddMetricStruct(ts.tenantUsage.Metrics()) +} + +func (ts *testState) stop() { + ts.s.Stopper().Stop(context.Background()) +} + +var testStateCommands = map[string]func(*testState, *testing.T, *datadriven.TestData) string{ + "create-tenant": (*testState).createTenant, + "token-bucket-request": (*testState).tokenBucketRequest, + "metrics": (*testState).metrics, + "configure": (*testState).configure, + "inspect": (*testState).inspect, +} + +func (ts *testState) tenantID(t *testing.T, d *datadriven.TestData) uint64 { + for _, arg := range d.CmdArgs { + if arg.Key == "tenant" { + if len(arg.Vals) != 1 { + d.Fatalf(t, "tenant argument requires a value") + } + id, err := strconv.Atoi(arg.Vals[0]) + if err != nil || id < 1 { + d.Fatalf(t, "invalid tenant argument") + } + return uint64(id) + } + } + d.Fatalf(t, "command requires tenant= argument") + return 0 +} + +func (ts *testState) createTenant(t *testing.T, d *datadriven.TestData) string { + ts.r.Exec(t, fmt.Sprintf("SELECT crdb_internal.create_tenant(%d)", ts.tenantID(t, d))) + return "" +} + +func (ts *testState) tokenBucketRequest(t *testing.T, d *datadriven.TestData) string { + tenantID := ts.tenantID(t, d) + var args struct { + InstanceID uint32 `yaml:"instance_id"` + Consumption struct { + RU float64 `yaml:"ru"` + ReadReq uint64 `yaml:"read_req"` + ReadBytes uint64 `yaml:"read_bytes"` + WriteReq uint64 `yaml:"write_req"` + WriteBytes uint64 `yaml:"write_bytes"` + SQLPodsCPUUsage float64 `yaml:"sql_pods_cpu_usage"` + } + } + if err := yaml.UnmarshalStrict([]byte(d.Input), &args); err != nil { + d.Fatalf(t, "failed to parse request yaml: %v", err) + } + req := roachpb.TokenBucketRequest{ + TenantID: uint64(tenantID), + InstanceID: args.InstanceID, + ConsumptionSinceLastRequest: roachpb.TokenBucketRequest_Consumption{ + RU: args.Consumption.RU, + ReadRequests: args.Consumption.ReadReq, + ReadBytes: args.Consumption.ReadBytes, + WriteRequests: args.Consumption.WriteReq, + WriteBytes: args.Consumption.WriteBytes, + SQLPodCPUSeconds: args.Consumption.SQLPodsCPUUsage, + }, + } + res := ts.tenantUsage.TokenBucketRequest( + context.Background(), roachpb.MakeTenantID(tenantID), &req, + ) + if res.Error != (errors.EncodedError{}) { + return fmt.Sprintf("error: %v", errors.DecodeError(context.Background(), res.Error)) + } + return "" +} + +func (ts *testState) metrics(t *testing.T, d *datadriven.TestData) string { + re, err := regexp.Compile(d.Input) + if err != nil { + d.Fatalf(t, "failed to compile pattern: %v", err) + } + str, err := metrictestutils.GetMetricsText(ts.metricsReg, re) + if err != nil { + d.Fatalf(t, "failed to scrape metrics: %v", err) + } + return str +} + +func (ts *testState) configure(t *testing.T, d *datadriven.TestData) string { + tenantID := ts.tenantID(t, d) + var args struct { + AvailableRU float64 `yaml:"available_ru"` + RefillRate float64 `yaml:"refill_rate"` + MaxBurstRU float64 `yaml:"max_burst_ru"` + // TODO(radu): Add AsOf/AsOfConsumedRU. + } + if err := yaml.UnmarshalStrict([]byte(d.Input), &args); err != nil { + d.Fatalf(t, "failed to parse request yaml: %v", err) + } + ts.r.Exec( + t, + `SELECT crdb_internal.update_tenant_resource_limits($1, $2, $3, $4, now(), 0)`, + tenantID, + args.AvailableRU, + args.RefillRate, + args.MaxBurstRU, + ) + return "" +} + +func (ts *testState) inspect(t *testing.T, d *datadriven.TestData) string { + tenantID := ts.tenantID(t, d) + res, err := tenantcostserver.InspectTenantMetadata( + context.Background(), + ts.s.InternalExecutor().(*sql.InternalExecutor), + nil, /* txn */ + roachpb.MakeTenantID(tenantID), + ) + if err != nil { + d.Fatalf(t, "error inspecting tenant state: %v", err) + } + return res +} diff --git a/pkg/ccl/multitenantccl/tenantcostserver/system_table.go b/pkg/ccl/multitenantccl/tenantcostserver/system_table.go new file mode 100644 index 000000000000..7425dbcd8371 --- /dev/null +++ b/pkg/ccl/multitenantccl/tenantcostserver/system_table.go @@ -0,0 +1,530 @@ +// Copyright 2021 The Cockroach Authors. +// +// Licensed as a CockroachDB Enterprise file under the Cockroach Community +// License (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt + +package tenantcostserver + +import ( + "bytes" + "context" + "fmt" + "math" + "math/rand" + + "github.com/cockroachdb/cockroach/pkg/base" + "github.com/cockroachdb/cockroach/pkg/ccl/multitenantccl/tenantcostserver/tenanttokenbucket" + "github.com/cockroachdb/cockroach/pkg/kv" + "github.com/cockroachdb/cockroach/pkg/roachpb" + "github.com/cockroachdb/cockroach/pkg/sql" + "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" + "github.com/cockroachdb/cockroach/pkg/sql/sessiondata" + "github.com/cockroachdb/cockroach/pkg/util" + "github.com/cockroachdb/errors" +) + +type tenantState struct { + // Present indicates if the state existed in the table. + Present bool + + // FirstInstance is the smallest active instance ID, or 0 if there are no + // known active instances. + FirstInstance base.SQLInstanceID + + Bucket tenanttokenbucket.State + + // Consumption is the current consumption information. + Consumption roachpb.TokenBucketRequest_Consumption +} + +func (ts *tenantState) addConsumption(c roachpb.TokenBucketRequest_Consumption) { + ts.Consumption.RU += c.RU + ts.Consumption.ReadRequests += c.ReadRequests + ts.Consumption.ReadBytes += c.ReadBytes + ts.Consumption.WriteRequests += c.WriteRequests + ts.Consumption.WriteBytes += c.WriteBytes + ts.Consumption.SQLPodCPUSeconds += c.SQLPodCPUSeconds +} + +type instanceState struct { + ID base.SQLInstanceID + + // Present indicates if the instance existed in the table. + Present bool + + // Next active instance ID or 0 if this is the instance with the largest ID. + NextInstance base.SQLInstanceID + + // Lease uniquely identifies the instance; used to disambiguate different + // incarnations of the same ID. + Lease tree.DBytes + // Seq is a sequence number used to detect duplicate client requests. + Seq int64 + // Shares term for this instance; see tenanttokenbucket.State. + Shares float64 + // Time of last request from this instance. + LastUpdate tree.DTimestamp +} + +// sysTableHelper implements the interactions with the system.tenant_usage +// table. +type sysTableHelper struct { + ctx context.Context + ex *sql.InternalExecutor + txn *kv.Txn + tenantID roachpb.TenantID +} + +func makeSysTableHelper( + ctx context.Context, ex *sql.InternalExecutor, txn *kv.Txn, tenantID roachpb.TenantID, +) sysTableHelper { + return sysTableHelper{ + ctx: ctx, + ex: ex, + txn: txn, + tenantID: tenantID, + } +} + +// readTenantState reads the tenant state from the system table. +// +// If the table was not initialized for the tenant, the tenant stats will not be +// Present. +func (h *sysTableHelper) readTenantState() (tenant tenantState, _ error) { + // We could use a simplified query, but the benefit will be marginal and + // this is not used in the hot path. + tenant, _, err := h.readTenantAndInstanceState(0 /* instanceID */) + return tenant, err +} + +// readTenantAndInstanceState reads the tenant and instance state from the system +// table. +// +// If the table was not initialized for the tenant, the tenant and instance +// state will not be Present. +// +// If the instance is not in the current active set (according to the table), +// the instance state will not be Present. +func (h *sysTableHelper) readTenantAndInstanceState( + instanceID base.SQLInstanceID, +) (tenant tenantState, instance instanceState, _ error) { + instance.ID = instanceID + // Read the two rows for the per-tenant state (instance_id = 0) and the + // per-instance state. + rows, err := h.ex.QueryBufferedEx( + h.ctx, "tenant-usage-select", h.txn, + sessiondata.NodeUserSessionDataOverride, + `SELECT + instance_id, /* 0 */ + next_instance_id, /* 1 */ + ru_burst_limit, /* 2 */ + ru_refill_rate, /* 3 */ + ru_current, /* 4 */ + current_share_sum, /* 5 */ + total_ru_usage, /* 6 */ + total_read_requests, /* 7 */ + total_read_bytes, /* 8 */ + total_write_requests, /* 9 */ + total_write_bytes, /* 10 */ + total_sql_pod_cpu_seconds, /* 11 */ + instance_lease, /* 12 */ + instance_seq, /* 13 */ + instance_shares, /* 14 */ + instance_last_update /* 15 */ + FROM system.tenant_usage + WHERE tenant_id = $1 AND instance_id IN (0, $2)`, + h.tenantID.ToUint64(), + int64(instanceID), + ) + if err != nil { + return tenant, instance, err + } + for _, r := range rows { + instanceID := base.SQLInstanceID(tree.MustBeDInt(r[0])) + if instanceID == 0 { + // Tenant state. + tenant.Present = true + tenant.FirstInstance = base.SQLInstanceID(tree.MustBeDInt(r[1])) + tenant.Bucket = tenanttokenbucket.State{ + RUBurstLimit: float64(tree.MustBeDFloat(r[2])), + RURefillRate: float64(tree.MustBeDFloat(r[3])), + RUCurrent: float64(tree.MustBeDFloat(r[4])), + CurrentShareSum: float64(tree.MustBeDFloat(r[5])), + } + tenant.Consumption = roachpb.TokenBucketRequest_Consumption{ + RU: float64(tree.MustBeDFloat(r[6])), + ReadRequests: uint64(tree.MustBeDInt(r[7])), + ReadBytes: uint64(tree.MustBeDInt(r[8])), + WriteRequests: uint64(tree.MustBeDInt(r[9])), + WriteBytes: uint64(tree.MustBeDInt(r[10])), + SQLPodCPUSeconds: float64(tree.MustBeDFloat(r[11])), + } + } else { + // Instance state. + instance.Present = true + instance.NextInstance = base.SQLInstanceID(tree.MustBeDInt(r[1])) + instance.Lease = tree.MustBeDBytes(r[12]) + instance.Seq = int64(tree.MustBeDInt(r[13])) + instance.Shares = float64(tree.MustBeDFloat(r[14])) + instance.LastUpdate = tree.MustBeDTimestamp(r[15]) + } + } + + return tenant, instance, nil +} + +// updateTenantState writes out an updated tenant state. +func (h *sysTableHelper) updateTenantState(tenant tenantState) error { + // Note: it is important that this UPSERT specifies all columns of the + // table, to allow it to perform "blind" writes. + _, err := h.ex.ExecEx( + h.ctx, "tenant-usage-upsert", h.txn, + sessiondata.NodeUserSessionDataOverride, + `UPSERT INTO system.tenant_usage( + tenant_id, + instance_id, + next_instance_id, + ru_burst_limit, + ru_refill_rate, + ru_current, + current_share_sum, + total_ru_usage, + total_read_requests, + total_read_bytes, + total_write_requests, + total_write_bytes, + total_sql_pod_cpu_seconds, + instance_lease, + instance_seq, + instance_shares, + instance_last_update + ) VALUES ($1, 0, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, NULL, NULL, NULL, NULL) + `, + h.tenantID.ToUint64(), + int64(tenant.FirstInstance), + tenant.Bucket.RUBurstLimit, + tenant.Bucket.RURefillRate, + tenant.Bucket.RUCurrent, + tenant.Bucket.CurrentShareSum, + tenant.Consumption.RU, + tenant.Consumption.ReadRequests, + tenant.Consumption.ReadBytes, + tenant.Consumption.WriteRequests, + tenant.Consumption.WriteBytes, + tenant.Consumption.SQLPodCPUSeconds, + ) + return err +} + +// updateTenantState writes out updated tenant and instance states. +func (h *sysTableHelper) updateTenantAndInstanceState( + tenant tenantState, instance instanceState, +) error { + // Note: it is important that this UPSERT specifies all columns of the + // table, to allow it to perform "blind" writes. + _, err := h.ex.ExecEx( + h.ctx, "tenant-usage-insert", h.txn, + sessiondata.NodeUserSessionDataOverride, + `UPSERT INTO system.tenant_usage( + tenant_id, + instance_id, + next_instance_id, + ru_burst_limit, + ru_refill_rate, + ru_current, + current_share_sum, + total_ru_usage, + total_read_requests, + total_read_bytes, + total_write_requests, + total_write_bytes, + total_sql_pod_cpu_seconds, + instance_lease, + instance_seq, + instance_shares, + instance_last_update + ) VALUES + ($1, 0, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, NULL, NULL, NULL, NULL), + ($1, $13, $14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, $15, $16, $17, $18) + `, + h.tenantID.ToUint64(), // $1 + int64(tenant.FirstInstance), // $2 + tenant.Bucket.RUBurstLimit, // $3 + tenant.Bucket.RURefillRate, // $4 + tenant.Bucket.RUCurrent, // $5 + tenant.Bucket.CurrentShareSum, // $6 + tenant.Consumption.RU, // $7 + tenant.Consumption.ReadRequests, // $8 + tenant.Consumption.ReadBytes, // $9 + tenant.Consumption.WriteRequests, // $10 + tenant.Consumption.WriteBytes, // $11 + tenant.Consumption.SQLPodCPUSeconds, // $12 + int64(instance.ID), // $13 + int64(instance.NextInstance), // $14 + &instance.Lease, // $15 + instance.Seq, // $16 + instance.Shares, // $17 + &instance.LastUpdate, // $18 + ) + return err +} + +// accomodateNewInstance is used when we are about to insert a new instance. It +// sets instance.NextInstance and updates the previous instance's +// next_instance_id in the table (or updates tenant.FirstInstance). +// +// Note that this should only happen after a SQL pod starts up (which is +// infrequent). In addition, the SQL pod start-up process is not blocked on +// tenant bucket requests (which happen in the background). +func (h *sysTableHelper) accomodateNewInstance(tenant *tenantState, instance *instanceState) error { + if tenant.FirstInstance == 0 || tenant.FirstInstance > instance.ID { + // The new instance has the lowest ID. + instance.NextInstance = tenant.FirstInstance + tenant.FirstInstance = instance.ID + return nil + } + // Find the previous instance. + row, err := h.ex.QueryRowEx( + h.ctx, "find-prev-id", h.txn, + sessiondata.NodeUserSessionDataOverride, + `SELECT + instance_id, /* 0 */ + next_instance_id, /* 1 */ + instance_lease, /* 2 */ + instance_seq, /* 3 */ + instance_shares, /* 4 */ + instance_last_update /* 5 */ + FROM system.tenant_usage + WHERE tenant_id = $1 AND instance_id > 0 AND instance_id < $2 + ORDER BY instance_id DESC + LIMIT 1`, + h.tenantID.ToUint64(), + int64(instance.ID), + ) + if err != nil { + return err + } + if row == nil { + return errors.Errorf("could not find row for previous instance") + } + prevInstanceID := base.SQLInstanceID(tree.MustBeDInt(row[0])) + instance.NextInstance = base.SQLInstanceID(tree.MustBeDInt(row[1])) + prevInstanceLease := row[2] + prevInstanceSeq := row[3] + prevInstanceShares := row[4] + prevInstanceLastUpdate := row[5] + + // Update the previous instance: its next_instance_id is the new instance. + // TODO(radu): consider coalescing this with updateTenantAndInstanceState to + // perform a single UPSERT. + _, err = h.ex.ExecEx( + h.ctx, "update-next-id", h.txn, + sessiondata.NodeUserSessionDataOverride, + // Update the previous instance's next_instance_id. + `UPSERT INTO system.tenant_usage( + tenant_id, + instance_id, + next_instance_id, + ru_burst_limit, + ru_refill_rate, + ru_current, + current_share_sum, + total_ru_usage, + total_read_requests, + total_read_bytes, + total_write_requests, + total_write_bytes, + total_sql_pod_cpu_seconds, + instance_lease, + instance_seq, + instance_shares, + instance_last_update + ) VALUES ($1, $2, $3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, $4, $5, $6, $7) + `, + h.tenantID.ToUint64(), + int64(prevInstanceID), + int64(instance.ID), + prevInstanceLease, + prevInstanceSeq, + prevInstanceShares, + prevInstanceLastUpdate, + ) + return err +} + +// maybeCheckInvariants checks the invariants for the system table with a random +// probability and only if this is a test build. +func (h *sysTableHelper) maybeCheckInvariants() error { + if util.CrdbTestBuild && rand.Intn(10) == 0 { + return h.checkInvariants() + } + return nil +} + +// checkInvariants reads all rows in the system table for the given tenant and +// checks that the state is consistent. +func (h *sysTableHelper) checkInvariants() error { + // Read the two rows for the per-tenant state (instance_id = 0) and the + // per-instance state. + rows, err := h.ex.QueryBufferedEx( + h.ctx, "tenant-usage-select", h.txn, + sessiondata.NodeUserSessionDataOverride, + `SELECT + instance_id, /* 0 */ + next_instance_id, /* 1 */ + ru_burst_limit, /* 2 */ + ru_refill_rate, /* 3 */ + ru_current, /* 4 */ + current_share_sum, /* 5 */ + total_ru_usage, /* 6 */ + total_read_requests, /* 7 */ + total_read_bytes, /* 8 */ + total_write_requests, /* 9 */ + total_write_bytes, /* 10 */ + total_sql_pod_cpu_seconds, /* 11 */ + instance_lease, /* 12 */ + instance_seq, /* 13 */ + instance_shares, /* 14 */ + instance_last_update /* 15 */ + FROM system.tenant_usage + WHERE tenant_id = $1 + ORDER BY instance_id`, + h.tenantID.ToUint64(), + ) + if err != nil { + return err + } + if len(rows) == 0 { + return nil + } + + // Get the instance IDs. + instanceIDs := make([]base.SQLInstanceID, len(rows)) + for i := range rows { + instanceIDs[i] = base.SQLInstanceID(tree.MustBeDInt(rows[i][0])) + if i > 0 && instanceIDs[i-1] >= instanceIDs[i] { + return errors.New("instances out of order") + } + } + if instanceIDs[0] != 0 { + return errors.New("instance 0 row missing") + } + + // Check NULL values. + for i := range rows { + var nullFirst, nullLast int + if i == 0 { + // Row 0 should have NULL per-instance values. + nullFirst, nullLast = 12, 15 + } else { + // Other rows should have NULL per-tenant values. + nullFirst, nullLast = 2, 11 + } + for j := range rows[i] { + isNull := (rows[i][j] == tree.DNull) + expNull := (j >= nullFirst && j <= nullLast) + if expNull != isNull { + if !expNull { + return errors.Errorf("expected NULL column %d", j) + } + return errors.Errorf("expected non-NULL column %d", j) + } + } + } + + // Verify next_instance_id values. + for i := range rows { + expNextInstanceID := base.SQLInstanceID(0) + if i+1 < len(rows) { + expNextInstanceID = instanceIDs[i+1] + } + nextInstanceID := base.SQLInstanceID(tree.MustBeDInt(rows[i][1])) + if expNextInstanceID != nextInstanceID { + return errors.Errorf("expected next instance %d, have %d", expNextInstanceID, nextInstanceID) + } + } + + // Verify the shares sum. + sharesSum := float64(tree.MustBeDFloat(rows[0][5])) + var expSharesSum float64 + for _, r := range rows[1:] { + expSharesSum += float64(tree.MustBeDFloat(r[14])) + } + + a, b := sharesSum, expSharesSum + if a > b { + a, b = b, a + } + // We use "units of least precision" for similarity: this is the number of + // representable floating point numbers in-between the two values. This is + // better than a fixed epsilon because the allowed error is proportional to + // the magnitude of the numbers. Because the mantissa is in the low bits, we + // can just use the bit representations as integers. + const ulpTolerance = 1000 + if math.Float64bits(a)+ulpTolerance <= math.Float64bits(b) { + return errors.Errorf("expected shares sum %g, have %g", expSharesSum, sharesSum) + } + return nil +} + +// InspectTenantMetadata returns all the information from the tenant_usage table +// for a given tenant, in a user-readable format (multi-line). Used for testing +// and debugging. +func InspectTenantMetadata( + ctx context.Context, ex *sql.InternalExecutor, txn *kv.Txn, tenantID roachpb.TenantID, +) (string, error) { + h := makeSysTableHelper(ctx, ex, txn, tenantID) + tenant, err := h.readTenantState() + if err != nil { + return "", err + } + if !tenant.Present { + return "empty state", nil + } + + var buf bytes.Buffer + fmt.Fprintf(&buf, "Bucket state: ru-burst-limit=%g ru-refill-rate=%g ru-current=%g current-share-sum=%g\n", + tenant.Bucket.RUBurstLimit, + tenant.Bucket.RURefillRate, + tenant.Bucket.RUCurrent, + tenant.Bucket.CurrentShareSum, + ) + fmt.Fprintf(&buf, "Consumption: ru=%g reads=%d req/%d bytes writes=%d req/%d bytes pod-cpu-usage: %g\n", + tenant.Consumption.RU, + tenant.Consumption.ReadRequests, + tenant.Consumption.ReadBytes, + tenant.Consumption.WriteRequests, + tenant.Consumption.WriteBytes, + tenant.Consumption.SQLPodCPUSeconds, + ) + fmt.Fprintf(&buf, "First active instance: %d\n", tenant.FirstInstance) + + rows, err := ex.QueryBufferedEx( + ctx, "inspect-tenant-state", txn, + sessiondata.NodeUserSessionDataOverride, + `SELECT + instance_id, /* 0 */ + next_instance_id, /* 1 */ + instance_lease, /* 2 */ + instance_seq, /* 3 */ + instance_shares, /* 4 */ + instance_last_update /* 5 */ + FROM system.tenant_usage + WHERE tenant_id = $1 AND instance_id > 0 + ORDER BY instance_id`, + tenantID.ToUint64(), + ) + if err != nil { + return "", err + } + for _, r := range rows { + fmt.Fprintf( + &buf, " Instance %s: lease=%s seq=%s shares=%s next-instance=%s\n", + r[0], r[2], r[3], r[4], r[1], + ) + } + return buf.String(), nil +} diff --git a/pkg/ccl/multitenantccl/tenantcostserver/testdata/configure b/pkg/ccl/multitenantccl/tenantcostserver/testdata/configure new file mode 100644 index 000000000000..a1864776e027 --- /dev/null +++ b/pkg/ccl/multitenantccl/tenantcostserver/testdata/configure @@ -0,0 +1,40 @@ +inspect tenant=5 +---- +empty state + +create-tenant tenant=5 +---- + +inspect tenant=5 +---- +empty state + +configure tenant=5 +available_ru: 1000 +refill_rate: 100 +max_burst_ru: 5000 +---- + +inspect tenant=5 +---- +Bucket state: ru-burst-limit=5000 ru-refill-rate=100 ru-current=1000 current-share-sum=0 +Consumption: ru=0 reads=0 req/0 bytes writes=0 req/0 bytes pod-cpu-usage: 0 +First active instance: 0 + +token-bucket-request tenant=5 +instance_id: 1 +consumption: + ru: 10 + read_req: 20 + read_bytes: 30 + write_req: 40 + write_bytes: 50 + sql_pods_cpu_usage: 60 +---- + +inspect tenant=5 +---- +Bucket state: ru-burst-limit=5000 ru-refill-rate=100 ru-current=1000 current-share-sum=0 +Consumption: ru=10 reads=20 req/30 bytes writes=40 req/50 bytes pod-cpu-usage: 60 +First active instance: 1 + Instance 1: lease='\x' seq=0 shares=0.0 next-instance=0 diff --git a/pkg/ccl/multitenantccl/tenantcostserver/testdata/instances b/pkg/ccl/multitenantccl/tenantcostserver/testdata/instances new file mode 100644 index 000000000000..3f44425dfba0 --- /dev/null +++ b/pkg/ccl/multitenantccl/tenantcostserver/testdata/instances @@ -0,0 +1,73 @@ +# The tests in this file verify the correct maintenance of next_instance_id. + +inspect tenant=5 +---- +empty state + +create-tenant tenant=5 +---- + +inspect tenant=5 +---- +empty state + +token-bucket-request tenant=5 +instance_id: 10 +---- + +inspect tenant=5 +---- +Bucket state: ru-burst-limit=0 ru-refill-rate=0 ru-current=0 current-share-sum=0 +Consumption: ru=0 reads=0 req/0 bytes writes=0 req/0 bytes pod-cpu-usage: 0 +First active instance: 10 + Instance 10: lease='\x' seq=0 shares=0.0 next-instance=0 + +token-bucket-request tenant=5 +instance_id: 10 +---- + +inspect tenant=5 +---- +Bucket state: ru-burst-limit=0 ru-refill-rate=0 ru-current=0 current-share-sum=0 +Consumption: ru=0 reads=0 req/0 bytes writes=0 req/0 bytes pod-cpu-usage: 0 +First active instance: 10 + Instance 10: lease='\x' seq=0 shares=0.0 next-instance=0 + +token-bucket-request tenant=5 +instance_id: 20 +---- + +inspect tenant=5 +---- +Bucket state: ru-burst-limit=0 ru-refill-rate=0 ru-current=0 current-share-sum=0 +Consumption: ru=0 reads=0 req/0 bytes writes=0 req/0 bytes pod-cpu-usage: 0 +First active instance: 10 + Instance 10: lease='\x' seq=0 shares=0.0 next-instance=20 + Instance 20: lease='\x' seq=0 shares=0.0 next-instance=0 + +token-bucket-request tenant=5 +instance_id: 15 +---- + +inspect tenant=5 +---- +Bucket state: ru-burst-limit=0 ru-refill-rate=0 ru-current=0 current-share-sum=0 +Consumption: ru=0 reads=0 req/0 bytes writes=0 req/0 bytes pod-cpu-usage: 0 +First active instance: 10 + Instance 10: lease='\x' seq=0 shares=0.0 next-instance=15 + Instance 15: lease='\x' seq=0 shares=0.0 next-instance=20 + Instance 20: lease='\x' seq=0 shares=0.0 next-instance=0 + +token-bucket-request tenant=5 +instance_id: 1 +---- + +inspect tenant=5 +---- +Bucket state: ru-burst-limit=0 ru-refill-rate=0 ru-current=0 current-share-sum=0 +Consumption: ru=0 reads=0 req/0 bytes writes=0 req/0 bytes pod-cpu-usage: 0 +First active instance: 1 + Instance 1: lease='\x' seq=0 shares=0.0 next-instance=10 + Instance 10: lease='\x' seq=0 shares=0.0 next-instance=15 + Instance 15: lease='\x' seq=0 shares=0.0 next-instance=20 + Instance 20: lease='\x' seq=0 shares=0.0 next-instance=0 diff --git a/pkg/ccl/multitenantccl/tenantcostserver/testdata/metrics b/pkg/ccl/multitenantccl/tenantcostserver/testdata/metrics index c40590d9b624..54bdf9184df0 100644 --- a/pkg/ccl/multitenantccl/tenantcostserver/testdata/metrics +++ b/pkg/ccl/multitenantccl/tenantcostserver/testdata/metrics @@ -1,7 +1,8 @@ -create-tenant 5 +create-tenant tenant=5 ---- -token-bucket-request 5 +token-bucket-request tenant=5 +instance_id: 1 consumption: ru: 10 read_req: 20 @@ -20,3 +21,43 @@ tenant_consumption_request_units{tenant_id="5"} 10 tenant_consumption_sql_pods_cpu_seconds{tenant_id="5"} 60 tenant_consumption_write_bytes{tenant_id="5"} 50 tenant_consumption_write_requests{tenant_id="5"} 40 + +token-bucket-request tenant=5 +instance_id: 1 +consumption: + ru: 100 + read_req: 200 + read_bytes: 300 + write_req: 400 + write_bytes: 500 + sql_pods_cpu_usage: 600 +---- + +token-bucket-request tenant=5 +instance_id: 2 +consumption: + ru: 1000 + read_req: 2000 + read_bytes: 3000 + write_req: 4000 + write_bytes: 5000 + sql_pods_cpu_usage: 6000 +---- + +inspect tenant=5 +---- +Bucket state: ru-burst-limit=0 ru-refill-rate=0 ru-current=0 current-share-sum=0 +Consumption: ru=1110 reads=2220 req/3330 bytes writes=4440 req/5550 bytes pod-cpu-usage: 6660 +First active instance: 1 + Instance 1: lease='\x' seq=0 shares=0.0 next-instance=2 + Instance 2: lease='\x' seq=0 shares=0.0 next-instance=0 + +metrics +tenant_id="5" +---- +tenant_consumption_read_bytes{tenant_id="5"} 3330 +tenant_consumption_read_requests{tenant_id="5"} 2220 +tenant_consumption_request_units{tenant_id="5"} 1110 +tenant_consumption_sql_pods_cpu_seconds{tenant_id="5"} 6660 +tenant_consumption_write_bytes{tenant_id="5"} 5550 +tenant_consumption_write_requests{tenant_id="5"} 4440 diff --git a/pkg/ccl/multitenantccl/tenantcostserver/token_bucket.go b/pkg/ccl/multitenantccl/tenantcostserver/token_bucket.go index de8f7b1f960a..ba8b51f0974b 100644 --- a/pkg/ccl/multitenantccl/tenantcostserver/token_bucket.go +++ b/pkg/ccl/multitenantccl/tenantcostserver/token_bucket.go @@ -11,10 +11,9 @@ package tenantcostserver import ( "context" - "github.com/cockroachdb/cockroach/pkg/ccl/multitenantccl/tenantcostserver/tenanttokenbucket" + "github.com/cockroachdb/cockroach/pkg/base" "github.com/cockroachdb/cockroach/pkg/kv" "github.com/cockroachdb/cockroach/pkg/roachpb" - "github.com/cockroachdb/cockroach/pkg/sql" "github.com/cockroachdb/cockroach/pkg/util/timeutil" "github.com/cockroachdb/errors" ) @@ -31,74 +30,64 @@ func (s *instance) TokenBucketRequest( Error: errors.EncodeError(ctx, errors.New("token bucket request for system tenant")), } } + instanceID := base.SQLInstanceID(in.InstanceID) + if instanceID < 1 { + return &roachpb.TokenBucketResponse{ + Error: errors.EncodeError(ctx, errors.Errorf("invalid instance ID %d", instanceID)), + } + } result := &roachpb.TokenBucketResponse{} + var consumption roachpb.TokenBucketRequest_Consumption if err := s.db.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error { - state, err := readTenantUsageState(ctx, s.executor, txn, tenantID) + *result = roachpb.TokenBucketResponse{} + + h := makeSysTableHelper(ctx, s.executor, txn, tenantID) + tenant, instance, err := h.readTenantAndInstanceState(instanceID) if err != nil { return err } - state.Seq++ - // Update consumption. - state.Consumption.RU += in.ConsumptionSinceLastRequest.RU - state.Consumption.ReadRequests += in.ConsumptionSinceLastRequest.ReadRequests - state.Consumption.ReadBytes += in.ConsumptionSinceLastRequest.ReadBytes - state.Consumption.WriteRequests += in.ConsumptionSinceLastRequest.WriteRequests - state.Consumption.WriteBytes += in.ConsumptionSinceLastRequest.WriteBytes - state.Consumption.SQLPodCPUSeconds += in.ConsumptionSinceLastRequest.SQLPodCPUSeconds + if !tenant.Present { + // TODO(radu): initialize tenant state. + tenant.FirstInstance = 0 + } + + if !instance.Present { + if err := h.accomodateNewInstance(&tenant, &instance); err != nil { + return err + } + } + + tenant.addConsumption(in.ConsumptionSinceLastRequest) - *result = state.Bucket.Request(in, timeutil.Now()) + // TODO(radu): update shares. + *result = tenant.Bucket.Request(in, timeutil.Now()) - if err := updateTenantUsageState(ctx, s.executor, txn, tenantID, state); err != nil { + if err := h.updateTenantAndInstanceState(tenant, instance); err != nil { return err } - // Report current consumption. - m := s.metrics.getTenantMetrics(tenantID) - m.totalRU.Update(state.Consumption.RU) - m.totalReadRequests.Update(int64(state.Consumption.ReadRequests)) - m.totalReadBytes.Update(int64(state.Consumption.ReadBytes)) - m.totalWriteRequests.Update(int64(state.Consumption.WriteRequests)) - m.totalWriteBytes.Update(int64(state.Consumption.WriteBytes)) - m.totalSQLPodsCPUSeconds.Update(state.Consumption.SQLPodCPUSeconds) - - return updateTenantUsageState(ctx, s.executor, txn, tenantID, state) + if err := h.maybeCheckInvariants(); err != nil { + panic(err) + } + consumption = tenant.Consumption + return nil }); err != nil { - *result = roachpb.TokenBucketResponse{ + return &roachpb.TokenBucketResponse{ Error: errors.EncodeError(ctx, err), } } - return result -} - -type tenantUsageState struct { - // Seq is a sequence number identifying this state. All state changes are - // strictly sequenced, with consecutive sequence numbers. - Seq int64 - - Bucket tenanttokenbucket.State - // Current consumption information. - Consumption roachpb.TokenBucketRequest_Consumption -} - -// readCurrentBucketState reads the current (last) bucket state. The zero struct -// is returned if the state is not yet initialized. -func readTenantUsageState( - ctx context.Context, ex *sql.InternalExecutor, txn *kv.Txn, tenantID roachpb.TenantID, -) (tenantUsageState, error) { - // TODO(radu): interact with the system table. - return tenantUsageState{}, nil -} - -func updateTenantUsageState( - ctx context.Context, - ex *sql.InternalExecutor, - txn *kv.Txn, - tenantID roachpb.TenantID, - newState tenantUsageState, -) error { - // TODO(radu): interact with the system table. - return nil + // Report current consumption. + // TODO(radu): there is a possible race here, where two different requests + // update the metrics in opposite order. + m := s.metrics.getTenantMetrics(tenantID) + m.totalRU.Update(consumption.RU) + m.totalReadRequests.Update(int64(consumption.ReadRequests)) + m.totalReadBytes.Update(int64(consumption.ReadBytes)) + m.totalWriteRequests.Update(int64(consumption.WriteRequests)) + m.totalWriteBytes.Update(int64(consumption.WriteBytes)) + m.totalSQLPodsCPUSeconds.Update(consumption.SQLPodCPUSeconds) + return result } diff --git a/pkg/roachpb/api.pb.go b/pkg/roachpb/api.pb.go index b45dd084a018..b3a80525b6c1 100644 --- a/pkg/roachpb/api.pb.go +++ b/pkg/roachpb/api.pb.go @@ -7011,9 +7011,15 @@ func (m *GossipSubscriptionEvent) XXX_DiscardUnknown() { var xxx_messageInfo_GossipSubscriptionEvent proto.InternalMessageInfo type TokenBucketRequest struct { - TenantID uint64 `protobuf:"varint,2,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"` // Consumption that occurred since this node's last request. ConsumptionSinceLastRequest TokenBucketRequest_Consumption `protobuf:"bytes,1,opt,name=consumption_since_last_request,json=consumptionSinceLastRequest,proto3" json:"consumption_since_last_request"` + TenantID uint64 `protobuf:"varint,2,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"` + // InstanceID is the ID of the SQL pod instance from where the request + // originates. + InstanceID uint32 `protobuf:"varint,3,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` + // InstanceLease uniquely identifies the SQL pod instance from where the + // request originates, in light of ID reuse. + InstanceLease []byte `protobuf:"bytes,4,opt,name=instance_lease,json=instanceLease,proto3" json:"instance_lease,omitempty"` } func (m *TokenBucketRequest) Reset() { *m = TokenBucketRequest{} } @@ -7380,538 +7386,541 @@ func init() { func init() { proto.RegisterFile("roachpb/api.proto", fileDescriptor_e08772acc330f58b) } var fileDescriptor_e08772acc330f58b = []byte{ - // 8496 bytes of a gzipped FileDescriptorProto + // 8535 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x7d, 0x5f, 0x6c, 0x23, 0x49, - 0x7a, 0x9f, 0x9a, 0xa4, 0x24, 0xf2, 0xa3, 0x44, 0xb6, 0x4a, 0xf3, 0x47, 0xa3, 0xd9, 0x95, 0x66, + 0x7a, 0x9f, 0x9a, 0xa4, 0x24, 0xf2, 0xa3, 0x48, 0xb6, 0x4a, 0xf3, 0x47, 0xab, 0xdd, 0x95, 0x66, 0x7a, 0x76, 0xfe, 0xfa, 0x96, 0xda, 0x99, 0xb9, 0xcb, 0xae, 0x77, 0xd7, 0x7b, 0x16, 0x29, 0xce, - 0x90, 0xd2, 0x48, 0xa3, 0x69, 0x52, 0x33, 0xd8, 0xf5, 0x39, 0xed, 0x56, 0x77, 0x49, 0xea, 0x13, - 0xd9, 0xcd, 0xe9, 0x6e, 0x6a, 0xc4, 0x45, 0xf2, 0x90, 0xc4, 0x70, 0xee, 0x29, 0xb8, 0x00, 0x01, - 0xbc, 0x07, 0x07, 0xc1, 0xf9, 0x0f, 0x92, 0x87, 0x3c, 0x38, 0x48, 0x82, 0x04, 0x0e, 0x92, 0x18, + 0x90, 0xd2, 0x48, 0xa3, 0x69, 0x52, 0xb3, 0xd8, 0xf5, 0x39, 0xed, 0x56, 0x77, 0x49, 0xea, 0x13, + 0xd9, 0xcd, 0xe9, 0x6e, 0x6a, 0xc4, 0x45, 0xf2, 0x90, 0xc4, 0xb0, 0xef, 0x29, 0xb8, 0x00, 0x01, + 0xbc, 0x07, 0x07, 0xc1, 0xf9, 0x0f, 0x92, 0x87, 0x3c, 0x24, 0x48, 0x82, 0x04, 0x0e, 0x92, 0x18, 0xc9, 0x4b, 0x0e, 0xc1, 0x21, 0x77, 0x7e, 0x33, 0x02, 0x44, 0x71, 0x74, 0x79, 0x88, 0x61, 0x04, - 0x0e, 0x82, 0x00, 0x06, 0x16, 0x48, 0x10, 0xd4, 0x9f, 0xfe, 0x47, 0x36, 0x29, 0x6a, 0xa6, 0x37, + 0x0e, 0x82, 0x00, 0x06, 0x16, 0x48, 0x10, 0xd4, 0x9f, 0xfe, 0x47, 0x36, 0x29, 0x6a, 0xb6, 0x37, 0x59, 0xe0, 0x5e, 0x24, 0xf6, 0x57, 0xf5, 0x7d, 0x5d, 0xf5, 0x55, 0xd5, 0x57, 0xdf, 0xaf, 0xea, - 0xab, 0x6a, 0x98, 0xb3, 0x2d, 0x55, 0x3b, 0xe8, 0xec, 0xae, 0xa8, 0x1d, 0xa3, 0xd4, 0xb1, 0x2d, - 0xd7, 0x42, 0x73, 0x9a, 0xa5, 0x1d, 0x52, 0x72, 0x89, 0x27, 0x2e, 0x5e, 0xc4, 0xb6, 0x6d, 0xd9, - 0x4e, 0x67, 0x77, 0x85, 0xfd, 0x60, 0x39, 0x17, 0xef, 0x1d, 0x1e, 0xad, 0x1c, 0x1e, 0x39, 0xd8, - 0x3e, 0xc2, 0xf6, 0x8a, 0x66, 0x99, 0x5a, 0xd7, 0xb6, 0xb1, 0xa9, 0xf5, 0x56, 0x5a, 0x96, 0x76, - 0x48, 0xff, 0x18, 0xe6, 0x7e, 0x5c, 0x5e, 0x1b, 0xab, 0xba, 0xd3, 0x6d, 0xb7, 0x55, 0xbb, 0xb7, - 0x42, 0xc5, 0xf2, 0x07, 0x9e, 0x17, 0x79, 0x85, 0xd2, 0x55, 0x57, 0xe5, 0xb4, 0x0b, 0x1e, 0x2d, - 0x52, 0x82, 0x4b, 0x1e, 0xb5, 0x8d, 0x5d, 0x35, 0x94, 0xfb, 0xaa, 0xe3, 0x5a, 0xb6, 0xba, 0x8f, - 0x57, 0xb0, 0xb9, 0x6f, 0x98, 0x98, 0x64, 0x38, 0xd2, 0x34, 0x9e, 0xf8, 0x56, 0x6c, 0xe2, 0x43, - 0x9e, 0xba, 0xd0, 0x75, 0x8d, 0xd6, 0xca, 0x41, 0x4b, 0x5b, 0x71, 0x8d, 0x36, 0x76, 0x5c, 0xb5, - 0xdd, 0xf1, 0xaa, 0x40, 0x53, 0x5c, 0x5b, 0xd5, 0x0c, 0x73, 0xdf, 0xfb, 0xdf, 0xd9, 0x5d, 0xb1, - 0xb1, 0x66, 0xd9, 0x3a, 0xd6, 0x15, 0xa7, 0xa3, 0x9a, 0x5e, 0x71, 0xf7, 0xad, 0x7d, 0x8b, 0xfe, - 0x5c, 0x21, 0xbf, 0x38, 0x75, 0x69, 0xdf, 0xb2, 0xf6, 0x5b, 0x78, 0x85, 0x3e, 0xed, 0x76, 0xf7, - 0x56, 0xf4, 0xae, 0xad, 0xba, 0x86, 0xc5, 0xb9, 0xa4, 0x7f, 0x26, 0xc0, 0xac, 0x8c, 0x5f, 0x76, - 0xb1, 0xe3, 0xd6, 0xb0, 0xaa, 0x63, 0x1b, 0x5d, 0x81, 0xf4, 0x21, 0xee, 0x2d, 0xa4, 0xaf, 0x09, - 0x77, 0x66, 0xca, 0xd3, 0x5f, 0x9e, 0x2c, 0xa7, 0x37, 0x70, 0x4f, 0x26, 0x34, 0x74, 0x0d, 0xa6, - 0xb1, 0xa9, 0x2b, 0x24, 0x39, 0x13, 0x4d, 0x9e, 0xc2, 0xa6, 0xbe, 0x81, 0x7b, 0xe8, 0x3b, 0x90, - 0x75, 0x88, 0x34, 0x53, 0xc3, 0x0b, 0x93, 0xd7, 0x84, 0x3b, 0x93, 0xe5, 0x5f, 0xfe, 0xf2, 0x64, - 0xf9, 0xe3, 0x7d, 0xc3, 0x3d, 0xe8, 0xee, 0x96, 0x34, 0xab, 0xbd, 0xe2, 0x37, 0xb5, 0xbe, 0x1b, - 0xfc, 0x5e, 0xe9, 0x1c, 0xee, 0xaf, 0xf4, 0xeb, 0xa8, 0xd4, 0x3c, 0x36, 0x1b, 0xf8, 0xa5, 0xec, - 0x4b, 0x5c, 0xcf, 0x64, 0x05, 0x31, 0xb5, 0x9e, 0xc9, 0xa6, 0xc4, 0xb4, 0xf4, 0x93, 0x14, 0x14, - 0x64, 0xec, 0x74, 0x2c, 0xd3, 0xc1, 0xbc, 0xe4, 0xef, 0x41, 0xda, 0x3d, 0x36, 0x69, 0xc9, 0xf3, - 0x0f, 0x96, 0x4a, 0x03, 0x9d, 0xaa, 0xd4, 0xb4, 0x55, 0xd3, 0x51, 0x35, 0x52, 0x7d, 0x99, 0x64, - 0x45, 0x1f, 0x40, 0xde, 0xc6, 0x4e, 0xb7, 0x8d, 0xa9, 0x22, 0x69, 0xa5, 0xf2, 0x0f, 0x2e, 0xc7, - 0x70, 0x36, 0x3a, 0xaa, 0x29, 0x03, 0xcb, 0x4b, 0x7e, 0xa3, 0x06, 0xcc, 0x72, 0x4e, 0x1b, 0xab, - 0x8e, 0x65, 0x2e, 0x4c, 0x5f, 0x13, 0xee, 0x14, 0x1e, 0x94, 0x62, 0x78, 0xa3, 0xa5, 0x24, 0x8f, - 0xdd, 0x36, 0x96, 0x29, 0x97, 0x3c, 0x63, 0x87, 0x9e, 0xd0, 0x15, 0xc8, 0x9a, 0xdd, 0x36, 0xd1, - 0xaf, 0x43, 0xb5, 0x97, 0x96, 0xa7, 0xcd, 0x6e, 0x7b, 0x03, 0xf7, 0x1c, 0x74, 0x15, 0x72, 0x24, - 0x69, 0xb7, 0xe7, 0x62, 0x67, 0x21, 0x4b, 0xd3, 0x48, 0xde, 0x32, 0x79, 0x96, 0x3e, 0x81, 0x99, - 0xb0, 0x54, 0x84, 0xa0, 0x20, 0x57, 0x1b, 0x3b, 0x9b, 0x55, 0x65, 0x67, 0x6b, 0x63, 0xeb, 0xe9, - 0x8b, 0x2d, 0x71, 0x02, 0x5d, 0x00, 0x91, 0xd3, 0x36, 0xaa, 0x9f, 0x2a, 0x4f, 0xea, 0x9b, 0xf5, - 0xa6, 0x28, 0x2c, 0x66, 0xbe, 0xf7, 0xbb, 0x4b, 0x13, 0xeb, 0x99, 0xec, 0x94, 0x38, 0x2d, 0xfd, - 0xae, 0x00, 0xf0, 0x18, 0xbb, 0xbc, 0x37, 0xa0, 0x32, 0x4c, 0x1d, 0xd0, 0x12, 0x2f, 0x08, 0x54, - 0x2d, 0xd7, 0x62, 0xab, 0x16, 0xea, 0x39, 0xe5, 0xec, 0x8f, 0x4e, 0x96, 0x27, 0x7e, 0x7a, 0xb2, - 0x2c, 0xc8, 0x9c, 0x13, 0x3d, 0x83, 0xfc, 0x21, 0xee, 0x29, 0x7c, 0x5c, 0x2e, 0xa4, 0xa8, 0x8e, - 0xde, 0x0b, 0x09, 0x3a, 0x3c, 0x2a, 0x79, 0x43, 0xb4, 0x14, 0x1a, 0xce, 0x25, 0xc2, 0x51, 0x6a, - 0xb8, 0x36, 0x36, 0xf7, 0xdd, 0x03, 0x19, 0x0e, 0x71, 0xef, 0x09, 0x93, 0x21, 0xfd, 0xa1, 0x00, - 0x79, 0x5a, 0x4a, 0xa6, 0x54, 0x54, 0xe9, 0x2b, 0xe6, 0xf5, 0x33, 0x5b, 0x20, 0xa6, 0x9c, 0x25, - 0x98, 0x3c, 0x52, 0x5b, 0x5d, 0x4c, 0x4b, 0x98, 0x7f, 0xb0, 0x10, 0x23, 0xe3, 0x39, 0x49, 0x97, - 0x59, 0x36, 0xf4, 0x11, 0xcc, 0x18, 0xa6, 0x8b, 0x4d, 0x57, 0x61, 0x6c, 0xe9, 0x33, 0xd8, 0xf2, - 0x2c, 0x37, 0x7d, 0x90, 0xfe, 0xa9, 0x00, 0xb0, 0xdd, 0x4d, 0x54, 0xcf, 0xdf, 0x1c, 0xb3, 0xfc, - 0xe5, 0x0c, 0x61, 0xf5, 0x6a, 0x71, 0x09, 0xa6, 0x0c, 0xb3, 0x65, 0x98, 0xac, 0xfc, 0x59, 0x99, - 0x3f, 0xa1, 0x0b, 0x30, 0xb9, 0xdb, 0x32, 0x4c, 0x9d, 0x8e, 0x87, 0xac, 0xcc, 0x1e, 0x24, 0x19, - 0xf2, 0xb4, 0xd4, 0x09, 0xea, 0x5d, 0x3a, 0x49, 0xc1, 0xc5, 0x8a, 0x65, 0xea, 0x06, 0x19, 0x92, - 0x6a, 0xeb, 0x6b, 0xa1, 0x95, 0x75, 0xb8, 0xa0, 0xe3, 0x8e, 0x8d, 0x35, 0xd5, 0xc5, 0xba, 0x82, - 0x8f, 0x3b, 0x63, 0xb6, 0x31, 0x0a, 0xb8, 0xaa, 0xc7, 0x1d, 0x4a, 0x23, 0xa3, 0x96, 0x08, 0x60, - 0xa3, 0x76, 0x8a, 0x98, 0x4c, 0x39, 0x8b, 0x8f, 0x3b, 0x74, 0xd4, 0xc6, 0xab, 0x19, 0x7d, 0x13, - 0x2e, 0xab, 0xad, 0x96, 0xf5, 0x4a, 0x31, 0xf6, 0x14, 0xdd, 0xc2, 0x8e, 0x62, 0x5a, 0xae, 0x82, - 0x8f, 0x0d, 0xc7, 0xa5, 0x26, 0x21, 0x2b, 0xcf, 0xd3, 0xe4, 0xfa, 0xde, 0x9a, 0x85, 0x9d, 0x2d, - 0xcb, 0xad, 0x92, 0xa4, 0x50, 0x53, 0x4e, 0x87, 0x9b, 0x52, 0xfa, 0x55, 0xb8, 0xd4, 0xaf, 0xdf, - 0x24, 0xdb, 0xef, 0xc7, 0x02, 0x14, 0xea, 0xa6, 0xe1, 0x7e, 0x2d, 0x1a, 0xce, 0xd7, 0x67, 0x3a, - 0xac, 0xcf, 0x7b, 0x20, 0xee, 0xa9, 0x46, 0xeb, 0xa9, 0xd9, 0xb4, 0xda, 0xbb, 0x8e, 0x6b, 0x99, - 0xd8, 0xe1, 0x0a, 0x1f, 0xa0, 0x4b, 0xcf, 0xa1, 0xe8, 0xd7, 0x26, 0x49, 0x35, 0xb9, 0x20, 0xd6, - 0x4d, 0xcd, 0xc6, 0x6d, 0x6c, 0x26, 0xaa, 0xa7, 0xb7, 0x20, 0x67, 0x78, 0x72, 0xa9, 0xae, 0xd2, - 0x72, 0x40, 0x90, 0xba, 0x30, 0x17, 0x7a, 0x6b, 0x92, 0xe6, 0x92, 0x4c, 0x46, 0xf8, 0x95, 0x12, - 0xb4, 0x11, 0x99, 0x8c, 0xf0, 0x2b, 0x66, 0xde, 0x1a, 0x30, 0xbb, 0x86, 0x5b, 0xd8, 0xc5, 0x09, - 0xd6, 0x54, 0xda, 0x81, 0x82, 0x27, 0x34, 0xc9, 0x86, 0xf9, 0x4d, 0x01, 0x10, 0x97, 0xab, 0x9a, - 0xfb, 0x49, 0x96, 0x18, 0x2d, 0x13, 0xd7, 0xc2, 0xed, 0xda, 0x26, 0x9b, 0xce, 0x59, 0x9f, 0x04, - 0x46, 0xa2, 0x33, 0x7a, 0x30, 0x64, 0x33, 0xe1, 0x21, 0xcb, 0xdd, 0x9b, 0x57, 0x30, 0x1f, 0x29, - 0x58, 0xb2, 0xcd, 0x97, 0xa1, 0x65, 0x4a, 0x5d, 0x4b, 0x87, 0x7d, 0x38, 0x4a, 0x94, 0xbe, 0x10, - 0x60, 0xae, 0xd2, 0xc2, 0xaa, 0x9d, 0xb8, 0x46, 0xbe, 0x0d, 0x59, 0x1d, 0xab, 0x3a, 0xad, 0x32, - 0x1b, 0xd8, 0x6f, 0x87, 0xa4, 0x10, 0x4f, 0xb7, 0x74, 0xd0, 0xd2, 0x4a, 0x4d, 0xcf, 0x07, 0xe6, - 0xa3, 0xdb, 0x67, 0x92, 0x3e, 0x05, 0x14, 0x2e, 0x59, 0x92, 0x1d, 0xe1, 0xf7, 0x52, 0x80, 0x64, - 0x7c, 0x84, 0x6d, 0x37, 0xf1, 0x6a, 0xaf, 0x41, 0xde, 0x55, 0xed, 0x7d, 0xec, 0x2a, 0xc4, 0xbb, - 0x3f, 0x4f, 0xcd, 0x81, 0xf1, 0x11, 0x32, 0x6a, 0xc2, 0x6d, 0x6c, 0xaa, 0xbb, 0x2d, 0x4c, 0xa5, - 0x28, 0xbb, 0x56, 0xd7, 0xd4, 0x15, 0xc3, 0xc5, 0xb6, 0xea, 0x5a, 0xb6, 0x62, 0x75, 0x5c, 0xa3, - 0x6d, 0x7c, 0x4e, 0x1d, 0x7b, 0xde, 0xd5, 0x6e, 0xb0, 0xec, 0x84, 0xb9, 0x4c, 0x32, 0xd7, 0x79, - 0xde, 0xa7, 0xa1, 0xac, 0xa8, 0x04, 0xf3, 0xc6, 0xbe, 0x69, 0xd9, 0x58, 0xd9, 0xd7, 0x14, 0xf7, - 0xc0, 0xc6, 0xce, 0x81, 0xd5, 0xf2, 0x26, 0xa4, 0x39, 0x96, 0xf4, 0x58, 0x6b, 0x7a, 0x09, 0xd2, - 0x67, 0x30, 0x1f, 0xd1, 0x52, 0x92, 0x4d, 0xf0, 0x3f, 0x04, 0xc8, 0x37, 0x34, 0xd5, 0x4c, 0x52, - 0xf7, 0x9f, 0x40, 0xde, 0xd1, 0x54, 0x53, 0xd9, 0xb3, 0xec, 0xb6, 0xea, 0xd2, 0x7a, 0x15, 0x22, - 0xba, 0xf7, 0xfd, 0x7b, 0x4d, 0x35, 0x1f, 0xd1, 0x4c, 0x32, 0x38, 0xfe, 0xef, 0x7e, 0xff, 0x75, - 0xf2, 0xcd, 0xfd, 0x57, 0x36, 0xbc, 0xd7, 0x33, 0xd9, 0xb4, 0x98, 0x91, 0xfe, 0x42, 0x80, 0x19, - 0x56, 0xe5, 0x24, 0x87, 0xf7, 0xb7, 0x20, 0x63, 0x5b, 0xaf, 0xd8, 0xf0, 0xce, 0x3f, 0xb8, 0x1a, - 0x23, 0x62, 0x03, 0xf7, 0xc2, 0xf3, 0x27, 0xcd, 0x8e, 0xca, 0xc0, 0xbd, 0x54, 0x85, 0x72, 0xa7, - 0xc7, 0xe5, 0x06, 0xc6, 0x25, 0x13, 0x19, 0xb7, 0xa1, 0xb8, 0xab, 0xba, 0xda, 0x81, 0x62, 0xf3, - 0x42, 0x92, 0xb9, 0x36, 0x7d, 0x67, 0x46, 0x2e, 0x50, 0xb2, 0x57, 0x74, 0x87, 0xd4, 0x9c, 0x8d, - 0x37, 0x07, 0xff, 0x9c, 0xb5, 0xf9, 0xff, 0x11, 0xf8, 0x18, 0xf2, 0x6a, 0xfe, 0xf3, 0xd6, 0xf4, - 0x3f, 0x48, 0xc1, 0xe5, 0xca, 0x01, 0xd6, 0x0e, 0x2b, 0x96, 0xe9, 0x18, 0x8e, 0x4b, 0x74, 0x97, - 0x64, 0xfb, 0x5f, 0x85, 0xdc, 0x2b, 0xc3, 0x3d, 0x50, 0x74, 0x63, 0x6f, 0x8f, 0x5a, 0xdb, 0xac, - 0x9c, 0x25, 0x84, 0x35, 0x63, 0x6f, 0x0f, 0x3d, 0x84, 0x4c, 0xdb, 0xd2, 0x99, 0x33, 0x5f, 0x78, - 0xb0, 0x1c, 0x23, 0x9e, 0x16, 0xcd, 0xe9, 0xb6, 0x37, 0x2d, 0x1d, 0xcb, 0x34, 0x33, 0x5a, 0x02, - 0xd0, 0x08, 0xb5, 0x63, 0x19, 0xa6, 0xcb, 0x8d, 0x63, 0x88, 0x82, 0x6a, 0x90, 0x73, 0xb1, 0xdd, - 0x36, 0x4c, 0xd5, 0xc5, 0x0b, 0x93, 0x54, 0x79, 0xef, 0xc4, 0x16, 0xbc, 0xd3, 0x32, 0x34, 0x75, - 0x0d, 0x3b, 0x9a, 0x6d, 0x74, 0x5c, 0xcb, 0xe6, 0x5a, 0x0c, 0x98, 0xa5, 0xbf, 0x95, 0x81, 0x85, - 0x41, 0xdd, 0x24, 0xd9, 0x43, 0xb6, 0x61, 0xca, 0xc6, 0x4e, 0xb7, 0xe5, 0xf2, 0x3e, 0xf2, 0x60, - 0x98, 0x0a, 0x62, 0x4a, 0x40, 0x97, 0x2e, 0x5a, 0x2e, 0x2f, 0x36, 0x97, 0xb3, 0xf8, 0x2f, 0x05, - 0x98, 0x62, 0x09, 0xe8, 0x3e, 0x64, 0x6d, 0x32, 0x31, 0x28, 0x86, 0x4e, 0xcb, 0x98, 0x2e, 0x5f, - 0x3a, 0x3d, 0x59, 0x9e, 0xa6, 0x93, 0x45, 0x7d, 0xed, 0xcb, 0xe0, 0xa7, 0x3c, 0x4d, 0xf3, 0xd5, - 0x75, 0xd2, 0x5a, 0x8e, 0xab, 0xda, 0x2e, 0x5d, 0x54, 0x4a, 0x31, 0x84, 0x44, 0x09, 0x1b, 0xb8, - 0x87, 0xd6, 0x61, 0xca, 0x71, 0x55, 0xb7, 0xeb, 0xf0, 0xf6, 0x3a, 0x57, 0x61, 0x1b, 0x94, 0x53, - 0xe6, 0x12, 0x88, 0xbb, 0xa5, 0x63, 0x57, 0x35, 0x5a, 0xb4, 0x01, 0x73, 0x32, 0x7f, 0x92, 0x7e, - 0x4b, 0x80, 0x29, 0x96, 0x15, 0x5d, 0x86, 0x79, 0x79, 0x75, 0xeb, 0x71, 0x55, 0xa9, 0x6f, 0xad, - 0x55, 0x9b, 0x55, 0x79, 0xb3, 0xbe, 0xb5, 0xda, 0xac, 0x8a, 0x13, 0xe8, 0x12, 0x20, 0x2f, 0xa1, - 0xf2, 0x74, 0xab, 0x51, 0x6f, 0x34, 0xab, 0x5b, 0x4d, 0x51, 0xa0, 0x6b, 0x2a, 0x94, 0x1e, 0xa2, - 0xa6, 0xd0, 0x3b, 0x70, 0xad, 0x9f, 0xaa, 0x34, 0x9a, 0xab, 0xcd, 0x86, 0x52, 0x6d, 0x34, 0xeb, - 0x9b, 0xab, 0xcd, 0xea, 0x9a, 0x98, 0x1e, 0x91, 0x8b, 0xbc, 0x44, 0x96, 0xab, 0x95, 0xa6, 0x98, - 0x91, 0x5c, 0xb8, 0x28, 0x63, 0xcd, 0x6a, 0x77, 0xba, 0x2e, 0x26, 0xa5, 0x74, 0x92, 0x1c, 0x29, - 0x97, 0x61, 0x5a, 0xb7, 0x7b, 0x8a, 0xdd, 0x35, 0xf9, 0x38, 0x99, 0xd2, 0xed, 0x9e, 0xdc, 0x35, - 0xa5, 0x7f, 0x24, 0xc0, 0xa5, 0xfe, 0xd7, 0x26, 0xd9, 0x09, 0x9f, 0x41, 0x5e, 0xd5, 0x75, 0xac, - 0x2b, 0x3a, 0x6e, 0xb9, 0x2a, 0x77, 0x89, 0xee, 0x85, 0x24, 0xf1, 0xa5, 0xc0, 0x92, 0xbf, 0x14, - 0xb8, 0xf9, 0xbc, 0x52, 0xa1, 0x05, 0x59, 0x23, 0x1c, 0x9e, 0xf9, 0xa1, 0x42, 0x28, 0x45, 0xfa, - 0x41, 0x06, 0x66, 0xab, 0xa6, 0xde, 0x3c, 0x4e, 0x74, 0x2e, 0xb9, 0x04, 0x53, 0x9a, 0xd5, 0x6e, - 0x1b, 0xae, 0xa7, 0x20, 0xf6, 0x84, 0x7e, 0x31, 0xe4, 0xca, 0xa6, 0xc7, 0x70, 0xe8, 0x02, 0x27, - 0x16, 0xfd, 0x1a, 0x5c, 0x26, 0x56, 0xd3, 0x36, 0xd5, 0x96, 0xc2, 0xa4, 0x29, 0xae, 0x6d, 0xec, - 0xef, 0x63, 0x9b, 0x2f, 0x3f, 0xde, 0x89, 0x29, 0x67, 0x9d, 0x73, 0x54, 0x28, 0x43, 0x93, 0xe5, - 0x97, 0x2f, 0x1a, 0x71, 0x64, 0xf4, 0x31, 0x00, 0x99, 0x8a, 0xe8, 0x92, 0xa6, 0xc3, 0xed, 0xd1, - 0xb0, 0x35, 0x4d, 0xcf, 0x04, 0x11, 0x06, 0xf2, 0xec, 0xa0, 0x67, 0x20, 0x1a, 0xa6, 0xb2, 0xd7, - 0x32, 0xf6, 0x0f, 0x5c, 0xe5, 0x95, 0x6d, 0xb8, 0xd8, 0x59, 0x98, 0xa3, 0x32, 0xe2, 0x9a, 0xba, - 0xc1, 0x97, 0x66, 0xf5, 0x17, 0x24, 0x27, 0x97, 0x56, 0x30, 0xcc, 0x47, 0x94, 0x9f, 0x12, 0x1d, - 0xb4, 0x42, 0xa0, 0xd0, 0xcb, 0xae, 0x61, 0x63, 0xe5, 0x7e, 0x47, 0xa3, 0xeb, 0x20, 0xd9, 0x72, - 0xe1, 0xf4, 0x64, 0x19, 0x64, 0x46, 0xbe, 0xbf, 0x5d, 0x21, 0xd0, 0x88, 0xfd, 0xee, 0x68, 0x44, - 0xed, 0x1d, 0xcb, 0x70, 0x2c, 0x73, 0x21, 0xc7, 0xd4, 0xce, 0x9e, 0xd0, 0x5d, 0x10, 0xdd, 0x63, - 0x53, 0x39, 0xc0, 0xaa, 0xed, 0xee, 0x62, 0xd5, 0x25, 0xf3, 0x33, 0xd0, 0x1c, 0x45, 0xf7, 0xd8, - 0xac, 0x85, 0xc8, 0xeb, 0x99, 0xec, 0xb4, 0x98, 0x5d, 0xcf, 0x64, 0xb3, 0x62, 0x4e, 0xfa, 0x4f, - 0x02, 0x14, 0xbc, 0xbe, 0x91, 0x64, 0x37, 0xbe, 0x03, 0xa2, 0x65, 0x62, 0xa5, 0x73, 0xa0, 0x3a, - 0x98, 0xb7, 0x25, 0x9f, 0x1d, 0x0a, 0x96, 0x89, 0xb7, 0x09, 0x99, 0xb5, 0x0c, 0xda, 0x86, 0x39, - 0xc7, 0x55, 0xf7, 0x0d, 0x73, 0x5f, 0xf1, 0x97, 0xf8, 0xa9, 0x67, 0x31, 0x26, 0x12, 0x10, 0x39, - 0xb7, 0x4f, 0x8f, 0xb8, 0x14, 0x7f, 0x24, 0xc0, 0xdc, 0xaa, 0xde, 0x36, 0xcc, 0x46, 0xa7, 0x65, - 0x24, 0xba, 0xc0, 0xf0, 0x0e, 0xe4, 0x1c, 0x22, 0x33, 0xb0, 0xce, 0x01, 0x5c, 0xcc, 0xd2, 0x14, - 0x62, 0xa6, 0x9f, 0x40, 0x11, 0x1f, 0x77, 0x0c, 0xb6, 0xaf, 0xc0, 0x50, 0x4e, 0x66, 0xfc, 0xba, - 0x15, 0x02, 0x5e, 0x92, 0xc4, 0xeb, 0xf4, 0x29, 0xa0, 0x70, 0x95, 0x92, 0x04, 0x1a, 0x9f, 0xc2, - 0x3c, 0x15, 0xbd, 0x63, 0x3a, 0x09, 0xeb, 0x4b, 0xfa, 0x15, 0xb8, 0x10, 0x15, 0x9d, 0x64, 0xb9, - 0x5f, 0xf0, 0x56, 0xde, 0xc4, 0x76, 0xa2, 0x08, 0xd5, 0xd7, 0x35, 0x17, 0x9c, 0x64, 0x99, 0x7f, - 0x5d, 0x80, 0x2b, 0x54, 0x36, 0xdd, 0x7a, 0xd9, 0xc3, 0xf6, 0x13, 0xac, 0x3a, 0x89, 0xc2, 0xeb, - 0x1b, 0x30, 0xc5, 0x60, 0x32, 0xed, 0x9f, 0x93, 0xe5, 0x3c, 0x71, 0x33, 0x1a, 0xae, 0x65, 0x13, - 0x37, 0x83, 0x27, 0x49, 0x2a, 0x2c, 0xc6, 0x95, 0x22, 0xc9, 0x9a, 0xfe, 0x3d, 0x01, 0xe6, 0xb8, - 0x87, 0x47, 0xba, 0x72, 0xe5, 0x80, 0x38, 0x38, 0xa8, 0x0a, 0x79, 0x8d, 0xfe, 0x52, 0xdc, 0x5e, - 0x07, 0x53, 0xf9, 0x85, 0x51, 0xce, 0x21, 0x63, 0x6b, 0xf6, 0x3a, 0x98, 0x78, 0x98, 0xde, 0x6f, - 0xa2, 0xa8, 0x50, 0x25, 0x47, 0xba, 0x97, 0x74, 0x1c, 0xd1, 0xbc, 0x9e, 0x9f, 0xc6, 0x75, 0xf0, - 0x4f, 0xd2, 0x5c, 0x09, 0xec, 0x1d, 0x3c, 0x7b, 0xa2, 0x0e, 0xc5, 0x67, 0x70, 0x29, 0xb4, 0x74, - 0x1e, 0xae, 0x78, 0xea, 0x1c, 0x15, 0x0f, 0x2d, 0xbf, 0x07, 0x54, 0xf4, 0x29, 0x84, 0x16, 0xd8, - 0x15, 0x56, 0x27, 0x0f, 0xaa, 0x9c, 0x47, 0x1d, 0x73, 0x81, 0x14, 0x46, 0x77, 0x50, 0x05, 0xb2, - 0xf8, 0xb8, 0xa3, 0xe8, 0xd8, 0xd1, 0xb8, 0xe1, 0x92, 0xe2, 0x04, 0x92, 0xa2, 0x0c, 0x38, 0xef, - 0xd3, 0xf8, 0xb8, 0x43, 0x88, 0x68, 0x87, 0xcc, 0x9b, 0xde, 0xbc, 0x4e, 0x8b, 0xed, 0x9c, 0x8d, - 0x05, 0x82, 0x9e, 0xc2, 0xc5, 0x15, 0xfd, 0x29, 0x9d, 0x89, 0x90, 0x7e, 0x28, 0xc0, 0xd5, 0xd8, - 0x56, 0x4b, 0x72, 0x22, 0xfb, 0x18, 0x32, 0xb4, 0xf2, 0xa9, 0x73, 0x56, 0x9e, 0x72, 0x49, 0xdf, - 0x4b, 0xf1, 0x31, 0x2e, 0xe3, 0x96, 0x45, 0x14, 0x9b, 0xf8, 0x12, 0xda, 0x53, 0x98, 0x3d, 0xb2, - 0x5c, 0x6c, 0xfb, 0xcd, 0x9e, 0x3a, 0x77, 0xb3, 0xcf, 0x50, 0x01, 0x5e, 0x8b, 0x3f, 0x87, 0x39, - 0xd3, 0x32, 0x95, 0xa8, 0xd0, 0xf3, 0xf7, 0xa5, 0xa2, 0x69, 0x99, 0xcf, 0x43, 0x72, 0x7d, 0x3b, - 0xd3, 0xa7, 0x89, 0x24, 0xed, 0xcc, 0xf7, 0x05, 0x98, 0xf7, 0x3d, 0x9d, 0x84, 0xdd, 0xdd, 0x6f, - 0x41, 0xda, 0xb4, 0x5e, 0x9d, 0x67, 0x89, 0x92, 0xe4, 0x27, 0xb3, 0x5e, 0xb4, 0x44, 0x49, 0xd6, - 0xf7, 0x5f, 0xa5, 0x20, 0xf7, 0xb8, 0x92, 0x64, 0x2d, 0x3f, 0xe6, 0xcb, 0xdf, 0xac, 0xbd, 0xe3, - 0x7a, 0xbb, 0xff, 0xbe, 0xd2, 0xe3, 0xca, 0x06, 0xee, 0x79, 0xbd, 0x9d, 0x70, 0xa1, 0x55, 0xc8, - 0x45, 0x17, 0x4a, 0xc7, 0xd4, 0x54, 0xc0, 0xb5, 0x88, 0x61, 0x92, 0xca, 0xf5, 0x42, 0x2d, 0x84, - 0x98, 0x50, 0x0b, 0xf2, 0x1a, 0xdf, 0x53, 0x4c, 0x9d, 0xe7, 0x35, 0x21, 0x17, 0x71, 0x52, 0x9c, - 0x92, 0x9e, 0x01, 0x90, 0xea, 0x24, 0xd9, 0x24, 0xbf, 0x91, 0x86, 0xc2, 0x76, 0xd7, 0x39, 0x48, - 0xb8, 0xf7, 0x55, 0x00, 0x3a, 0x5d, 0xe7, 0x80, 0x8c, 0xc8, 0x63, 0x93, 0xd7, 0xf9, 0x8c, 0x28, - 0x0e, 0xaf, 0xd2, 0x8c, 0xaf, 0x79, 0x6c, 0xa2, 0x1a, 0x17, 0x82, 0x95, 0x20, 0x14, 0xe4, 0xc6, - 0x28, 0x64, 0xd9, 0x3c, 0x36, 0x37, 0xb1, 0x0f, 0x29, 0x99, 0x24, 0x4c, 0x24, 0x7d, 0x0c, 0xd3, - 0xe4, 0x41, 0x71, 0xad, 0xf3, 0x34, 0xf3, 0x14, 0xe1, 0x69, 0x5a, 0xe8, 0x23, 0xc8, 0x31, 0x6e, - 0x32, 0xfb, 0x4d, 0xd1, 0xd9, 0x2f, 0xae, 0x2e, 0x5c, 0x8d, 0x74, 0xde, 0xcb, 0x52, 0x56, 0x32, - 0xd7, 0x5d, 0x80, 0xc9, 0x3d, 0xcb, 0xd6, 0xbc, 0xcd, 0x5c, 0xf6, 0xc0, 0xda, 0x93, 0x41, 0x9a, - 0xf5, 0x4c, 0x36, 0x27, 0x82, 0xf4, 0x5b, 0x02, 0x14, 0xfd, 0x86, 0x48, 0x72, 0x42, 0xa8, 0x44, - 0xb4, 0x78, 0xfe, 0xa6, 0x20, 0x0a, 0x94, 0xfe, 0x1d, 0xf5, 0x88, 0x34, 0xeb, 0x88, 0xb6, 0x4c, - 0x92, 0x3d, 0xe5, 0x23, 0x16, 0xe8, 0x93, 0x3a, 0x6f, 0xeb, 0xd2, 0x98, 0x9f, 0xfb, 0x70, 0xc1, - 0x68, 0x13, 0x7b, 0x6e, 0xb8, 0xad, 0x1e, 0x87, 0x6d, 0x2e, 0xf6, 0x76, 0x8d, 0xe7, 0x83, 0xb4, - 0x8a, 0x97, 0x24, 0xfd, 0x1e, 0x5d, 0xad, 0x0e, 0x6a, 0x92, 0xa4, 0xaa, 0xeb, 0x30, 0x6b, 0x33, - 0xd1, 0xc4, 0xad, 0x39, 0xa7, 0xb6, 0x67, 0x7c, 0x56, 0xa2, 0xf0, 0xdf, 0x4e, 0x41, 0xf1, 0x59, - 0x17, 0xdb, 0xbd, 0xaf, 0x93, 0xba, 0x6f, 0x41, 0xf1, 0x95, 0x6a, 0xb8, 0xca, 0x9e, 0x65, 0x2b, - 0xdd, 0x8e, 0xae, 0xba, 0x5e, 0xb4, 0xc9, 0x2c, 0x21, 0x3f, 0xb2, 0xec, 0x1d, 0x4a, 0x44, 0x18, - 0xd0, 0xa1, 0x69, 0xbd, 0x32, 0x15, 0x42, 0xa6, 0x40, 0xf9, 0xd8, 0xe4, 0x4b, 0xc8, 0xe5, 0xf7, - 0xff, 0xe3, 0xc9, 0xf2, 0xc3, 0xb1, 0x62, 0xc8, 0x68, 0xbc, 0x5c, 0xb7, 0x6b, 0xe8, 0xa5, 0x9d, - 0x9d, 0xfa, 0x9a, 0x2c, 0x52, 0x91, 0x2f, 0x98, 0xc4, 0xe6, 0xb1, 0xe9, 0x48, 0x7f, 0x3f, 0x05, - 0x62, 0xa0, 0xa3, 0x24, 0x1b, 0xb2, 0x0a, 0xf9, 0x97, 0x5d, 0x6c, 0x1b, 0xaf, 0xd1, 0x8c, 0xc0, - 0x19, 0x89, 0xd9, 0xb9, 0x07, 0x73, 0xee, 0xb1, 0xa9, 0xb0, 0x08, 0x3f, 0x16, 0xf8, 0xe1, 0x05, - 0x2c, 0x14, 0x5d, 0x52, 0x66, 0x42, 0xa7, 0x41, 0x1f, 0x0e, 0xfa, 0x0c, 0x66, 0x22, 0xda, 0x4a, - 0xbf, 0x99, 0xb6, 0xf2, 0xaf, 0x42, 0x8a, 0xfa, 0x43, 0x01, 0x10, 0x55, 0x54, 0x9d, 0xad, 0xf1, - 0x7f, 0x5d, 0xfa, 0xd3, 0x1d, 0x10, 0x69, 0x3c, 0xa6, 0x62, 0xec, 0x29, 0x6d, 0xc3, 0x71, 0x0c, - 0x73, 0x9f, 0x77, 0xa8, 0x02, 0xa5, 0xd7, 0xf7, 0x36, 0x19, 0x55, 0xfa, 0xab, 0x30, 0x1f, 0xa9, - 0x40, 0x92, 0x8d, 0x7d, 0x1d, 0x66, 0xf6, 0xd8, 0x16, 0x2c, 0x15, 0xce, 0x97, 0x07, 0xf3, 0x94, - 0xc6, 0xde, 0x27, 0xfd, 0x59, 0x0a, 0x2e, 0xc8, 0xd8, 0xb1, 0x5a, 0x47, 0x38, 0x79, 0x15, 0xd6, - 0x80, 0xef, 0xbd, 0x28, 0xaf, 0xa5, 0xc9, 0x1c, 0x63, 0x66, 0xd3, 0x5c, 0x74, 0x8d, 0xfd, 0x9d, - 0xd1, 0x3d, 0x76, 0x70, 0x55, 0x9d, 0xaf, 0xd4, 0x65, 0x22, 0x2b, 0x75, 0x16, 0x14, 0xd9, 0xee, - 0xb1, 0xae, 0x38, 0xf8, 0xa5, 0xd9, 0x6d, 0x7b, 0x60, 0xa8, 0x34, 0xaa, 0x90, 0x75, 0xc6, 0xd2, - 0xc0, 0x2f, 0xb7, 0xba, 0x6d, 0xea, 0x3b, 0x97, 0x2f, 0x91, 0xf2, 0x9e, 0x9e, 0x2c, 0x17, 0x22, - 0x69, 0x8e, 0x5c, 0x30, 0xfc, 0x67, 0x22, 0x5d, 0xfa, 0x0e, 0x5c, 0xec, 0x53, 0x76, 0x92, 0x1e, - 0xcf, 0xbf, 0x48, 0xc3, 0x95, 0xa8, 0xf8, 0xa4, 0x21, 0xce, 0xd7, 0xbd, 0x41, 0x6b, 0x30, 0xdb, - 0x36, 0xcc, 0xd7, 0x5b, 0xbd, 0x9c, 0x69, 0x1b, 0xa6, 0x4f, 0x8b, 0xeb, 0x1a, 0x53, 0x5f, 0x69, - 0xd7, 0x50, 0x61, 0x31, 0xae, 0xed, 0x92, 0xec, 0x1f, 0xdf, 0x13, 0x60, 0x26, 0xe9, 0x65, 0xb9, - 0xd7, 0x8b, 0x82, 0x93, 0x9a, 0x30, 0xfb, 0x15, 0xac, 0xe3, 0xfd, 0xb6, 0x00, 0xa8, 0x69, 0x77, - 0x4d, 0x02, 0x6a, 0x9f, 0x58, 0xfb, 0x49, 0x56, 0xf3, 0x02, 0x4c, 0x1a, 0xa6, 0x8e, 0x8f, 0x69, - 0x35, 0x33, 0x32, 0x7b, 0x88, 0x6c, 0x25, 0xa6, 0xc7, 0xda, 0x4a, 0x94, 0x3e, 0x83, 0xf9, 0x48, - 0x11, 0x93, 0xac, 0xff, 0x9f, 0xa6, 0x60, 0x9e, 0x57, 0x24, 0xf1, 0x15, 0xcc, 0x6f, 0xc2, 0x64, - 0x8b, 0xc8, 0x1c, 0xd1, 0xce, 0xf4, 0x9d, 0x5e, 0x3b, 0xd3, 0xcc, 0xe8, 0x97, 0x00, 0x3a, 0x36, - 0x3e, 0x52, 0x18, 0x6b, 0x7a, 0x2c, 0xd6, 0x1c, 0xe1, 0xa0, 0x04, 0xf4, 0x85, 0x00, 0x45, 0x32, - 0xa0, 0x3b, 0xb6, 0xd5, 0xb1, 0x1c, 0xe2, 0xb3, 0x38, 0xe3, 0xc1, 0x9c, 0x67, 0xa7, 0x27, 0xcb, - 0xb3, 0x9b, 0x86, 0xb9, 0xcd, 0x19, 0x9b, 0x8d, 0xb1, 0x03, 0xfc, 0xbd, 0x63, 0x0e, 0xa5, 0x4a, - 0xcb, 0xd2, 0x0e, 0x83, 0xcd, 0x31, 0x62, 0x59, 0x7c, 0x71, 0x8e, 0xf4, 0x13, 0x01, 0x2e, 0x7c, - 0x65, 0xcb, 0xc5, 0xff, 0x3f, 0x94, 0x2d, 0x3d, 0x07, 0x91, 0xfe, 0xa8, 0x9b, 0x7b, 0x56, 0x92, - 0x0b, 0xf7, 0xff, 0x5b, 0x80, 0xb9, 0x90, 0xe0, 0x24, 0x1d, 0x9c, 0xd7, 0xd5, 0xd3, 0x2c, 0x0b, - 0x87, 0x71, 0xc7, 0x53, 0x95, 0x3c, 0xc3, 0xb3, 0xb3, 0x4e, 0x59, 0x82, 0x19, 0x4c, 0xac, 0x18, - 0x5d, 0xe2, 0xdd, 0x65, 0x87, 0x4c, 0xfa, 0x56, 0xf4, 0xf3, 0x7e, 0x86, 0x72, 0x4f, 0xfa, 0x15, - 0xe2, 0x61, 0x85, 0x07, 0x65, 0x92, 0x43, 0xfe, 0x9f, 0xa7, 0xe0, 0x52, 0x85, 0x6d, 0x81, 0x7b, - 0x31, 0x21, 0x49, 0x76, 0xc4, 0x05, 0x98, 0x3e, 0xc2, 0xb6, 0x63, 0x58, 0x6c, 0xb6, 0x9f, 0x95, - 0xbd, 0x47, 0xb4, 0x08, 0x59, 0xc7, 0x54, 0x3b, 0xce, 0x81, 0xe5, 0x6d, 0x27, 0xfa, 0xcf, 0x7e, - 0xfc, 0xca, 0xe4, 0xeb, 0xc7, 0xaf, 0x4c, 0x8d, 0x8e, 0x5f, 0x99, 0x7e, 0x83, 0xf8, 0x15, 0xbe, - 0x77, 0xf7, 0xef, 0x05, 0xb8, 0x3c, 0xa0, 0xb9, 0x24, 0x3b, 0xe7, 0x77, 0x21, 0xaf, 0x71, 0xc1, - 0x64, 0x7e, 0x60, 0x1b, 0x93, 0x75, 0x92, 0xed, 0x35, 0xa1, 0xcf, 0xe9, 0xc9, 0x32, 0x78, 0x45, - 0xad, 0xaf, 0x71, 0xe5, 0x90, 0xdf, 0xba, 0xf4, 0xdf, 0x01, 0x8a, 0xd5, 0x63, 0xb6, 0x28, 0xdf, - 0x60, 0x5e, 0x09, 0x7a, 0x04, 0xd9, 0x8e, 0x6d, 0x1d, 0x19, 0x5e, 0x35, 0x0a, 0x91, 0xe0, 0x05, - 0xaf, 0x1a, 0x7d, 0x5c, 0xdb, 0x9c, 0x43, 0xf6, 0x79, 0x51, 0x13, 0x72, 0x4f, 0x2c, 0x4d, 0x6d, - 0x3d, 0x32, 0x5a, 0xde, 0x40, 0x7b, 0xef, 0x6c, 0x41, 0x25, 0x9f, 0x67, 0x5b, 0x75, 0x0f, 0xbc, - 0x46, 0xf0, 0x89, 0xa8, 0x0e, 0xd9, 0x9a, 0xeb, 0x76, 0x48, 0x22, 0x1f, 0x7f, 0xb7, 0xc7, 0x10, - 0x4a, 0x58, 0xbc, 0x88, 0x5b, 0x8f, 0x1d, 0x35, 0x61, 0xee, 0x31, 0x3d, 0x3f, 0x56, 0x69, 0x59, - 0x5d, 0xbd, 0x62, 0x99, 0x7b, 0xc6, 0x3e, 0x9f, 0x26, 0x6e, 0x8d, 0x21, 0xf3, 0x71, 0xa5, 0x21, - 0x0f, 0x0a, 0x40, 0xab, 0x90, 0x6d, 0x3c, 0xe4, 0xc2, 0x98, 0x1b, 0x79, 0x73, 0x0c, 0x61, 0x8d, - 0x87, 0xb2, 0xcf, 0x86, 0xd6, 0x21, 0xbf, 0xfa, 0x79, 0xd7, 0xc6, 0x5c, 0xca, 0xd4, 0xd0, 0xc8, - 0x89, 0x7e, 0x29, 0x94, 0x4b, 0x0e, 0x33, 0xa3, 0xef, 0x40, 0x91, 0xe8, 0xad, 0xa9, 0xee, 0xb6, - 0x3c, 0x79, 0x59, 0x2a, 0xef, 0x1b, 0x63, 0xc8, 0xf3, 0x39, 0xbd, 0x2d, 0x81, 0x3e, 0x51, 0x8b, - 0x32, 0xcc, 0x46, 0xda, 0x0b, 0x21, 0xc8, 0x74, 0x48, 0xd3, 0x08, 0x34, 0x0c, 0x89, 0xfe, 0x46, - 0xef, 0xc2, 0xb4, 0x69, 0xe9, 0xd8, 0xeb, 0xcc, 0xb3, 0xe5, 0x0b, 0xa7, 0x27, 0xcb, 0x53, 0x5b, - 0x96, 0xce, 0x7c, 0x1d, 0xfe, 0x4b, 0x9e, 0x22, 0x99, 0xea, 0xfa, 0xe2, 0x35, 0xc8, 0x90, 0x26, - 0x22, 0x36, 0x64, 0x57, 0x75, 0xf0, 0x8e, 0x6d, 0x70, 0x69, 0xde, 0xe3, 0xe2, 0xef, 0xa7, 0x20, - 0xd5, 0x78, 0x48, 0xbc, 0xf9, 0xdd, 0xae, 0x76, 0x88, 0x5d, 0x9e, 0xce, 0x9f, 0xa8, 0x97, 0x6f, - 0xe3, 0x3d, 0x83, 0x39, 0x5d, 0x39, 0x99, 0x3f, 0xa1, 0xb7, 0x01, 0x54, 0x4d, 0xc3, 0x8e, 0xa3, - 0x78, 0x47, 0x00, 0x73, 0x72, 0x8e, 0x51, 0x36, 0x70, 0x8f, 0xb0, 0x39, 0x58, 0xb3, 0xb1, 0xeb, - 0xc5, 0x50, 0xb1, 0x27, 0xc2, 0xe6, 0xe2, 0x76, 0x47, 0x71, 0xad, 0x43, 0x6c, 0xd2, 0x26, 0xcd, - 0x11, 0xab, 0xd0, 0xee, 0x34, 0x09, 0x81, 0x18, 0x34, 0x6c, 0xea, 0x81, 0xf5, 0xc9, 0xc9, 0xfe, - 0x33, 0x11, 0x69, 0xe3, 0x7d, 0x83, 0x1f, 0xa0, 0xcb, 0xc9, 0xfc, 0x89, 0x68, 0x49, 0xed, 0xba, - 0x07, 0xb4, 0x25, 0x72, 0x32, 0xfd, 0x8d, 0x6e, 0x41, 0x91, 0x85, 0x5d, 0x2a, 0xd8, 0xd4, 0x14, - 0x6a, 0x07, 0x73, 0x34, 0x79, 0x96, 0x91, 0xab, 0xa6, 0x46, 0xac, 0x1e, 0x7a, 0x08, 0x9c, 0xa0, - 0x1c, 0xb6, 0x1d, 0xa2, 0x53, 0x20, 0xb9, 0xca, 0xc5, 0xd3, 0x93, 0xe5, 0x7c, 0x83, 0x26, 0x6c, - 0x6c, 0x36, 0xc8, 0x5c, 0xc2, 0x72, 0x6d, 0xb4, 0x9d, 0xba, 0xbe, 0xf8, 0x77, 0x04, 0x48, 0x3f, - 0xae, 0x34, 0xce, 0xad, 0x32, 0xaf, 0xa0, 0xe9, 0x50, 0x41, 0x6f, 0x43, 0x71, 0xd7, 0x68, 0xb5, - 0x0c, 0x73, 0x9f, 0xf8, 0x57, 0xdf, 0xc5, 0x9a, 0xa7, 0xb0, 0x02, 0x27, 0x6f, 0x33, 0x2a, 0xba, - 0x06, 0x79, 0xcd, 0xc6, 0x3a, 0x36, 0x5d, 0x43, 0x6d, 0x39, 0x5c, 0x73, 0x61, 0xd2, 0xe2, 0x5f, - 0x13, 0x60, 0x92, 0x76, 0x56, 0xf4, 0x16, 0xe4, 0x34, 0xcb, 0x74, 0x55, 0xc3, 0xe4, 0x56, 0x27, - 0x27, 0x07, 0x84, 0xa1, 0xc5, 0xbb, 0x0e, 0x33, 0xaa, 0xa6, 0x59, 0x5d, 0xd3, 0x55, 0x4c, 0xb5, - 0x8d, 0x79, 0x31, 0xf3, 0x9c, 0xb6, 0xa5, 0xb6, 0x31, 0x5a, 0x06, 0xef, 0xd1, 0x3f, 0xd9, 0x99, - 0x93, 0x81, 0x93, 0x36, 0x70, 0x6f, 0x11, 0x43, 0xce, 0xef, 0xd5, 0xa4, 0xbe, 0x5d, 0xc7, 0x2f, - 0x01, 0xfd, 0x8d, 0xde, 0x83, 0x0b, 0x2f, 0xbb, 0x6a, 0xcb, 0xd8, 0xa3, 0x8b, 0x5f, 0x34, 0x4a, - 0x9d, 0xbe, 0x8c, 0x15, 0x05, 0xf9, 0x69, 0x54, 0x02, 0x7d, 0xa7, 0x37, 0x08, 0xd2, 0xc1, 0x20, - 0x60, 0x21, 0x3b, 0x52, 0x0f, 0xe6, 0x64, 0xec, 0xda, 0xbd, 0x26, 0x3b, 0xec, 0x5a, 0x3d, 0xc2, - 0xa6, 0x4b, 0xea, 0x6e, 0x75, 0x30, 0x0b, 0x12, 0xf1, 0xea, 0xee, 0x13, 0xd0, 0x4d, 0x28, 0xa8, - 0x2e, 0xe9, 0x6e, 0xae, 0x62, 0x76, 0xdb, 0xbb, 0xd8, 0x66, 0xa1, 0x00, 0xf2, 0x2c, 0xa7, 0x6e, - 0x51, 0x22, 0x3f, 0x91, 0x61, 0xf7, 0x14, 0xba, 0x4e, 0xc4, 0x5f, 0x0d, 0x94, 0x54, 0x25, 0x14, - 0xe9, 0x2e, 0x5c, 0x24, 0xf5, 0xac, 0x9a, 0x9a, 0xdd, 0xeb, 0x10, 0xc9, 0x4f, 0xe9, 0x5f, 0x07, - 0x89, 0xa1, 0x7d, 0x1a, 0xba, 0x3d, 0x23, 0xfd, 0x78, 0x0a, 0x66, 0xab, 0xc7, 0x1d, 0xcb, 0x4e, - 0x74, 0x55, 0xa7, 0x0c, 0xd3, 0x1c, 0xf8, 0x8e, 0xd8, 0x8a, 0xed, 0xb3, 0x40, 0xde, 0x3e, 0x34, - 0x67, 0x44, 0x65, 0x00, 0x16, 0x50, 0x49, 0xe3, 0x70, 0xd2, 0xe7, 0xd8, 0x39, 0xa2, 0x6c, 0xf4, - 0xb0, 0xc1, 0x16, 0xe4, 0xdb, 0x47, 0x9a, 0xa6, 0xec, 0x19, 0x2d, 0x97, 0xc7, 0xa5, 0xc5, 0x87, - 0x50, 0x6f, 0x3e, 0xaf, 0x54, 0x1e, 0xd1, 0x4c, 0x2c, 0x9e, 0x2b, 0x78, 0x96, 0x81, 0x48, 0x60, - 0xbf, 0xd1, 0x37, 0x80, 0x1f, 0x7c, 0x51, 0x1c, 0xef, 0x18, 0x5b, 0x79, 0xf6, 0xf4, 0x64, 0x39, - 0x27, 0x53, 0x6a, 0xa3, 0xd1, 0x94, 0x73, 0x2c, 0x43, 0xc3, 0x71, 0xcf, 0x73, 0xd4, 0x61, 0x7a, - 0xfc, 0xa3, 0x0e, 0x7f, 0x53, 0x80, 0x4b, 0x5c, 0x47, 0xca, 0x2e, 0x0d, 0xef, 0x56, 0x5b, 0x86, - 0xdb, 0x53, 0x0e, 0x8f, 0x16, 0xb2, 0xd4, 0xe5, 0xf9, 0xc5, 0x58, 0x5d, 0x87, 0x9a, 0xb8, 0xe4, - 0x69, 0xbc, 0xf7, 0x84, 0x33, 0x6f, 0x1c, 0x55, 0x4d, 0xd7, 0xee, 0x95, 0x2f, 0x9f, 0x9e, 0x2c, - 0xcf, 0x0f, 0xa6, 0x3e, 0x97, 0xe7, 0x9d, 0x41, 0x16, 0x54, 0x03, 0xc0, 0x7e, 0x17, 0xa3, 0x16, - 0x2c, 0x7e, 0xea, 0x8a, 0xed, 0x8b, 0x72, 0x88, 0x17, 0xdd, 0x01, 0x91, 0x1f, 0x2d, 0xd9, 0x33, - 0x5a, 0x58, 0x71, 0x8c, 0xcf, 0x31, 0xb5, 0x75, 0x69, 0xb9, 0xc0, 0xe8, 0x44, 0x44, 0xc3, 0xf8, - 0x1c, 0xa3, 0xfb, 0x70, 0x31, 0x68, 0x01, 0x65, 0x17, 0xb7, 0xac, 0x57, 0x2c, 0x7b, 0x9e, 0x66, - 0x47, 0xbe, 0xf6, 0xcb, 0x24, 0x89, 0xb0, 0x2c, 0x7e, 0x17, 0x16, 0x86, 0x55, 0x38, 0x3c, 0x20, - 0x72, 0x6c, 0xbf, 0xf2, 0x83, 0xe8, 0x62, 0xc5, 0x18, 0x1d, 0x97, 0x2f, 0x58, 0x7c, 0x98, 0xfa, - 0x40, 0x90, 0xfe, 0x61, 0x0a, 0x66, 0xcb, 0xdd, 0xd6, 0xe1, 0xd3, 0x4e, 0x83, 0x1d, 0xcb, 0x47, - 0x57, 0x21, 0xa7, 0xab, 0xae, 0xca, 0x0a, 0x29, 0xb0, 0x23, 0x66, 0x84, 0x40, 0x6b, 0x73, 0x1b, - 0x8a, 0xa1, 0x58, 0x10, 0x1e, 0xf1, 0x4e, 0xab, 0x1d, 0x90, 0x69, 0x50, 0xfa, 0x07, 0xb0, 0x10, - 0xca, 0x48, 0x57, 0x16, 0x14, 0x6c, 0xba, 0xb6, 0x81, 0xd9, 0xea, 0x58, 0x5a, 0x0e, 0x05, 0xac, - 0xd4, 0x49, 0x72, 0x95, 0xa5, 0xa2, 0x26, 0xcc, 0x90, 0x8c, 0x3d, 0x85, 0x5a, 0x41, 0x6f, 0xf5, - 0xf2, 0x7e, 0x4c, 0xb5, 0x22, 0xe5, 0x2e, 0x51, 0xfd, 0x54, 0x28, 0x0f, 0xfd, 0x29, 0xe7, 0x71, - 0x40, 0x59, 0xfc, 0x04, 0xc4, 0xfe, 0x0c, 0x61, 0x5d, 0x66, 0x98, 0x2e, 0x2f, 0x84, 0x75, 0x99, - 0x0e, 0xe9, 0x69, 0x3d, 0x93, 0xcd, 0x88, 0x93, 0xd2, 0x4f, 0xd2, 0x50, 0xf0, 0x7a, 0x66, 0x92, - 0x6e, 0x75, 0x19, 0x26, 0x49, 0x3f, 0xf2, 0xc2, 0x2b, 0x6e, 0x8d, 0x18, 0x10, 0x3c, 0xc6, 0x9a, - 0xf4, 0x2f, 0x0f, 0x01, 0x52, 0xd6, 0x24, 0xcc, 0xcf, 0xe2, 0x9f, 0x0b, 0x90, 0xa1, 0x9e, 0xec, - 0x7d, 0xc8, 0xd0, 0x73, 0xf9, 0xc2, 0xc8, 0x73, 0xf9, 0xde, 0xf6, 0x3c, 0xc9, 0xea, 0x4f, 0x2c, - 0xa9, 0x90, 0x77, 0x55, 0xa6, 0xf1, 0x3d, 0x96, 0xed, 0x62, 0x9d, 0x7b, 0x8a, 0xd7, 0xce, 0x6a, - 0x47, 0xcf, 0x13, 0xf6, 0xf8, 0xd0, 0x15, 0x48, 0x13, 0xdb, 0x35, 0xcd, 0xb6, 0xea, 0x4f, 0x4f, - 0x96, 0xd3, 0xc4, 0x6a, 0x11, 0x1a, 0x5a, 0x81, 0x7c, 0xd4, 0x9a, 0x10, 0x67, 0x83, 0x9a, 0xc3, - 0x90, 0x25, 0x80, 0x96, 0x3f, 0x84, 0x18, 0x4a, 0x62, 0x6d, 0xc9, 0x37, 0xe9, 0x7f, 0x5d, 0xe0, - 0x31, 0x89, 0x0d, 0x8d, 0xcc, 0x59, 0x76, 0x92, 0x93, 0xca, 0x5d, 0x10, 0x6d, 0xd5, 0xd4, 0xad, - 0xb6, 0xf1, 0x39, 0x66, 0xa8, 0xdc, 0xe1, 0xdb, 0x15, 0x45, 0x9f, 0x4e, 0xe1, 0xb3, 0x23, 0xfd, - 0x37, 0x81, 0xc7, 0x2f, 0xfa, 0xc5, 0x48, 0x76, 0x53, 0x39, 0xcf, 0x97, 0xf4, 0xcc, 0x3d, 0xcb, - 0x0b, 0xbf, 0x78, 0x6b, 0x58, 0xb0, 0x51, 0xdd, 0xdc, 0xb3, 0xbc, 0xed, 0x31, 0xdb, 0x23, 0x38, - 0x8b, 0xbf, 0x0c, 0x93, 0x34, 0xf9, 0x35, 0xfa, 0x86, 0x1f, 0x33, 0x9b, 0x12, 0xd3, 0xd2, 0x9f, - 0xa4, 0xe0, 0x1d, 0x5a, 0xd5, 0xe7, 0xd8, 0x36, 0xf6, 0x7a, 0xdb, 0xb6, 0xe5, 0x62, 0xcd, 0xc5, - 0x7a, 0xb0, 0x2a, 0x95, 0x60, 0x13, 0xe8, 0x90, 0xe3, 0xfb, 0x79, 0x86, 0xce, 0x6f, 0xce, 0x78, - 0xfc, 0x66, 0x68, 0x35, 0xcb, 0xf6, 0x01, 0xeb, 0x6b, 0x72, 0x96, 0x49, 0xae, 0xeb, 0x68, 0x15, - 0x72, 0x1d, 0xaf, 0x1a, 0xe7, 0x0a, 0x19, 0xf1, 0xb9, 0xd0, 0x06, 0x14, 0x79, 0x41, 0xd5, 0x96, - 0x71, 0x84, 0x15, 0xd5, 0x3d, 0xcf, 0x10, 0x9e, 0x65, 0xbc, 0xab, 0x84, 0x75, 0xd5, 0x95, 0xfe, - 0x76, 0x06, 0x6e, 0x9e, 0xa1, 0xe2, 0x24, 0xbb, 0xd7, 0x22, 0x64, 0x8f, 0xc8, 0x8b, 0x0c, 0x5e, - 0xfb, 0xac, 0xec, 0x3f, 0xa3, 0xdd, 0xc8, 0x3c, 0xb0, 0xa7, 0x1a, 0x2d, 0x32, 0x6f, 0xb0, 0x20, - 0xbd, 0xe1, 0x61, 0x40, 0xf1, 0x41, 0x6f, 0xa1, 0x19, 0xe3, 0x11, 0x15, 0x44, 0xb3, 0x39, 0xe8, - 0x7b, 0x02, 0x2c, 0xb2, 0x17, 0xb2, 0x48, 0xb1, 0xbe, 0xd7, 0x64, 0xe8, 0x6b, 0xd6, 0x62, 0x5e, - 0x33, 0x96, 0x8e, 0x4a, 0xa1, 0x77, 0xf1, 0x82, 0x2c, 0x84, 0xdf, 0x16, 0x2e, 0xca, 0xe2, 0x6f, - 0x0a, 0x90, 0x0f, 0x11, 0xd0, 0xad, 0x81, 0x73, 0x39, 0xf9, 0xd3, 0xb8, 0xc3, 0x38, 0x37, 0x07, - 0x0e, 0xe3, 0x94, 0xb3, 0x5f, 0x9e, 0x2c, 0x67, 0x64, 0x16, 0xef, 0xed, 0x1d, 0xcb, 0xb9, 0x1e, - 0x5c, 0x03, 0x93, 0xee, 0xcb, 0xe4, 0xdd, 0x03, 0x43, 0x61, 0x9d, 0xea, 0x6d, 0x23, 0x51, 0x58, - 0x47, 0x9e, 0xa4, 0x1f, 0xa4, 0x60, 0x6e, 0x55, 0xd7, 0x1b, 0x0d, 0x0a, 0x05, 0x92, 0x1c, 0x63, - 0x08, 0x32, 0xc4, 0x3f, 0xe0, 0x67, 0x88, 0xe8, 0x6f, 0xf4, 0x2e, 0x20, 0xdd, 0x70, 0xd8, 0x75, - 0x0a, 0xce, 0x81, 0xaa, 0x5b, 0xaf, 0x82, 0xdd, 0xe2, 0x39, 0x2f, 0xa5, 0xe1, 0x25, 0xa0, 0x06, - 0x50, 0xa7, 0x55, 0x71, 0x5c, 0xd5, 0x5f, 0x0d, 0xbf, 0x39, 0xd6, 0xa9, 0x14, 0xe6, 0xcd, 0xfa, - 0x8f, 0x72, 0x8e, 0xc8, 0xa1, 0x3f, 0x89, 0x8f, 0x66, 0x90, 0x46, 0x71, 0x15, 0xd5, 0xf1, 0xce, - 0x53, 0xb0, 0x8b, 0x1c, 0x0a, 0x8c, 0xbe, 0xea, 0xb0, 0x63, 0x12, 0x2c, 0x0c, 0x3b, 0x50, 0x4d, - 0x92, 0x6b, 0x99, 0xbf, 0x23, 0x40, 0x41, 0xc6, 0x7b, 0x36, 0x76, 0x0e, 0x92, 0xd4, 0xf9, 0x23, - 0x98, 0xb1, 0x99, 0x54, 0x65, 0xcf, 0xb6, 0xda, 0xe7, 0xb1, 0x15, 0x79, 0xce, 0xf8, 0xc8, 0xb6, - 0xda, 0xdc, 0x24, 0x3f, 0x87, 0xa2, 0x5f, 0xc6, 0x24, 0x2b, 0xff, 0x0f, 0xe8, 0x89, 0x4b, 0x26, - 0x38, 0xe9, 0x6d, 0xdb, 0x64, 0x35, 0x40, 0xd7, 0xb3, 0xc3, 0x05, 0x4d, 0x52, 0x0d, 0xff, 0x55, - 0x80, 0x42, 0xa3, 0xbb, 0xcb, 0xae, 0x09, 0x4a, 0x4e, 0x03, 0x55, 0xc8, 0xb5, 0xf0, 0x9e, 0xab, - 0xbc, 0x56, 0x00, 0x71, 0x96, 0xb0, 0xd2, 0xf0, 0xe9, 0xc7, 0x00, 0x36, 0x3d, 0x72, 0x44, 0xe5, - 0xa4, 0xcf, 0x29, 0x27, 0x47, 0x79, 0x09, 0x99, 0xcc, 0x3a, 0x45, 0xbf, 0x9a, 0x49, 0xce, 0x2f, - 0x2f, 0x22, 0xd6, 0x21, 0x7d, 0x1e, 0xeb, 0x30, 0xc7, 0x77, 0xaa, 0xe3, 0x2d, 0x44, 0x09, 0xe6, - 0xa9, 0x5b, 0xa6, 0xa8, 0x9d, 0x4e, 0xcb, 0xf0, 0x70, 0x0a, 0xb5, 0x3f, 0x19, 0x79, 0x8e, 0x26, - 0xad, 0xb2, 0x14, 0x8a, 0x50, 0xd0, 0x6f, 0x08, 0x30, 0xb3, 0x67, 0x63, 0xfc, 0x39, 0x56, 0xa8, - 0x49, 0x1e, 0x6f, 0x2b, 0x7e, 0x8d, 0x94, 0xe1, 0x8d, 0xb7, 0xea, 0xf2, 0xec, 0xc5, 0x0d, 0xf2, - 0x5e, 0xb4, 0x05, 0xa2, 0xd6, 0x62, 0x9b, 0x87, 0x7e, 0x58, 0xc0, 0xd4, 0xf8, 0x03, 0xa0, 0xc8, - 0x98, 0x83, 0xc8, 0x80, 0x67, 0x64, 0x30, 0xa9, 0xba, 0xc2, 0xaf, 0x66, 0xa3, 0xce, 0x76, 0x34, - 0x2c, 0x20, 0x7c, 0xf4, 0x3a, 0x74, 0xa3, 0x5b, 0x49, 0xc6, 0xaa, 0xce, 0x3d, 0x77, 0x32, 0xae, - 0xfc, 0x07, 0x3e, 0xae, 0x5e, 0xc0, 0x1c, 0xed, 0x37, 0x49, 0x9f, 0xa0, 0x94, 0xfe, 0x71, 0x1a, - 0x50, 0x58, 0xf2, 0x57, 0xd7, 0xdf, 0x52, 0xc9, 0xf5, 0xb7, 0x75, 0x90, 0x42, 0xce, 0x50, 0x4b, - 0x75, 0x5c, 0x85, 0xc5, 0x9f, 0x39, 0x4a, 0x07, 0xdb, 0x8a, 0x83, 0x35, 0x8b, 0x5f, 0xa2, 0x23, - 0xc8, 0x4b, 0x41, 0xce, 0x27, 0xaa, 0xe3, 0x3e, 0x63, 0xf9, 0xb6, 0xb1, 0xdd, 0xa0, 0xb9, 0xd0, - 0x43, 0xb8, 0xd4, 0x56, 0x8f, 0xe3, 0xf8, 0x27, 0x29, 0xff, 0x7c, 0x5b, 0x3d, 0x1e, 0x60, 0xfa, - 0x10, 0x16, 0xe3, 0x99, 0x14, 0x07, 0x7b, 0xfb, 0x53, 0x97, 0x62, 0x18, 0x1b, 0xd8, 0x45, 0xab, - 0x00, 0x01, 0x88, 0xe0, 0x73, 0xf4, 0x38, 0x18, 0x22, 0xe7, 0x63, 0x08, 0xe9, 0xfb, 0x02, 0x14, - 0x36, 0x8d, 0x7d, 0x5b, 0x4d, 0xf4, 0x8a, 0x1a, 0xf4, 0x61, 0x74, 0x43, 0x2f, 0xff, 0x60, 0x31, - 0x2e, 0x60, 0x83, 0xe5, 0xf0, 0x16, 0xed, 0x38, 0x03, 0x99, 0xfa, 0xfc, 0x12, 0x25, 0x69, 0xf3, - 0x35, 0x78, 0x9b, 0x86, 0xc0, 0xf1, 0xf8, 0x97, 0xaf, 0x04, 0xdd, 0x48, 0x7f, 0x20, 0xc0, 0xd2, - 0xb0, 0xb7, 0x24, 0x39, 0x20, 0x64, 0x7a, 0x59, 0x1f, 0x7d, 0x83, 0xe2, 0x8f, 0x88, 0x33, 0x2c, - 0x0d, 0xe2, 0x23, 0x01, 0xfc, 0xb2, 0x35, 0xe8, 0x35, 0x7e, 0xec, 0xb7, 0x23, 0xfd, 0xdb, 0x45, - 0x98, 0xe1, 0xf5, 0xdb, 0x31, 0x0d, 0xcb, 0x44, 0xf7, 0x21, 0xbd, 0xcf, 0xd7, 0xfe, 0xf3, 0xb1, - 0x4b, 0x9e, 0xc1, 0x0d, 0x79, 0xb5, 0x09, 0x99, 0xe4, 0x25, 0x2c, 0x9d, 0xae, 0x1b, 0x53, 0x9e, - 0x20, 0xc8, 0x3b, 0xcc, 0xd2, 0xe9, 0xba, 0xa8, 0x01, 0x45, 0x2d, 0xb8, 0x96, 0x4b, 0x21, 0xec, - 0xe9, 0xa1, 0xeb, 0x80, 0xb1, 0x17, 0xa4, 0xd5, 0x26, 0xe4, 0x82, 0x16, 0x49, 0x40, 0x95, 0xf0, - 0x6d, 0x50, 0x99, 0x81, 0x08, 0xb2, 0xe0, 0x2c, 0x71, 0xf4, 0x26, 0xaa, 0xda, 0x44, 0xe8, 0xd2, - 0x28, 0xf4, 0x21, 0x4c, 0xe9, 0xf4, 0xde, 0x21, 0x3e, 0xab, 0xc4, 0x75, 0x88, 0xc8, 0xf5, 0x4e, - 0xb5, 0x09, 0x99, 0x73, 0xa0, 0x75, 0x98, 0x61, 0xbf, 0x18, 0xe6, 0xe1, 0x73, 0xc1, 0xcd, 0xe1, - 0x12, 0x42, 0xde, 0x58, 0x6d, 0x42, 0xce, 0xeb, 0x01, 0x15, 0x3d, 0x86, 0xbc, 0xd6, 0xc2, 0xaa, - 0xcd, 0x45, 0xdd, 0x1a, 0x7a, 0xec, 0x6d, 0xe0, 0xae, 0xa2, 0xda, 0x84, 0x0c, 0x9a, 0x4f, 0x24, - 0x85, 0xb2, 0xe9, 0x95, 0x35, 0x5c, 0xd2, 0x7b, 0x43, 0x0b, 0x35, 0x78, 0xff, 0x4f, 0x8d, 0x7a, - 0x69, 0x3e, 0x15, 0x7d, 0x13, 0x32, 0x8e, 0xa6, 0x9a, 0x7c, 0x62, 0x5a, 0x1a, 0x72, 0xa7, 0x48, - 0xc0, 0x4c, 0x73, 0xa3, 0x8f, 0x18, 0x5c, 0x72, 0x8f, 0xbd, 0xc5, 0xde, 0x38, 0x9d, 0x46, 0xce, - 0xae, 0x13, 0x9d, 0x62, 0x4a, 0x20, 0x7a, 0x50, 0x09, 0x3e, 0x54, 0xe8, 0x81, 0x52, 0xba, 0xba, - 0x1b, 0xaf, 0x87, 0x81, 0x03, 0xc0, 0x35, 0x7a, 0x40, 0xde, 0x23, 0xa2, 0x4d, 0x98, 0x65, 0x82, - 0xba, 0xec, 0x6c, 0xea, 0xc2, 0xca, 0xd0, 0x6d, 0xdc, 0x98, 0xd3, 0xb1, 0xb5, 0x09, 0x79, 0x46, - 0x0d, 0x91, 0x83, 0x72, 0xb5, 0xb1, 0xbd, 0xcf, 0x96, 0x91, 0x47, 0x94, 0x2b, 0x1c, 0x1b, 0xe7, - 0x97, 0x8b, 0x12, 0xd1, 0xaf, 0xc1, 0x05, 0x26, 0xc8, 0xe5, 0x21, 0x3f, 0x3c, 0x72, 0xe4, 0xed, - 0xa1, 0x5b, 0xb0, 0x43, 0xcf, 0x93, 0xd6, 0x26, 0x64, 0xa4, 0x0e, 0x24, 0x22, 0x0d, 0x2e, 0xb2, - 0x37, 0xf0, 0x03, 0x89, 0x36, 0x3f, 0x43, 0xb7, 0x70, 0x83, 0xbe, 0xe2, 0xdd, 0x61, 0xaf, 0x88, - 0x3d, 0x27, 0x59, 0x9b, 0x90, 0xe7, 0xd5, 0xc1, 0xd4, 0xa0, 0x1a, 0x36, 0x3f, 0xfa, 0xc5, 0xbb, - 0xdb, 0xbb, 0xa3, 0xab, 0x11, 0x77, 0x64, 0xce, 0xaf, 0x46, 0x24, 0x91, 0x34, 0xa0, 0x7f, 0xf0, - 0x9d, 0x76, 0xa6, 0x99, 0xa1, 0x0d, 0x18, 0x73, 0x3e, 0x8c, 0x34, 0xe0, 0x41, 0x88, 0x8c, 0x4a, - 0x90, 0xda, 0xd7, 0x16, 0x66, 0x87, 0x4e, 0xa0, 0xfe, 0x19, 0xa8, 0xda, 0x84, 0x9c, 0xda, 0xd7, - 0xd0, 0x27, 0x90, 0x65, 0x07, 0x5a, 0x8e, 0xcd, 0x85, 0xc2, 0x50, 0x23, 0x1e, 0x3d, 0x16, 0x54, - 0x9b, 0x90, 0xe9, 0x19, 0x1a, 0xde, 0x91, 0xf9, 0x61, 0x05, 0x2a, 0xa2, 0x34, 0xe2, 0x1c, 0x6b, - 0xdf, 0x91, 0x11, 0xd2, 0x61, 0x6c, 0x9f, 0x88, 0xb6, 0xa1, 0xc0, 0x0d, 0xb8, 0x17, 0x7c, 0x2d, - 0x0e, 0x0d, 0x72, 0x88, 0x8b, 0xbf, 0xae, 0xd1, 0x85, 0xaa, 0x10, 0x9d, 0xb4, 0x5d, 0x54, 0x22, - 0x6f, 0xbb, 0xb9, 0xa1, 0x6d, 0x37, 0x34, 0x16, 0x98, 0xb4, 0x9d, 0x3d, 0x90, 0x88, 0xde, 0x87, - 0x49, 0x36, 0x4e, 0x10, 0x15, 0x19, 0x17, 0xb7, 0xd3, 0x37, 0x44, 0x58, 0x7e, 0x62, 0xbd, 0x5c, - 0x1e, 0xd3, 0xa8, 0xb4, 0xac, 0xfd, 0x85, 0xf9, 0xa1, 0xd6, 0x6b, 0x30, 0x3a, 0x93, 0x58, 0x2f, - 0x37, 0xa0, 0x92, 0x0e, 0x64, 0xb3, 0x14, 0x3e, 0xc4, 0x2e, 0x0c, 0xed, 0x40, 0x31, 0xa1, 0x8e, - 0x35, 0x7a, 0xda, 0x24, 0x20, 0xfb, 0x86, 0xd5, 0xc1, 0x0a, 0x35, 0x8a, 0x17, 0x47, 0x1b, 0xd6, + 0xab, 0x6a, 0x98, 0xb7, 0x2d, 0x55, 0x3b, 0xec, 0xee, 0xad, 0xaa, 0x5d, 0xa3, 0xdc, 0xb5, 0x2d, + 0xd7, 0x42, 0xf3, 0x9a, 0xa5, 0x1d, 0x51, 0x72, 0x99, 0x27, 0x2e, 0x5d, 0xc6, 0xb6, 0x6d, 0xd9, + 0x4e, 0x77, 0x6f, 0x95, 0xfd, 0x60, 0x39, 0x97, 0xee, 0x1d, 0x1d, 0xaf, 0x1e, 0x1d, 0x3b, 0xd8, + 0x3e, 0xc6, 0xf6, 0xaa, 0x66, 0x99, 0x5a, 0xcf, 0xb6, 0xb1, 0xa9, 0xf5, 0x57, 0xdb, 0x96, 0x76, + 0x44, 0xff, 0x18, 0xe6, 0x41, 0x5c, 0x5e, 0x1b, 0xab, 0xba, 0xd3, 0xeb, 0x74, 0x54, 0xbb, 0xbf, + 0x4a, 0xc5, 0xf2, 0x07, 0x9e, 0x17, 0x79, 0x85, 0xd2, 0x55, 0x57, 0xe5, 0xb4, 0x4b, 0x1e, 0x2d, + 0x52, 0x82, 0x2b, 0x1e, 0xb5, 0x83, 0x5d, 0x35, 0x94, 0xfb, 0x75, 0xc7, 0xb5, 0x6c, 0xf5, 0x00, + 0xaf, 0x62, 0xf3, 0xc0, 0x30, 0x31, 0xc9, 0x70, 0xac, 0x69, 0x3c, 0xf1, 0x8d, 0xd8, 0xc4, 0x87, + 0x3c, 0x75, 0xb1, 0xe7, 0x1a, 0xed, 0xd5, 0xc3, 0xb6, 0xb6, 0xea, 0x1a, 0x1d, 0xec, 0xb8, 0x6a, + 0xa7, 0xeb, 0x55, 0x81, 0xa6, 0xb8, 0xb6, 0xaa, 0x19, 0xe6, 0x81, 0xf7, 0xbf, 0xbb, 0xb7, 0x6a, + 0x63, 0xcd, 0xb2, 0x75, 0xac, 0x2b, 0x4e, 0x57, 0x35, 0xbd, 0xe2, 0x1e, 0x58, 0x07, 0x16, 0xfd, + 0xb9, 0x4a, 0x7e, 0x71, 0xea, 0xf2, 0x81, 0x65, 0x1d, 0xb4, 0xf1, 0x2a, 0x7d, 0xda, 0xeb, 0xed, + 0xaf, 0xea, 0x3d, 0x5b, 0x75, 0x0d, 0x8b, 0x73, 0x49, 0xff, 0x4c, 0x80, 0x82, 0x8c, 0x5f, 0xf4, + 0xb0, 0xe3, 0xd6, 0xb1, 0xaa, 0x63, 0x1b, 0xbd, 0x06, 0xe9, 0x23, 0xdc, 0x5f, 0x4c, 0x5f, 0x13, + 0xee, 0xcc, 0x55, 0x66, 0xbf, 0x38, 0x5d, 0x49, 0x6f, 0xe2, 0xbe, 0x4c, 0x68, 0xe8, 0x1a, 0xcc, + 0x62, 0x53, 0x57, 0x48, 0x72, 0x26, 0x9a, 0x3c, 0x83, 0x4d, 0x7d, 0x13, 0xf7, 0xd1, 0x77, 0x20, + 0xeb, 0x10, 0x69, 0xa6, 0x86, 0x17, 0xa7, 0xaf, 0x09, 0x77, 0xa6, 0x2b, 0xbf, 0xfc, 0xc5, 0xe9, + 0xca, 0x87, 0x07, 0x86, 0x7b, 0xd8, 0xdb, 0x2b, 0x6b, 0x56, 0x67, 0xd5, 0x6f, 0x6a, 0x7d, 0x2f, + 0xf8, 0xbd, 0xda, 0x3d, 0x3a, 0x58, 0x1d, 0xd4, 0x51, 0xb9, 0x75, 0x62, 0x36, 0xf1, 0x0b, 0xd9, + 0x97, 0xb8, 0x91, 0xc9, 0x0a, 0x62, 0x6a, 0x23, 0x93, 0x4d, 0x89, 0x69, 0xe9, 0x27, 0x29, 0x28, + 0xca, 0xd8, 0xe9, 0x5a, 0xa6, 0x83, 0x79, 0xc9, 0xdf, 0x81, 0xb4, 0x7b, 0x62, 0xd2, 0x92, 0xe7, + 0x1f, 0x2c, 0x97, 0x87, 0x3a, 0x55, 0xb9, 0x65, 0xab, 0xa6, 0xa3, 0x6a, 0xa4, 0xfa, 0x32, 0xc9, + 0x8a, 0xde, 0x83, 0xbc, 0x8d, 0x9d, 0x5e, 0x07, 0x53, 0x45, 0xd2, 0x4a, 0xe5, 0x1f, 0x5c, 0x8d, + 0xe1, 0x6c, 0x76, 0x55, 0x53, 0x06, 0x96, 0x97, 0xfc, 0x46, 0x4d, 0x28, 0x70, 0x4e, 0x1b, 0xab, + 0x8e, 0x65, 0x2e, 0xce, 0x5e, 0x13, 0xee, 0x14, 0x1f, 0x94, 0x63, 0x78, 0xa3, 0xa5, 0x24, 0x8f, + 0xbd, 0x0e, 0x96, 0x29, 0x97, 0x3c, 0x67, 0x87, 0x9e, 0xd0, 0x6b, 0x90, 0x35, 0x7b, 0x1d, 0xa2, + 0x5f, 0x87, 0x6a, 0x2f, 0x2d, 0xcf, 0x9a, 0xbd, 0xce, 0x26, 0xee, 0x3b, 0xe8, 0x75, 0xc8, 0x91, + 0xa4, 0xbd, 0xbe, 0x8b, 0x9d, 0xc5, 0x2c, 0x4d, 0x23, 0x79, 0x2b, 0xe4, 0x59, 0xfa, 0x08, 0xe6, + 0xc2, 0x52, 0x11, 0x82, 0xa2, 0x5c, 0x6b, 0xee, 0x6e, 0xd5, 0x94, 0xdd, 0xed, 0xcd, 0xed, 0xa7, + 0x1f, 0x6f, 0x8b, 0x53, 0xe8, 0x12, 0x88, 0x9c, 0xb6, 0x59, 0xfb, 0x44, 0x79, 0xd2, 0xd8, 0x6a, + 0xb4, 0x44, 0x61, 0x29, 0xf3, 0xbd, 0xdf, 0x5b, 0x9e, 0xda, 0xc8, 0x64, 0x67, 0xc4, 0x59, 0xe9, + 0xf7, 0x04, 0x80, 0xc7, 0xd8, 0xe5, 0xbd, 0x01, 0x55, 0x60, 0xe6, 0x90, 0x96, 0x78, 0x51, 0xa0, + 0x6a, 0xb9, 0x16, 0x5b, 0xb5, 0x50, 0xcf, 0xa9, 0x64, 0x7f, 0x74, 0xba, 0x32, 0xf5, 0xd3, 0xd3, + 0x15, 0x41, 0xe6, 0x9c, 0xe8, 0x19, 0xe4, 0x8f, 0x70, 0x5f, 0xe1, 0xe3, 0x72, 0x31, 0x45, 0x75, + 0xf4, 0x4e, 0x48, 0xd0, 0xd1, 0x71, 0xd9, 0x1b, 0xa2, 0xe5, 0xd0, 0x70, 0x2e, 0x13, 0x8e, 0x72, + 0xd3, 0xb5, 0xb1, 0x79, 0xe0, 0x1e, 0xca, 0x70, 0x84, 0xfb, 0x4f, 0x98, 0x0c, 0xe9, 0x0f, 0x05, + 0xc8, 0xd3, 0x52, 0x32, 0xa5, 0xa2, 0xea, 0x40, 0x31, 0xaf, 0x9f, 0xdb, 0x02, 0x31, 0xe5, 0x2c, + 0xc3, 0xf4, 0xb1, 0xda, 0xee, 0x61, 0x5a, 0xc2, 0xfc, 0x83, 0xc5, 0x18, 0x19, 0xcf, 0x49, 0xba, + 0xcc, 0xb2, 0xa1, 0x0f, 0x60, 0xce, 0x30, 0x5d, 0x6c, 0xba, 0x0a, 0x63, 0x4b, 0x9f, 0xc3, 0x96, + 0x67, 0xb9, 0xe9, 0x83, 0xf4, 0x4f, 0x05, 0x80, 0x9d, 0x5e, 0xa2, 0x7a, 0xfe, 0xe6, 0x84, 0xe5, + 0xaf, 0x64, 0x08, 0xab, 0x57, 0x8b, 0x2b, 0x30, 0x63, 0x98, 0x6d, 0xc3, 0x64, 0xe5, 0xcf, 0xca, + 0xfc, 0x09, 0x5d, 0x82, 0xe9, 0xbd, 0xb6, 0x61, 0xea, 0x74, 0x3c, 0x64, 0x65, 0xf6, 0x20, 0xc9, + 0x90, 0xa7, 0xa5, 0x4e, 0x50, 0xef, 0xd2, 0x69, 0x0a, 0x2e, 0x57, 0x2d, 0x53, 0x37, 0xc8, 0x90, + 0x54, 0xdb, 0x5f, 0x0b, 0xad, 0x6c, 0xc0, 0x25, 0x1d, 0x77, 0x6d, 0xac, 0xa9, 0x2e, 0xd6, 0x15, + 0x7c, 0xd2, 0x9d, 0xb0, 0x8d, 0x51, 0xc0, 0x55, 0x3b, 0xe9, 0x52, 0x1a, 0x19, 0xb5, 0x44, 0x00, + 0x1b, 0xb5, 0x33, 0xc4, 0x64, 0xca, 0x59, 0x7c, 0xd2, 0xa5, 0xa3, 0x36, 0x5e, 0xcd, 0xe8, 0x9b, + 0x70, 0x55, 0x6d, 0xb7, 0xad, 0x97, 0x8a, 0xb1, 0xaf, 0xe8, 0x16, 0x76, 0x14, 0xd3, 0x72, 0x15, + 0x7c, 0x62, 0x38, 0x2e, 0x35, 0x09, 0x59, 0x79, 0x81, 0x26, 0x37, 0xf6, 0xd7, 0x2d, 0xec, 0x6c, + 0x5b, 0x6e, 0x8d, 0x24, 0x85, 0x9a, 0x72, 0x36, 0xdc, 0x94, 0xd2, 0xaf, 0xc2, 0x95, 0x41, 0xfd, + 0x26, 0xd9, 0x7e, 0x3f, 0x16, 0xa0, 0xd8, 0x30, 0x0d, 0xf7, 0x6b, 0xd1, 0x70, 0xbe, 0x3e, 0xd3, + 0x61, 0x7d, 0xde, 0x03, 0x71, 0x5f, 0x35, 0xda, 0x4f, 0xcd, 0x96, 0xd5, 0xd9, 0x73, 0x5c, 0xcb, + 0xc4, 0x0e, 0x57, 0xf8, 0x10, 0x5d, 0x7a, 0x0e, 0x25, 0xbf, 0x36, 0x49, 0xaa, 0xc9, 0x05, 0xb1, + 0x61, 0x6a, 0x36, 0xee, 0x60, 0x33, 0x51, 0x3d, 0xbd, 0x01, 0x39, 0xc3, 0x93, 0x4b, 0x75, 0x95, + 0x96, 0x03, 0x82, 0xd4, 0x83, 0xf9, 0xd0, 0x5b, 0x93, 0x34, 0x97, 0x64, 0x32, 0xc2, 0x2f, 0x95, + 0xa0, 0x8d, 0xc8, 0x64, 0x84, 0x5f, 0x32, 0xf3, 0xd6, 0x84, 0xc2, 0x3a, 0x6e, 0x63, 0x17, 0x27, + 0x58, 0x53, 0x69, 0x17, 0x8a, 0x9e, 0xd0, 0x24, 0x1b, 0xe6, 0xb7, 0x04, 0x40, 0x5c, 0xae, 0x6a, + 0x1e, 0x24, 0x59, 0x62, 0xb4, 0x42, 0x5c, 0x0b, 0xb7, 0x67, 0x9b, 0x6c, 0x3a, 0x67, 0x7d, 0x12, + 0x18, 0x89, 0xce, 0xe8, 0xc1, 0x90, 0xcd, 0x84, 0x87, 0x2c, 0x77, 0x6f, 0x5e, 0xc2, 0x42, 0xa4, + 0x60, 0xc9, 0x36, 0x5f, 0x86, 0x96, 0x29, 0x75, 0x2d, 0x1d, 0xf6, 0xe1, 0x28, 0x51, 0xfa, 0x5c, + 0x80, 0xf9, 0x6a, 0x1b, 0xab, 0x76, 0xe2, 0x1a, 0xf9, 0x36, 0x64, 0x75, 0xac, 0xea, 0xb4, 0xca, + 0x6c, 0x60, 0xbf, 0x19, 0x92, 0x42, 0x3c, 0xdd, 0xf2, 0x61, 0x5b, 0x2b, 0xb7, 0x3c, 0x1f, 0x98, + 0x8f, 0x6e, 0x9f, 0x49, 0xfa, 0x04, 0x50, 0xb8, 0x64, 0x49, 0x76, 0x84, 0xdf, 0x4f, 0x01, 0x92, + 0xf1, 0x31, 0xb6, 0xdd, 0xc4, 0xab, 0xbd, 0x0e, 0x79, 0x57, 0xb5, 0x0f, 0xb0, 0xab, 0x10, 0xef, + 0xfe, 0x22, 0x35, 0x07, 0xc6, 0x47, 0xc8, 0xa8, 0x05, 0xb7, 0xb1, 0xa9, 0xee, 0xb5, 0x31, 0x95, + 0xa2, 0xec, 0x59, 0x3d, 0x53, 0x57, 0x0c, 0x17, 0xdb, 0xaa, 0x6b, 0xd9, 0x8a, 0xd5, 0x75, 0x8d, + 0x8e, 0xf1, 0x19, 0x75, 0xec, 0x79, 0x57, 0xbb, 0xc1, 0xb2, 0x13, 0xe6, 0x0a, 0xc9, 0xdc, 0xe0, + 0x79, 0x9f, 0x86, 0xb2, 0xa2, 0x32, 0x2c, 0x18, 0x07, 0xa6, 0x65, 0x63, 0xe5, 0x40, 0x53, 0xdc, + 0x43, 0x1b, 0x3b, 0x87, 0x56, 0xdb, 0x9b, 0x90, 0xe6, 0x59, 0xd2, 0x63, 0xad, 0xe5, 0x25, 0x48, + 0x9f, 0xc2, 0x42, 0x44, 0x4b, 0x49, 0x36, 0xc1, 0xff, 0x10, 0x20, 0xdf, 0xd4, 0x54, 0x33, 0x49, + 0xdd, 0x7f, 0x04, 0x79, 0x47, 0x53, 0x4d, 0x65, 0xdf, 0xb2, 0x3b, 0xaa, 0x4b, 0xeb, 0x55, 0x8c, + 0xe8, 0xde, 0xf7, 0xef, 0x35, 0xd5, 0x7c, 0x44, 0x33, 0xc9, 0xe0, 0xf8, 0xbf, 0x07, 0xfd, 0xd7, + 0xe9, 0x2f, 0xef, 0xbf, 0xb2, 0xe1, 0xbd, 0x91, 0xc9, 0xa6, 0xc5, 0x8c, 0xf4, 0x17, 0x02, 0xcc, + 0xb1, 0x2a, 0x27, 0x39, 0xbc, 0xbf, 0x05, 0x19, 0xdb, 0x7a, 0xc9, 0x86, 0x77, 0xfe, 0xc1, 0xeb, + 0x31, 0x22, 0x36, 0x71, 0x3f, 0x3c, 0x7f, 0xd2, 0xec, 0xa8, 0x02, 0xdc, 0x4b, 0x55, 0x28, 0x77, + 0x7a, 0x52, 0x6e, 0x60, 0x5c, 0x32, 0x91, 0x71, 0x1b, 0x4a, 0x7b, 0xaa, 0xab, 0x1d, 0x2a, 0x36, + 0x2f, 0x24, 0x99, 0x6b, 0xd3, 0x77, 0xe6, 0xe4, 0x22, 0x25, 0x7b, 0x45, 0x77, 0x48, 0xcd, 0xd9, + 0x78, 0x73, 0xf0, 0xcf, 0x59, 0x9b, 0xff, 0x1f, 0x81, 0x8f, 0x21, 0xaf, 0xe6, 0x3f, 0x6f, 0x4d, + 0xff, 0x83, 0x14, 0x5c, 0xad, 0x1e, 0x62, 0xed, 0xa8, 0x6a, 0x99, 0x8e, 0xe1, 0xb8, 0x44, 0x77, + 0x49, 0xb6, 0xff, 0xeb, 0x90, 0x7b, 0x69, 0xb8, 0x87, 0x8a, 0x6e, 0xec, 0xef, 0x53, 0x6b, 0x9b, + 0x95, 0xb3, 0x84, 0xb0, 0x6e, 0xec, 0xef, 0xa3, 0x87, 0x90, 0xe9, 0x58, 0x3a, 0x73, 0xe6, 0x8b, + 0x0f, 0x56, 0x62, 0xc4, 0xd3, 0xa2, 0x39, 0xbd, 0xce, 0x96, 0xa5, 0x63, 0x99, 0x66, 0x46, 0xcb, + 0x00, 0x1a, 0xa1, 0x76, 0x2d, 0xc3, 0x74, 0xb9, 0x71, 0x0c, 0x51, 0x50, 0x1d, 0x72, 0x2e, 0xb6, + 0x3b, 0x86, 0xa9, 0xba, 0x78, 0x71, 0x9a, 0x2a, 0xef, 0xad, 0xd8, 0x82, 0x77, 0xdb, 0x86, 0xa6, + 0xae, 0x63, 0x47, 0xb3, 0x8d, 0xae, 0x6b, 0xd9, 0x5c, 0x8b, 0x01, 0xb3, 0xf4, 0x37, 0x33, 0xb0, + 0x38, 0xac, 0x9b, 0x24, 0x7b, 0xc8, 0x0e, 0xcc, 0xd8, 0xd8, 0xe9, 0xb5, 0x5d, 0xde, 0x47, 0x1e, + 0x8c, 0x52, 0x41, 0x4c, 0x09, 0xe8, 0xd2, 0x45, 0xdb, 0xe5, 0xc5, 0xe6, 0x72, 0x96, 0xfe, 0xa5, + 0x00, 0x33, 0x2c, 0x01, 0xdd, 0x87, 0xac, 0x4d, 0x26, 0x06, 0xc5, 0xd0, 0x69, 0x19, 0xd3, 0x95, + 0x2b, 0x67, 0xa7, 0x2b, 0xb3, 0x74, 0xb2, 0x68, 0xac, 0x7f, 0x11, 0xfc, 0x94, 0x67, 0x69, 0xbe, + 0x86, 0x4e, 0x5a, 0xcb, 0x71, 0x55, 0xdb, 0xa5, 0x8b, 0x4a, 0x29, 0x86, 0x90, 0x28, 0x61, 0x13, + 0xf7, 0xd1, 0x06, 0xcc, 0x38, 0xae, 0xea, 0xf6, 0x1c, 0xde, 0x5e, 0x17, 0x2a, 0x6c, 0x93, 0x72, + 0xca, 0x5c, 0x02, 0x71, 0xb7, 0x74, 0xec, 0xaa, 0x46, 0x9b, 0x36, 0x60, 0x4e, 0xe6, 0x4f, 0xd2, + 0x6f, 0x0b, 0x30, 0xc3, 0xb2, 0xa2, 0xab, 0xb0, 0x20, 0xaf, 0x6d, 0x3f, 0xae, 0x29, 0x8d, 0xed, + 0xf5, 0x5a, 0xab, 0x26, 0x6f, 0x35, 0xb6, 0xd7, 0x5a, 0x35, 0x71, 0x0a, 0x5d, 0x01, 0xe4, 0x25, + 0x54, 0x9f, 0x6e, 0x37, 0x1b, 0xcd, 0x56, 0x6d, 0xbb, 0x25, 0x0a, 0x74, 0x4d, 0x85, 0xd2, 0x43, + 0xd4, 0x14, 0x7a, 0x0b, 0xae, 0x0d, 0x52, 0x95, 0x66, 0x6b, 0xad, 0xd5, 0x54, 0x6a, 0xcd, 0x56, + 0x63, 0x6b, 0xad, 0x55, 0x5b, 0x17, 0xd3, 0x63, 0x72, 0x91, 0x97, 0xc8, 0x72, 0xad, 0xda, 0x12, + 0x33, 0x92, 0x0b, 0x97, 0x65, 0xac, 0x59, 0x9d, 0x6e, 0xcf, 0xc5, 0xa4, 0x94, 0x4e, 0x92, 0x23, + 0xe5, 0x2a, 0xcc, 0xea, 0x76, 0x5f, 0xb1, 0x7b, 0x26, 0x1f, 0x27, 0x33, 0xba, 0xdd, 0x97, 0x7b, + 0xa6, 0xf4, 0x8f, 0x04, 0xb8, 0x32, 0xf8, 0xda, 0x24, 0x3b, 0xe1, 0x33, 0xc8, 0xab, 0xba, 0x8e, + 0x75, 0x45, 0xc7, 0x6d, 0x57, 0xe5, 0x2e, 0xd1, 0xbd, 0x90, 0x24, 0xbe, 0x14, 0x58, 0xf6, 0x97, + 0x02, 0xb7, 0x9e, 0x57, 0xab, 0xb4, 0x20, 0xeb, 0x84, 0xc3, 0x33, 0x3f, 0x54, 0x08, 0xa5, 0x48, + 0x3f, 0xc8, 0x40, 0xa1, 0x66, 0xea, 0xad, 0x93, 0x44, 0xe7, 0x92, 0x2b, 0x30, 0xa3, 0x59, 0x9d, + 0x8e, 0xe1, 0x7a, 0x0a, 0x62, 0x4f, 0xe8, 0x17, 0x43, 0xae, 0x6c, 0x7a, 0x02, 0x87, 0x2e, 0x70, + 0x62, 0xd1, 0xaf, 0xc1, 0x55, 0x62, 0x35, 0x6d, 0x53, 0x6d, 0x2b, 0x4c, 0x9a, 0xe2, 0xda, 0xc6, + 0xc1, 0x01, 0xb6, 0xf9, 0xf2, 0xe3, 0x9d, 0x98, 0x72, 0x36, 0x38, 0x47, 0x95, 0x32, 0xb4, 0x58, + 0x7e, 0xf9, 0xb2, 0x11, 0x47, 0x46, 0x1f, 0x02, 0x90, 0xa9, 0x88, 0x2e, 0x69, 0x3a, 0xdc, 0x1e, + 0x8d, 0x5a, 0xd3, 0xf4, 0x4c, 0x10, 0x61, 0x20, 0xcf, 0x0e, 0x7a, 0x06, 0xa2, 0x61, 0x2a, 0xfb, + 0x6d, 0xe3, 0xe0, 0xd0, 0x55, 0x5e, 0xda, 0x86, 0x8b, 0x9d, 0xc5, 0x79, 0x2a, 0x23, 0xae, 0xa9, + 0x9b, 0x7c, 0x69, 0x56, 0xff, 0x98, 0xe4, 0xe4, 0xd2, 0x8a, 0x86, 0xf9, 0x88, 0xf2, 0x53, 0xa2, + 0x83, 0x56, 0x09, 0x14, 0x7a, 0xd1, 0x33, 0x6c, 0xac, 0xdc, 0xef, 0x6a, 0x74, 0x1d, 0x24, 0x5b, + 0x29, 0x9e, 0x9d, 0xae, 0x80, 0xcc, 0xc8, 0xf7, 0x77, 0xaa, 0x04, 0x1a, 0xb1, 0xdf, 0x5d, 0x8d, + 0xa8, 0xbd, 0x6b, 0x19, 0x8e, 0x65, 0x2e, 0xe6, 0x98, 0xda, 0xd9, 0x13, 0xba, 0x0b, 0xa2, 0x7b, + 0x62, 0x2a, 0x87, 0x58, 0xb5, 0xdd, 0x3d, 0xac, 0xba, 0x64, 0x7e, 0x06, 0x9a, 0xa3, 0xe4, 0x9e, + 0x98, 0xf5, 0x10, 0x79, 0x23, 0x93, 0x9d, 0x15, 0xb3, 0x1b, 0x99, 0x6c, 0x56, 0xcc, 0x49, 0xff, + 0x49, 0x80, 0xa2, 0xd7, 0x37, 0x92, 0xec, 0xc6, 0x77, 0x40, 0xb4, 0x4c, 0xac, 0x74, 0x0f, 0x55, + 0x07, 0xf3, 0xb6, 0xe4, 0xb3, 0x43, 0xd1, 0x32, 0xf1, 0x0e, 0x21, 0xb3, 0x96, 0x41, 0x3b, 0x30, + 0xef, 0xb8, 0xea, 0x81, 0x61, 0x1e, 0x28, 0xfe, 0x12, 0x3f, 0xf5, 0x2c, 0x26, 0x44, 0x02, 0x22, + 0xe7, 0xf6, 0xe9, 0x11, 0x97, 0xe2, 0x8f, 0x04, 0x98, 0x5f, 0xd3, 0x3b, 0x86, 0xd9, 0xec, 0xb6, + 0x8d, 0x44, 0x17, 0x18, 0xde, 0x82, 0x9c, 0x43, 0x64, 0x06, 0xd6, 0x39, 0x80, 0x8b, 0x59, 0x9a, + 0x42, 0xcc, 0xf4, 0x13, 0x28, 0xe1, 0x93, 0xae, 0xc1, 0xf6, 0x15, 0x18, 0xca, 0xc9, 0x4c, 0x5e, + 0xb7, 0x62, 0xc0, 0x4b, 0x92, 0x78, 0x9d, 0x3e, 0x01, 0x14, 0xae, 0x52, 0x92, 0x40, 0xe3, 0x13, + 0x58, 0xa0, 0xa2, 0x77, 0x4d, 0x27, 0x61, 0x7d, 0x49, 0xbf, 0x02, 0x97, 0xa2, 0xa2, 0x93, 0x2c, + 0xf7, 0xc7, 0xbc, 0x95, 0xb7, 0xb0, 0x9d, 0x28, 0x42, 0xf5, 0x75, 0xcd, 0x05, 0x27, 0x59, 0xe6, + 0x5f, 0x17, 0xe0, 0x35, 0x2a, 0x9b, 0x6e, 0xbd, 0xec, 0x63, 0xfb, 0x09, 0x56, 0x9d, 0x44, 0xe1, + 0xf5, 0x0d, 0x98, 0x61, 0x30, 0x99, 0xf6, 0xcf, 0xe9, 0x4a, 0x9e, 0xb8, 0x19, 0x4d, 0xd7, 0xb2, + 0x89, 0x9b, 0xc1, 0x93, 0x24, 0x15, 0x96, 0xe2, 0x4a, 0x91, 0x64, 0x4d, 0xff, 0xae, 0x00, 0xf3, + 0xdc, 0xc3, 0x23, 0x5d, 0xb9, 0x7a, 0x48, 0x1c, 0x1c, 0x54, 0x83, 0xbc, 0x46, 0x7f, 0x29, 0x6e, + 0xbf, 0x8b, 0xa9, 0xfc, 0xe2, 0x38, 0xe7, 0x90, 0xb1, 0xb5, 0xfa, 0x5d, 0x4c, 0x3c, 0x4c, 0xef, + 0x37, 0x51, 0x54, 0xa8, 0x92, 0x63, 0xdd, 0x4b, 0x3a, 0x8e, 0x68, 0x5e, 0xcf, 0x4f, 0xe3, 0x3a, + 0xf8, 0x27, 0x69, 0xae, 0x04, 0xf6, 0x0e, 0x9e, 0x3d, 0x51, 0x87, 0xe2, 0x53, 0xb8, 0x12, 0x5a, + 0x3a, 0x0f, 0x57, 0x3c, 0x75, 0x81, 0x8a, 0x87, 0x96, 0xdf, 0x03, 0x2a, 0xfa, 0x04, 0x42, 0x0b, + 0xec, 0x0a, 0xab, 0x93, 0x07, 0x55, 0x2e, 0xa2, 0x8e, 0xf9, 0x40, 0x0a, 0xa3, 0x3b, 0xa8, 0x0a, + 0x59, 0x7c, 0xd2, 0x55, 0x74, 0xec, 0x68, 0xdc, 0x70, 0x49, 0x71, 0x02, 0x49, 0x51, 0x86, 0x9c, + 0xf7, 0x59, 0x7c, 0xd2, 0x25, 0x44, 0xb4, 0x4b, 0xe6, 0x4d, 0x6f, 0x5e, 0xa7, 0xc5, 0x76, 0xce, + 0xc7, 0x02, 0x41, 0x4f, 0xe1, 0xe2, 0x4a, 0xfe, 0x94, 0xce, 0x44, 0x48, 0x3f, 0x14, 0xe0, 0xf5, + 0xd8, 0x56, 0x4b, 0x72, 0x22, 0xfb, 0x10, 0x32, 0xb4, 0xf2, 0xa9, 0x0b, 0x56, 0x9e, 0x72, 0x49, + 0xdf, 0x4b, 0xf1, 0x31, 0x2e, 0xe3, 0xb6, 0x45, 0x14, 0x9b, 0xf8, 0x12, 0xda, 0x53, 0x28, 0x1c, + 0x5b, 0x2e, 0xb6, 0xfd, 0x66, 0x4f, 0x5d, 0xb8, 0xd9, 0xe7, 0xa8, 0x00, 0xaf, 0xc5, 0x9f, 0xc3, + 0xbc, 0x69, 0x99, 0x4a, 0x54, 0xe8, 0xc5, 0xfb, 0x52, 0xc9, 0xb4, 0xcc, 0xe7, 0x21, 0xb9, 0xbe, + 0x9d, 0x19, 0xd0, 0x44, 0x92, 0x76, 0xe6, 0xfb, 0x02, 0x2c, 0xf8, 0x9e, 0x4e, 0xc2, 0xee, 0xee, + 0xb7, 0x20, 0x6d, 0x5a, 0x2f, 0x2f, 0xb2, 0x44, 0x49, 0xf2, 0x93, 0x59, 0x2f, 0x5a, 0xa2, 0x24, + 0xeb, 0xfb, 0xaf, 0x52, 0x90, 0x7b, 0x5c, 0x4d, 0xb2, 0x96, 0x1f, 0xf2, 0xe5, 0x6f, 0xd6, 0xde, + 0x71, 0xbd, 0xdd, 0x7f, 0x5f, 0xf9, 0x71, 0x75, 0x13, 0xf7, 0xbd, 0xde, 0x4e, 0xb8, 0xd0, 0x1a, + 0xe4, 0xa2, 0x0b, 0xa5, 0x13, 0x6a, 0x2a, 0xe0, 0x5a, 0xc2, 0x30, 0x4d, 0xe5, 0x7a, 0xa1, 0x16, + 0x42, 0x4c, 0xa8, 0x05, 0x79, 0x8d, 0xef, 0x29, 0xa6, 0x2e, 0xf2, 0x9a, 0x90, 0x8b, 0x38, 0x2d, + 0xce, 0x48, 0xcf, 0x00, 0x48, 0x75, 0x92, 0x6c, 0x92, 0xdf, 0x48, 0x43, 0x71, 0xa7, 0xe7, 0x1c, + 0x26, 0xdc, 0xfb, 0xaa, 0x00, 0xdd, 0x9e, 0x73, 0x48, 0x46, 0xe4, 0x89, 0xc9, 0xeb, 0x7c, 0x4e, + 0x14, 0x87, 0x57, 0x69, 0xc6, 0xd7, 0x3a, 0x31, 0x51, 0x9d, 0x0b, 0xc1, 0x4a, 0x10, 0x0a, 0x72, + 0x63, 0x1c, 0xb2, 0x6c, 0x9d, 0x98, 0x5b, 0xd8, 0x87, 0x94, 0x4c, 0x12, 0x26, 0x92, 0x3e, 0x84, + 0x59, 0xf2, 0xa0, 0xb8, 0xd6, 0x45, 0x9a, 0x79, 0x86, 0xf0, 0xb4, 0x2c, 0xf4, 0x01, 0xe4, 0x18, + 0x37, 0x99, 0xfd, 0x66, 0xe8, 0xec, 0x17, 0x57, 0x17, 0xae, 0x46, 0x3a, 0xef, 0x65, 0x29, 0x2b, + 0x99, 0xeb, 0x2e, 0xc1, 0xf4, 0xbe, 0x65, 0x6b, 0xde, 0x66, 0x2e, 0x7b, 0x60, 0xed, 0xc9, 0x20, + 0xcd, 0x46, 0x26, 0x9b, 0x13, 0x41, 0xfa, 0x6d, 0x01, 0x4a, 0x7e, 0x43, 0x24, 0x39, 0x21, 0x54, + 0x23, 0x5a, 0xbc, 0x78, 0x53, 0x10, 0x05, 0x4a, 0xff, 0x8e, 0x7a, 0x44, 0x9a, 0x75, 0x4c, 0x5b, + 0x26, 0xc9, 0x9e, 0xf2, 0x01, 0x0b, 0xf4, 0x49, 0x5d, 0xb4, 0x75, 0x69, 0xcc, 0xcf, 0x7d, 0xb8, + 0x64, 0x74, 0x88, 0x3d, 0x37, 0xdc, 0x76, 0x9f, 0xc3, 0x36, 0x17, 0x7b, 0xbb, 0xc6, 0x0b, 0x41, + 0x5a, 0xd5, 0x4b, 0x92, 0x7e, 0x9f, 0xae, 0x56, 0x07, 0x35, 0x49, 0x52, 0xd5, 0x0d, 0x28, 0xd8, + 0x4c, 0x34, 0x71, 0x6b, 0x2e, 0xa8, 0xed, 0x39, 0x9f, 0x95, 0x28, 0xfc, 0x77, 0x52, 0x50, 0x7a, + 0xd6, 0xc3, 0x76, 0xff, 0xeb, 0xa4, 0xee, 0x5b, 0x50, 0x7a, 0xa9, 0x1a, 0xae, 0xb2, 0x6f, 0xd9, + 0x4a, 0xaf, 0xab, 0xab, 0xae, 0x17, 0x6d, 0x52, 0x20, 0xe4, 0x47, 0x96, 0xbd, 0x4b, 0x89, 0x08, + 0x03, 0x3a, 0x32, 0xad, 0x97, 0xa6, 0x42, 0xc8, 0x14, 0x28, 0x9f, 0x98, 0x7c, 0x09, 0xb9, 0xf2, + 0xee, 0x7f, 0x3c, 0x5d, 0x79, 0x38, 0x51, 0x0c, 0x19, 0x8d, 0x97, 0xeb, 0xf5, 0x0c, 0xbd, 0xbc, + 0xbb, 0xdb, 0x58, 0x97, 0x45, 0x2a, 0xf2, 0x63, 0x26, 0xb1, 0x75, 0x62, 0x3a, 0xd2, 0xdf, 0x4b, + 0x81, 0x18, 0xe8, 0x28, 0xc9, 0x86, 0xac, 0x41, 0xfe, 0x45, 0x0f, 0xdb, 0xc6, 0x2b, 0x34, 0x23, + 0x70, 0x46, 0x62, 0x76, 0xee, 0xc1, 0xbc, 0x7b, 0x62, 0x2a, 0x2c, 0xc2, 0x8f, 0x05, 0x7e, 0x78, + 0x01, 0x0b, 0x25, 0x97, 0x94, 0x99, 0xd0, 0x69, 0xd0, 0x87, 0x83, 0x3e, 0x85, 0xb9, 0x88, 0xb6, + 0xd2, 0x5f, 0x4e, 0x5b, 0xf9, 0x97, 0x21, 0x45, 0xfd, 0xa1, 0x00, 0x88, 0x2a, 0xaa, 0xc1, 0xd6, + 0xf8, 0xbf, 0x2e, 0xfd, 0xe9, 0x0e, 0x88, 0x34, 0x1e, 0x53, 0x31, 0xf6, 0x95, 0x8e, 0xe1, 0x38, + 0x86, 0x79, 0xc0, 0x3b, 0x54, 0x91, 0xd2, 0x1b, 0xfb, 0x5b, 0x8c, 0x2a, 0xfd, 0x55, 0x58, 0x88, + 0x54, 0x20, 0xc9, 0xc6, 0xbe, 0x0e, 0x73, 0xfb, 0x6c, 0x0b, 0x96, 0x0a, 0xe7, 0xcb, 0x83, 0x79, + 0x4a, 0x63, 0xef, 0x93, 0xfe, 0x2c, 0x05, 0x97, 0x64, 0xec, 0x58, 0xed, 0x63, 0x9c, 0xbc, 0x0a, + 0xeb, 0xc0, 0xf7, 0x5e, 0x94, 0x57, 0xd2, 0x64, 0x8e, 0x31, 0xb3, 0x69, 0x2e, 0xba, 0xc6, 0xfe, + 0xd6, 0xf8, 0x1e, 0x3b, 0xbc, 0xaa, 0xce, 0x57, 0xea, 0x32, 0x91, 0x95, 0x3a, 0x0b, 0x4a, 0x6c, + 0xf7, 0x58, 0x57, 0x1c, 0xfc, 0xc2, 0xec, 0x75, 0x3c, 0x30, 0x54, 0x1e, 0x57, 0xc8, 0x06, 0x63, + 0x69, 0xe2, 0x17, 0xdb, 0xbd, 0x0e, 0xf5, 0x9d, 0x2b, 0x57, 0x48, 0x79, 0xcf, 0x4e, 0x57, 0x8a, + 0x91, 0x34, 0x47, 0x2e, 0x1a, 0xfe, 0x33, 0x91, 0x2e, 0x7d, 0x07, 0x2e, 0x0f, 0x28, 0x3b, 0x49, + 0x8f, 0xe7, 0x5f, 0xa4, 0xe1, 0xb5, 0xa8, 0xf8, 0xa4, 0x21, 0xce, 0xd7, 0xbd, 0x41, 0xeb, 0x50, + 0xe8, 0x18, 0xe6, 0xab, 0xad, 0x5e, 0xce, 0x75, 0x0c, 0xd3, 0xa7, 0xc5, 0x75, 0x8d, 0x99, 0xaf, + 0xb4, 0x6b, 0xa8, 0xb0, 0x14, 0xd7, 0x76, 0x49, 0xf6, 0x8f, 0xef, 0x09, 0x30, 0x97, 0xf4, 0xb2, + 0xdc, 0xab, 0x45, 0xc1, 0x49, 0x2d, 0x28, 0x7c, 0x05, 0xeb, 0x78, 0xbf, 0x23, 0x00, 0x6a, 0xd9, + 0x3d, 0x93, 0x80, 0xda, 0x27, 0xd6, 0x41, 0x92, 0xd5, 0xbc, 0x04, 0xd3, 0x86, 0xa9, 0xe3, 0x13, + 0x5a, 0xcd, 0x8c, 0xcc, 0x1e, 0x22, 0x5b, 0x89, 0xe9, 0x89, 0xb6, 0x12, 0xa5, 0x4f, 0x61, 0x21, + 0x52, 0xc4, 0x24, 0xeb, 0xff, 0xa7, 0x29, 0x58, 0xe0, 0x15, 0x49, 0x7c, 0x05, 0xf3, 0x9b, 0x30, + 0xdd, 0x26, 0x32, 0xc7, 0xb4, 0x33, 0x7d, 0xa7, 0xd7, 0xce, 0x34, 0x33, 0xfa, 0x25, 0x80, 0xae, + 0x8d, 0x8f, 0x15, 0xc6, 0x9a, 0x9e, 0x88, 0x35, 0x47, 0x38, 0x28, 0x01, 0x7d, 0x2e, 0x40, 0x89, + 0x0c, 0xe8, 0xae, 0x6d, 0x75, 0x2d, 0x87, 0xf8, 0x2c, 0xce, 0x64, 0x30, 0xe7, 0xd9, 0xd9, 0xe9, + 0x4a, 0x61, 0xcb, 0x30, 0x77, 0x38, 0x63, 0xab, 0x39, 0x71, 0x80, 0xbf, 0x77, 0xcc, 0xa1, 0x5c, + 0x6d, 0x5b, 0xda, 0x51, 0xb0, 0x39, 0x46, 0x2c, 0x8b, 0x2f, 0xce, 0x91, 0x7e, 0x22, 0xc0, 0xa5, + 0xaf, 0x6c, 0xb9, 0xf8, 0xff, 0x87, 0xb2, 0xa5, 0xe7, 0x20, 0xd2, 0x1f, 0x0d, 0x73, 0xdf, 0x4a, + 0x72, 0xe1, 0xfe, 0x7f, 0x0b, 0x30, 0x1f, 0x12, 0x9c, 0xa4, 0x83, 0xf3, 0xaa, 0x7a, 0x2a, 0xb0, + 0x70, 0x18, 0x77, 0x32, 0x55, 0xc9, 0x73, 0x3c, 0x3b, 0xeb, 0x94, 0x65, 0x98, 0xc3, 0xc4, 0x8a, + 0xd1, 0x25, 0xde, 0x3d, 0x76, 0xc8, 0x64, 0x60, 0x45, 0x3f, 0xef, 0x67, 0xa8, 0xf4, 0xa5, 0x5f, + 0x21, 0x1e, 0x56, 0x78, 0x50, 0x26, 0x39, 0xe4, 0xff, 0x79, 0x0a, 0xae, 0x54, 0xd9, 0x16, 0xb8, + 0x17, 0x13, 0x92, 0x64, 0x47, 0x5c, 0x84, 0xd9, 0x63, 0x6c, 0x3b, 0x86, 0xc5, 0x66, 0xfb, 0x82, + 0xec, 0x3d, 0xa2, 0x25, 0xc8, 0x3a, 0xa6, 0xda, 0x75, 0x0e, 0x2d, 0x6f, 0x3b, 0xd1, 0x7f, 0xf6, + 0xe3, 0x57, 0xa6, 0x5f, 0x3d, 0x7e, 0x65, 0x66, 0x7c, 0xfc, 0xca, 0xec, 0x97, 0x88, 0x5f, 0xe1, + 0x7b, 0x77, 0xff, 0x5e, 0x80, 0xab, 0x43, 0x9a, 0x4b, 0xb2, 0x73, 0x7e, 0x17, 0xf2, 0x1a, 0x17, + 0x4c, 0xe6, 0x07, 0xb6, 0x31, 0xd9, 0x20, 0xd9, 0x5e, 0x11, 0xfa, 0x9c, 0x9d, 0xae, 0x80, 0x57, + 0xd4, 0xc6, 0x3a, 0x57, 0x0e, 0xf9, 0xad, 0x4b, 0xff, 0x1d, 0xa0, 0x54, 0x3b, 0x61, 0x8b, 0xf2, + 0x4d, 0xe6, 0x95, 0xa0, 0x47, 0x90, 0xed, 0xda, 0xd6, 0xb1, 0xe1, 0x55, 0xa3, 0x18, 0x09, 0x5e, + 0xf0, 0xaa, 0x31, 0xc0, 0xb5, 0xc3, 0x39, 0x64, 0x9f, 0x17, 0xb5, 0x20, 0xf7, 0xc4, 0xd2, 0xd4, + 0xf6, 0x23, 0xa3, 0xed, 0x0d, 0xb4, 0x77, 0xce, 0x17, 0x54, 0xf6, 0x79, 0x76, 0x54, 0xf7, 0xd0, + 0x6b, 0x04, 0x9f, 0x88, 0x1a, 0x90, 0xad, 0xbb, 0x6e, 0x97, 0x24, 0xf2, 0xf1, 0x77, 0x7b, 0x02, + 0xa1, 0x84, 0xc5, 0x8b, 0xb8, 0xf5, 0xd8, 0x51, 0x0b, 0xe6, 0x1f, 0xd3, 0xf3, 0x63, 0xd5, 0xb6, + 0xd5, 0xd3, 0xab, 0x96, 0xb9, 0x6f, 0x1c, 0xf0, 0x69, 0xe2, 0xd6, 0x04, 0x32, 0x1f, 0x57, 0x9b, + 0xf2, 0xb0, 0x00, 0xb4, 0x06, 0xd9, 0xe6, 0x43, 0x2e, 0x8c, 0xb9, 0x91, 0x37, 0x27, 0x10, 0xd6, + 0x7c, 0x28, 0xfb, 0x6c, 0x68, 0x03, 0xf2, 0x6b, 0x9f, 0xf5, 0x6c, 0xcc, 0xa5, 0xcc, 0x8c, 0x8c, + 0x9c, 0x18, 0x94, 0x42, 0xb9, 0xe4, 0x30, 0x33, 0xfa, 0x0e, 0x94, 0x88, 0xde, 0x5a, 0xea, 0x5e, + 0xdb, 0x93, 0x97, 0xa5, 0xf2, 0xbe, 0x31, 0x81, 0x3c, 0x9f, 0xd3, 0xdb, 0x12, 0x18, 0x10, 0xb5, + 0x24, 0x43, 0x21, 0xd2, 0x5e, 0x08, 0x41, 0xa6, 0x4b, 0x9a, 0x46, 0xa0, 0x61, 0x48, 0xf4, 0x37, + 0x7a, 0x1b, 0x66, 0x4d, 0x4b, 0xc7, 0x5e, 0x67, 0x2e, 0x54, 0x2e, 0x9d, 0x9d, 0xae, 0xcc, 0x6c, + 0x5b, 0x3a, 0xf3, 0x75, 0xf8, 0x2f, 0x79, 0x86, 0x64, 0x6a, 0xe8, 0x4b, 0xd7, 0x20, 0x43, 0x9a, + 0x88, 0xd8, 0x90, 0x3d, 0xd5, 0xc1, 0xbb, 0xb6, 0xc1, 0xa5, 0x79, 0x8f, 0x4b, 0xff, 0x30, 0x05, + 0xa9, 0xe6, 0x43, 0xe2, 0xcd, 0xef, 0xf5, 0xb4, 0x23, 0xec, 0xf2, 0x74, 0xfe, 0x44, 0xbd, 0x7c, + 0x1b, 0xef, 0x1b, 0xcc, 0xe9, 0xca, 0xc9, 0xfc, 0x09, 0xbd, 0x09, 0xa0, 0x6a, 0x1a, 0x76, 0x1c, + 0xc5, 0x3b, 0x02, 0x98, 0x93, 0x73, 0x8c, 0xb2, 0x89, 0xfb, 0x84, 0xcd, 0xc1, 0x9a, 0x8d, 0x5d, + 0x2f, 0x86, 0x8a, 0x3d, 0x11, 0x36, 0x17, 0x77, 0xba, 0x8a, 0x6b, 0x1d, 0x61, 0x93, 0x36, 0x69, + 0x8e, 0x58, 0x85, 0x4e, 0xb7, 0x45, 0x08, 0xc4, 0xa0, 0x61, 0x53, 0x0f, 0xac, 0x4f, 0x4e, 0xf6, + 0x9f, 0x89, 0x48, 0x1b, 0x1f, 0x18, 0xfc, 0x00, 0x5d, 0x4e, 0xe6, 0x4f, 0x44, 0x4b, 0x6a, 0xcf, + 0x3d, 0xa4, 0x2d, 0x91, 0x93, 0xe9, 0x6f, 0x74, 0x0b, 0x4a, 0x2c, 0xec, 0x52, 0xc1, 0xa6, 0xa6, + 0x50, 0x3b, 0x98, 0xa3, 0xc9, 0x05, 0x46, 0xae, 0x99, 0x1a, 0xb1, 0x7a, 0xe8, 0x21, 0x70, 0x82, + 0x72, 0xd4, 0x71, 0x88, 0x4e, 0x81, 0xe4, 0xaa, 0x94, 0xce, 0x4e, 0x57, 0xf2, 0x4d, 0x9a, 0xb0, + 0xb9, 0xd5, 0x24, 0x73, 0x09, 0xcb, 0xb5, 0xd9, 0x71, 0x1a, 0xfa, 0xd2, 0xdf, 0x16, 0x20, 0xfd, + 0xb8, 0xda, 0xbc, 0xb0, 0xca, 0xbc, 0x82, 0xa6, 0x43, 0x05, 0xbd, 0x0d, 0xa5, 0x3d, 0xa3, 0xdd, + 0x36, 0xcc, 0x03, 0xe2, 0x5f, 0x7d, 0x17, 0x6b, 0x9e, 0xc2, 0x8a, 0x9c, 0xbc, 0xc3, 0xa8, 0xe8, + 0x1a, 0xe4, 0x35, 0x1b, 0xeb, 0xd8, 0x74, 0x0d, 0xb5, 0xed, 0x70, 0xcd, 0x85, 0x49, 0x4b, 0x7f, + 0x4d, 0x80, 0x69, 0xda, 0x59, 0xd1, 0x1b, 0x90, 0xd3, 0x2c, 0xd3, 0x55, 0x0d, 0x93, 0x5b, 0x9d, + 0x9c, 0x1c, 0x10, 0x46, 0x16, 0xef, 0x3a, 0xcc, 0xa9, 0x9a, 0x66, 0xf5, 0x4c, 0x57, 0x31, 0xd5, + 0x0e, 0xe6, 0xc5, 0xcc, 0x73, 0xda, 0xb6, 0xda, 0xc1, 0x68, 0x05, 0xbc, 0x47, 0xff, 0x64, 0x67, + 0x4e, 0x06, 0x4e, 0xda, 0xc4, 0xfd, 0x25, 0x0c, 0x39, 0xbf, 0x57, 0x93, 0xfa, 0xf6, 0x1c, 0xbf, + 0x04, 0xf4, 0x37, 0x7a, 0x07, 0x2e, 0xbd, 0xe8, 0xa9, 0x6d, 0x63, 0x9f, 0x2e, 0x7e, 0xd1, 0x28, + 0x75, 0xfa, 0x32, 0x56, 0x14, 0xe4, 0xa7, 0x51, 0x09, 0xf4, 0x9d, 0xde, 0x20, 0x48, 0x07, 0x83, + 0x80, 0x85, 0xec, 0x48, 0x7d, 0x98, 0x97, 0xb1, 0x6b, 0xf7, 0x5b, 0xec, 0xb0, 0x6b, 0xed, 0x18, + 0x9b, 0x2e, 0xa9, 0xbb, 0xd5, 0xc5, 0x2c, 0x48, 0xc4, 0xab, 0xbb, 0x4f, 0x40, 0x37, 0xa1, 0xa8, + 0xba, 0xa4, 0xbb, 0xb9, 0x8a, 0xd9, 0xeb, 0xec, 0x61, 0x9b, 0x85, 0x02, 0xc8, 0x05, 0x4e, 0xdd, + 0xa6, 0x44, 0x7e, 0x22, 0xc3, 0xee, 0x2b, 0x74, 0x9d, 0x88, 0xbf, 0x1a, 0x28, 0xa9, 0x46, 0x28, + 0xd2, 0x5d, 0xb8, 0x4c, 0xea, 0x59, 0x33, 0x35, 0xbb, 0xdf, 0x25, 0x92, 0x9f, 0xd2, 0xbf, 0x0e, + 0x12, 0x43, 0xfb, 0x34, 0x74, 0x7b, 0x46, 0xfa, 0xf1, 0x0c, 0x14, 0x6a, 0x27, 0x5d, 0xcb, 0x4e, + 0x74, 0x55, 0xa7, 0x02, 0xb3, 0x1c, 0xf8, 0x8e, 0xd9, 0x8a, 0x1d, 0xb0, 0x40, 0xde, 0x3e, 0x34, + 0x67, 0x44, 0x15, 0x00, 0x16, 0x50, 0x49, 0xe3, 0x70, 0xd2, 0x17, 0xd8, 0x39, 0xa2, 0x6c, 0xf4, + 0xb0, 0xc1, 0x36, 0xe4, 0x3b, 0xc7, 0x9a, 0xa6, 0xec, 0x1b, 0x6d, 0x97, 0xc7, 0xa5, 0xc5, 0x87, + 0x50, 0x6f, 0x3d, 0xaf, 0x56, 0x1f, 0xd1, 0x4c, 0x2c, 0x9e, 0x2b, 0x78, 0x96, 0x81, 0x48, 0x60, + 0xbf, 0xd1, 0x37, 0x80, 0x1f, 0x7c, 0x51, 0x1c, 0xef, 0x18, 0x5b, 0xa5, 0x70, 0x76, 0xba, 0x92, + 0x93, 0x29, 0xb5, 0xd9, 0x6c, 0xc9, 0x39, 0x96, 0xa1, 0xe9, 0xb8, 0x17, 0x39, 0xea, 0x30, 0x3b, + 0xf9, 0x51, 0x87, 0xdf, 0x14, 0xe0, 0x0a, 0xd7, 0x91, 0xb2, 0x47, 0xc3, 0xbb, 0xd5, 0xb6, 0xe1, + 0xf6, 0x95, 0xa3, 0xe3, 0xc5, 0x2c, 0x75, 0x79, 0x7e, 0x31, 0x56, 0xd7, 0xa1, 0x26, 0x2e, 0x7b, + 0x1a, 0xef, 0x3f, 0xe1, 0xcc, 0x9b, 0xc7, 0x35, 0xd3, 0xb5, 0xfb, 0x95, 0xab, 0x67, 0xa7, 0x2b, + 0x0b, 0xc3, 0xa9, 0xcf, 0xe5, 0x05, 0x67, 0x98, 0x05, 0xd5, 0x01, 0xb0, 0xdf, 0xc5, 0xa8, 0x05, + 0x8b, 0x9f, 0xba, 0x62, 0xfb, 0xa2, 0x1c, 0xe2, 0x45, 0x77, 0x40, 0xe4, 0x47, 0x4b, 0xf6, 0x8d, + 0x36, 0x56, 0x1c, 0xe3, 0x33, 0x4c, 0x6d, 0x5d, 0x5a, 0x2e, 0x32, 0x3a, 0x11, 0xd1, 0x34, 0x3e, + 0xc3, 0xe8, 0x3e, 0x5c, 0x0e, 0x5a, 0x40, 0xd9, 0xc3, 0x6d, 0xeb, 0x25, 0xcb, 0x9e, 0xa7, 0xd9, + 0x91, 0xaf, 0xfd, 0x0a, 0x49, 0x22, 0x2c, 0x4b, 0xdf, 0x85, 0xc5, 0x51, 0x15, 0x0e, 0x0f, 0x88, + 0x1c, 0xdb, 0xaf, 0x7c, 0x2f, 0xba, 0x58, 0x31, 0x41, 0xc7, 0xe5, 0x0b, 0x16, 0xef, 0xa7, 0xde, + 0x13, 0xa4, 0x7f, 0x90, 0x82, 0x42, 0xa5, 0xd7, 0x3e, 0x7a, 0xda, 0x6d, 0xb2, 0x63, 0xf9, 0xe8, + 0x75, 0xc8, 0xe9, 0xaa, 0xab, 0xb2, 0x42, 0x0a, 0xec, 0x88, 0x19, 0x21, 0xd0, 0xda, 0xdc, 0x86, + 0x52, 0x28, 0x16, 0x84, 0x47, 0xbc, 0xd3, 0x6a, 0x07, 0x64, 0x1a, 0x94, 0xfe, 0x1e, 0x2c, 0x86, + 0x32, 0xd2, 0x95, 0x05, 0x05, 0x9b, 0xae, 0x6d, 0x60, 0xb6, 0x3a, 0x96, 0x96, 0x43, 0x01, 0x2b, + 0x0d, 0x92, 0x5c, 0x63, 0xa9, 0xa8, 0x05, 0x73, 0x24, 0x63, 0x5f, 0xa1, 0x56, 0xd0, 0x5b, 0xbd, + 0xbc, 0x1f, 0x53, 0xad, 0x48, 0xb9, 0xcb, 0x54, 0x3f, 0x55, 0xca, 0x43, 0x7f, 0xca, 0x79, 0x1c, + 0x50, 0x96, 0x3e, 0x02, 0x71, 0x30, 0x43, 0x58, 0x97, 0x19, 0xa6, 0xcb, 0x4b, 0x61, 0x5d, 0xa6, + 0x43, 0x7a, 0xda, 0xc8, 0x64, 0x33, 0xe2, 0xb4, 0xf4, 0x93, 0x34, 0x14, 0xbd, 0x9e, 0x99, 0xa4, + 0x5b, 0x5d, 0x81, 0x69, 0xd2, 0x8f, 0xbc, 0xf0, 0x8a, 0x5b, 0x63, 0x06, 0x04, 0x8f, 0xb1, 0x26, + 0xfd, 0xcb, 0x43, 0x80, 0x94, 0x35, 0x09, 0xf3, 0xb3, 0xf4, 0xe7, 0x02, 0x64, 0xa8, 0x27, 0x7b, + 0x1f, 0x32, 0xf4, 0x5c, 0xbe, 0x30, 0xf6, 0x5c, 0xbe, 0xb7, 0x3d, 0x4f, 0xb2, 0xfa, 0x13, 0x4b, + 0x2a, 0xe4, 0x5d, 0x55, 0x68, 0x7c, 0x8f, 0x65, 0xbb, 0x58, 0xe7, 0x9e, 0xe2, 0xb5, 0xf3, 0xda, + 0xd1, 0xf3, 0x84, 0x3d, 0x3e, 0xf4, 0x1a, 0xa4, 0x89, 0xed, 0x9a, 0x65, 0x5b, 0xf5, 0x67, 0xa7, + 0x2b, 0x69, 0x62, 0xb5, 0x08, 0x0d, 0xad, 0x42, 0x3e, 0x6a, 0x4d, 0x88, 0xb3, 0x41, 0xcd, 0x61, + 0xc8, 0x12, 0x40, 0xdb, 0x1f, 0x42, 0x0c, 0x25, 0xb1, 0xb6, 0xe4, 0x9b, 0xf4, 0xbf, 0x2e, 0xf0, + 0x98, 0xc4, 0xa6, 0x46, 0xe6, 0x2c, 0x3b, 0xc9, 0x49, 0xe5, 0x2e, 0x88, 0xb6, 0x6a, 0xea, 0x56, + 0xc7, 0xf8, 0x0c, 0x33, 0x54, 0xee, 0xf0, 0xed, 0x8a, 0x92, 0x4f, 0xa7, 0xf0, 0xd9, 0x91, 0xfe, + 0x9b, 0xc0, 0xe3, 0x17, 0xfd, 0x62, 0x24, 0xbb, 0xa9, 0x9c, 0xe7, 0x4b, 0x7a, 0xe6, 0xbe, 0xe5, + 0x85, 0x5f, 0xbc, 0x31, 0x2a, 0xd8, 0xa8, 0x61, 0xee, 0x5b, 0xde, 0xf6, 0x98, 0xed, 0x11, 0x9c, + 0xa5, 0x5f, 0x86, 0x69, 0x9a, 0xfc, 0x0a, 0x7d, 0xc3, 0x8f, 0x99, 0x4d, 0x89, 0x69, 0xe9, 0x4f, + 0x52, 0xf0, 0x16, 0xad, 0xea, 0x73, 0x6c, 0x1b, 0xfb, 0xfd, 0x1d, 0xdb, 0x72, 0xb1, 0xe6, 0x62, + 0x3d, 0x58, 0x95, 0x4a, 0xb0, 0x09, 0x74, 0xc8, 0xf1, 0xfd, 0x3c, 0x43, 0xe7, 0x37, 0x67, 0x3c, + 0xfe, 0x72, 0x68, 0x35, 0xcb, 0xf6, 0x01, 0x1b, 0xeb, 0x72, 0x96, 0x49, 0x6e, 0xe8, 0x68, 0x0d, + 0x72, 0x5d, 0xaf, 0x1a, 0x17, 0x0a, 0x19, 0xf1, 0xb9, 0xd0, 0x26, 0x94, 0x78, 0x41, 0xd5, 0xb6, + 0x71, 0x8c, 0x15, 0xd5, 0xbd, 0xc8, 0x10, 0x2e, 0x30, 0xde, 0x35, 0xc2, 0xba, 0xe6, 0x4a, 0x7f, + 0x2b, 0x03, 0x37, 0xcf, 0x51, 0x71, 0x92, 0xdd, 0x6b, 0x09, 0xb2, 0xc7, 0xe4, 0x45, 0x06, 0xaf, + 0x7d, 0x56, 0xf6, 0x9f, 0xd1, 0x5e, 0x64, 0x1e, 0xd8, 0x57, 0x8d, 0x36, 0x99, 0x37, 0x58, 0x90, + 0xde, 0xe8, 0x30, 0xa0, 0xf8, 0xa0, 0xb7, 0xd0, 0x8c, 0xf1, 0x88, 0x0a, 0xa2, 0xd9, 0x1c, 0xf4, + 0x3d, 0x01, 0x96, 0xd8, 0x0b, 0x59, 0xa4, 0xd8, 0xc0, 0x6b, 0x32, 0xf4, 0x35, 0xeb, 0x31, 0xaf, + 0x99, 0x48, 0x47, 0xe5, 0xd0, 0xbb, 0x78, 0x41, 0x16, 0xc3, 0x6f, 0x0b, 0x17, 0x65, 0xe9, 0xb7, + 0x04, 0xc8, 0x87, 0x08, 0xe8, 0xd6, 0xd0, 0xb9, 0x9c, 0xfc, 0x59, 0xdc, 0x61, 0x9c, 0x9b, 0x43, + 0x87, 0x71, 0x2a, 0xd9, 0x2f, 0x4e, 0x57, 0x32, 0x32, 0x8b, 0xf7, 0xf6, 0x8e, 0xe5, 0x5c, 0x0f, + 0xae, 0x81, 0x49, 0x0f, 0x64, 0xf2, 0xee, 0x81, 0xa1, 0xb0, 0x4e, 0xf5, 0xb6, 0x91, 0x28, 0xac, + 0x23, 0x4f, 0xd2, 0x0f, 0x52, 0x30, 0xbf, 0xa6, 0xeb, 0xcd, 0x26, 0x85, 0x02, 0x49, 0x8e, 0x31, + 0x04, 0x19, 0xe2, 0x1f, 0xf0, 0x33, 0x44, 0xf4, 0x37, 0x7a, 0x1b, 0x90, 0x6e, 0x38, 0xec, 0x3a, + 0x05, 0xe7, 0x50, 0xd5, 0xad, 0x97, 0xc1, 0x6e, 0xf1, 0xbc, 0x97, 0xd2, 0xf4, 0x12, 0x50, 0x13, + 0xa8, 0xd3, 0xaa, 0x38, 0xae, 0xea, 0xaf, 0x86, 0xdf, 0x9c, 0xe8, 0x54, 0x0a, 0xf3, 0x66, 0xfd, + 0x47, 0x39, 0x47, 0xe4, 0xd0, 0x9f, 0xc4, 0x47, 0x33, 0x48, 0xa3, 0xb8, 0x8a, 0xea, 0x78, 0xe7, + 0x29, 0xd8, 0x45, 0x0e, 0x45, 0x46, 0x5f, 0x73, 0xd8, 0x31, 0x09, 0x16, 0x86, 0x1d, 0xa8, 0x26, + 0xc9, 0xb5, 0xcc, 0xdf, 0x15, 0xa0, 0x28, 0xe3, 0x7d, 0x1b, 0x3b, 0x87, 0x49, 0xea, 0xfc, 0x11, + 0xcc, 0xd9, 0x4c, 0xaa, 0xb2, 0x6f, 0x5b, 0x9d, 0x8b, 0xd8, 0x8a, 0x3c, 0x67, 0x7c, 0x64, 0x5b, + 0x1d, 0x6e, 0x92, 0x9f, 0x43, 0xc9, 0x2f, 0x63, 0x92, 0x95, 0xff, 0xfb, 0xf4, 0xc4, 0x25, 0x13, + 0x9c, 0xf4, 0xb6, 0x6d, 0xb2, 0x1a, 0xa0, 0xeb, 0xd9, 0xe1, 0x82, 0x26, 0xa9, 0x86, 0xff, 0x2a, + 0x40, 0xb1, 0xd9, 0xdb, 0x63, 0xd7, 0x04, 0x25, 0xa7, 0x81, 0x1a, 0xe4, 0xda, 0x78, 0xdf, 0x55, + 0x5e, 0x29, 0x80, 0x38, 0x4b, 0x58, 0x69, 0xf8, 0xf4, 0x63, 0x00, 0x9b, 0x1e, 0x39, 0xa2, 0x72, + 0xd2, 0x17, 0x94, 0x93, 0xa3, 0xbc, 0x84, 0x4c, 0x66, 0x9d, 0x92, 0x5f, 0xcd, 0x24, 0xe7, 0x97, + 0x8f, 0x23, 0xd6, 0x21, 0x7d, 0x11, 0xeb, 0x30, 0xcf, 0x77, 0xaa, 0xe3, 0x2d, 0x44, 0x19, 0x16, + 0xa8, 0x5b, 0xa6, 0xa8, 0xdd, 0x6e, 0xdb, 0xf0, 0x70, 0x0a, 0xb5, 0x3f, 0x19, 0x79, 0x9e, 0x26, + 0xad, 0xb1, 0x14, 0x8a, 0x50, 0xd0, 0x6f, 0x08, 0x30, 0xb7, 0x6f, 0x63, 0xfc, 0x19, 0x56, 0xa8, + 0x49, 0x9e, 0x6c, 0x2b, 0x7e, 0x9d, 0x94, 0xe1, 0x4b, 0x6f, 0xd5, 0xe5, 0xd9, 0x8b, 0x9b, 0xe4, + 0xbd, 0x68, 0x1b, 0x44, 0xad, 0xcd, 0x36, 0x0f, 0xfd, 0xb0, 0x80, 0x99, 0xc9, 0x07, 0x40, 0x89, + 0x31, 0x07, 0x91, 0x01, 0xcf, 0xc8, 0x60, 0x52, 0x75, 0x85, 0x5f, 0xcd, 0x46, 0x9d, 0xed, 0x68, + 0x58, 0x40, 0xf8, 0xe8, 0x75, 0xe8, 0x46, 0xb7, 0xb2, 0x8c, 0x55, 0x9d, 0x7b, 0xee, 0x64, 0x5c, + 0xf9, 0x0f, 0x7c, 0x5c, 0x7d, 0x0c, 0xf3, 0xb4, 0xdf, 0x24, 0x7d, 0x82, 0x52, 0xfa, 0xc7, 0x69, + 0x40, 0x61, 0xc9, 0x5f, 0x5d, 0x7f, 0x4b, 0x25, 0xd7, 0xdf, 0x36, 0x40, 0x0a, 0x39, 0x43, 0x6d, + 0xd5, 0x71, 0x15, 0x16, 0x7f, 0xe6, 0x28, 0x5d, 0x6c, 0x2b, 0x0e, 0xd6, 0x2c, 0x7e, 0x89, 0x8e, + 0x20, 0x2f, 0x07, 0x39, 0x9f, 0xa8, 0x8e, 0xfb, 0x8c, 0xe5, 0xdb, 0xc1, 0x76, 0x93, 0xe6, 0x42, + 0x0f, 0xe1, 0x4a, 0x47, 0x3d, 0x89, 0xe3, 0x9f, 0xa6, 0xfc, 0x0b, 0x1d, 0xf5, 0x64, 0x88, 0xe9, + 0x7d, 0x58, 0x8a, 0x67, 0x52, 0x1c, 0xec, 0xed, 0x4f, 0x5d, 0x89, 0x61, 0x6c, 0x62, 0x17, 0xad, + 0x01, 0x04, 0x20, 0x82, 0xcf, 0xd1, 0x93, 0x60, 0x88, 0x9c, 0x8f, 0x21, 0xa4, 0xef, 0x0b, 0x50, + 0xdc, 0x32, 0x0e, 0x6c, 0x35, 0xd1, 0x2b, 0x6a, 0xd0, 0xfb, 0xd1, 0x0d, 0xbd, 0xfc, 0x83, 0xa5, + 0xb8, 0x80, 0x0d, 0x96, 0xc3, 0x5b, 0xb4, 0xe3, 0x0c, 0x64, 0xea, 0xf3, 0x4b, 0x94, 0xa4, 0xcd, + 0xd7, 0xe0, 0x4d, 0x1a, 0x02, 0xc7, 0xe3, 0x5f, 0xbe, 0x12, 0x74, 0x23, 0xfd, 0x81, 0x00, 0xcb, + 0xa3, 0xde, 0x92, 0xe4, 0x80, 0x90, 0xe9, 0x65, 0x7d, 0xf4, 0x0d, 0x8a, 0x3f, 0x22, 0xce, 0xb1, + 0x34, 0x88, 0x8f, 0x04, 0xf0, 0xcb, 0xd6, 0xa4, 0xd7, 0xf8, 0xb1, 0xdf, 0x8e, 0xf4, 0x6f, 0x97, + 0x60, 0x8e, 0xd7, 0x6f, 0xd7, 0x34, 0x2c, 0x13, 0xdd, 0x87, 0xf4, 0x01, 0x5f, 0xfb, 0xcf, 0xc7, + 0x2e, 0x79, 0x06, 0x37, 0xe4, 0xd5, 0xa7, 0x64, 0x92, 0x97, 0xb0, 0x74, 0x7b, 0x6e, 0x4c, 0x79, + 0x82, 0x20, 0xef, 0x30, 0x4b, 0xb7, 0xe7, 0xa2, 0x26, 0x94, 0xb4, 0xe0, 0x5a, 0x2e, 0x85, 0xb0, + 0xa7, 0x47, 0xae, 0x03, 0xc6, 0x5e, 0x90, 0x56, 0x9f, 0x92, 0x8b, 0x5a, 0x24, 0x01, 0x55, 0xc3, + 0xb7, 0x41, 0x65, 0x86, 0x22, 0xc8, 0x82, 0xb3, 0xc4, 0xd1, 0x9b, 0xa8, 0xea, 0x53, 0xa1, 0x4b, + 0xa3, 0xd0, 0xfb, 0x30, 0xa3, 0xd3, 0x7b, 0x87, 0xf8, 0xac, 0x12, 0xd7, 0x21, 0x22, 0xd7, 0x3b, + 0xd5, 0xa7, 0x64, 0xce, 0x81, 0x36, 0x60, 0x8e, 0xfd, 0x62, 0x98, 0x87, 0xcf, 0x05, 0x37, 0x47, + 0x4b, 0x08, 0x79, 0x63, 0xf5, 0x29, 0x39, 0xaf, 0x07, 0x54, 0xf4, 0x18, 0xf2, 0x5a, 0x1b, 0xab, + 0x36, 0x17, 0x75, 0x6b, 0xe4, 0xb1, 0xb7, 0xa1, 0xbb, 0x8a, 0xea, 0x53, 0x32, 0x68, 0x3e, 0x91, + 0x14, 0xca, 0xa6, 0x57, 0xd6, 0x70, 0x49, 0xef, 0x8c, 0x2c, 0xd4, 0xf0, 0xfd, 0x3f, 0x75, 0xea, + 0xa5, 0xf9, 0x54, 0xf4, 0x4d, 0xc8, 0x38, 0x9a, 0x6a, 0xf2, 0x89, 0x69, 0x79, 0xc4, 0x9d, 0x22, + 0x01, 0x33, 0xcd, 0x8d, 0x3e, 0x60, 0x70, 0xc9, 0x3d, 0xf1, 0x16, 0x7b, 0xe3, 0x74, 0x1a, 0x39, + 0xbb, 0x4e, 0x74, 0x8a, 0x29, 0x81, 0xe8, 0x41, 0x25, 0xf8, 0x50, 0xa1, 0x07, 0x4a, 0xe9, 0xea, + 0x6e, 0xbc, 0x1e, 0x86, 0x0e, 0x00, 0xd7, 0xe9, 0x01, 0x79, 0x8f, 0x88, 0xb6, 0xa0, 0xc0, 0x04, + 0xf5, 0xd8, 0xd9, 0xd4, 0xc5, 0xd5, 0x91, 0xdb, 0xb8, 0x31, 0xa7, 0x63, 0xeb, 0x53, 0xf2, 0x9c, + 0x1a, 0x22, 0x07, 0xe5, 0xea, 0x60, 0xfb, 0x80, 0x2d, 0x23, 0x8f, 0x29, 0x57, 0x38, 0x36, 0xce, + 0x2f, 0x17, 0x25, 0xa2, 0x5f, 0x83, 0x4b, 0x4c, 0x90, 0xcb, 0x43, 0x7e, 0x78, 0xe4, 0xc8, 0x9b, + 0x23, 0xb7, 0x60, 0x47, 0x9e, 0x27, 0xad, 0x4f, 0xc9, 0x48, 0x1d, 0x4a, 0x44, 0x1a, 0x5c, 0x66, + 0x6f, 0xe0, 0x07, 0x12, 0x6d, 0x7e, 0x86, 0x6e, 0xf1, 0x06, 0x7d, 0xc5, 0xdb, 0xa3, 0x5e, 0x11, + 0x7b, 0x4e, 0xb2, 0x3e, 0x25, 0x2f, 0xa8, 0xc3, 0xa9, 0x41, 0x35, 0x6c, 0x7e, 0xf4, 0x8b, 0x77, + 0xb7, 0xb7, 0xc7, 0x57, 0x23, 0xee, 0xc8, 0x9c, 0x5f, 0x8d, 0x48, 0x22, 0x69, 0x40, 0xff, 0xe0, + 0x3b, 0xed, 0x4c, 0x73, 0x23, 0x1b, 0x30, 0xe6, 0x7c, 0x18, 0x69, 0xc0, 0xc3, 0x10, 0x19, 0x95, + 0x21, 0x75, 0xa0, 0x2d, 0x16, 0x46, 0x4e, 0xa0, 0xfe, 0x19, 0xa8, 0xfa, 0x94, 0x9c, 0x3a, 0xd0, + 0xd0, 0x47, 0x90, 0x65, 0x07, 0x5a, 0x4e, 0xcc, 0xc5, 0xe2, 0x48, 0x23, 0x1e, 0x3d, 0x16, 0x54, + 0x9f, 0x92, 0xe9, 0x19, 0x1a, 0xde, 0x91, 0xf9, 0x61, 0x05, 0x2a, 0xa2, 0x3c, 0xe6, 0x1c, 0xeb, + 0xc0, 0x91, 0x11, 0xd2, 0x61, 0x6c, 0x9f, 0x88, 0x76, 0xa0, 0xc8, 0x0d, 0xb8, 0x17, 0x7c, 0x2d, + 0x8e, 0x0c, 0x72, 0x88, 0x8b, 0xbf, 0xae, 0xd3, 0x85, 0xaa, 0x10, 0x9d, 0xb4, 0x5d, 0x54, 0x22, + 0x6f, 0xbb, 0xf9, 0x91, 0x6d, 0x37, 0x32, 0x16, 0x98, 0xb4, 0x9d, 0x3d, 0x94, 0x88, 0xde, 0x85, + 0x69, 0x36, 0x4e, 0x10, 0x15, 0x19, 0x17, 0xb7, 0x33, 0x30, 0x44, 0x58, 0x7e, 0x62, 0xbd, 0x5c, + 0x1e, 0xd3, 0xa8, 0xb4, 0xad, 0x83, 0xc5, 0x85, 0x91, 0xd6, 0x6b, 0x38, 0x3a, 0x93, 0x58, 0x2f, + 0x37, 0xa0, 0x92, 0x0e, 0x64, 0xb3, 0x14, 0x3e, 0xc4, 0x2e, 0x8d, 0xec, 0x40, 0x31, 0xa1, 0x8e, + 0x75, 0x7a, 0xda, 0x24, 0x20, 0xfb, 0x86, 0xd5, 0xc1, 0x0a, 0x35, 0x8a, 0x97, 0xc7, 0x1b, 0xd6, 0xc8, 0x45, 0x4f, 0xbe, 0x61, 0x65, 0x54, 0xf4, 0x1c, 0x44, 0x7e, 0xdb, 0x88, 0xe2, 0x85, 0xde, - 0x2c, 0x5c, 0xa2, 0xf2, 0xee, 0xc6, 0x4e, 0x88, 0x71, 0x51, 0x59, 0x35, 0x82, 0x28, 0xa2, 0x29, - 0xe8, 0x53, 0x98, 0xa3, 0xf2, 0x14, 0x2d, 0xb8, 0x20, 0x66, 0x61, 0x61, 0xe0, 0xba, 0x91, 0xe1, - 0x77, 0xc9, 0x78, 0x92, 0x45, 0xad, 0x2f, 0x89, 0x8c, 0x07, 0xc3, 0x34, 0x5c, 0x3a, 0x77, 0x2f, - 0x0e, 0x1d, 0x0f, 0xd1, 0xcb, 0x31, 0xc9, 0x78, 0x30, 0x18, 0x85, 0x74, 0xe3, 0x3e, 0x8b, 0xf7, - 0xd6, 0xd0, 0x6e, 0x3c, 0xc4, 0xd8, 0xcd, 0xba, 0x11, 0x3b, 0xb7, 0x06, 0xc0, 0x70, 0x24, 0x75, - 0x8d, 0x97, 0x86, 0x3a, 0x00, 0xfd, 0xa1, 0x88, 0xc4, 0x01, 0x68, 0x79, 0x34, 0xe2, 0x00, 0xb0, - 0x4d, 0x8f, 0x85, 0x6b, 0xc3, 0x27, 0xab, 0xf0, 0xb6, 0x28, 0x9d, 0xac, 0x28, 0x01, 0xad, 0x42, - 0x8e, 0x38, 0xf5, 0x3d, 0x3a, 0xc2, 0xaf, 0x0f, 0xc5, 0xf0, 0x7d, 0x67, 0x94, 0x6a, 0x13, 0x72, - 0xf6, 0x25, 0x27, 0x91, 0x5e, 0xc5, 0x44, 0xf0, 0xb1, 0x7d, 0x6f, 0x68, 0xaf, 0x1a, 0x3c, 0x9c, - 0x42, 0x7a, 0xd5, 0xcb, 0x80, 0x1a, 0x4c, 0x79, 0x0e, 0xdb, 0xce, 0x58, 0x78, 0x67, 0xf4, 0x94, - 0x17, 0xdd, 0x7c, 0xf1, 0xa7, 0x3c, 0x4e, 0x66, 0x53, 0x9e, 0xae, 0x38, 0x0e, 0x8d, 0x70, 0x58, - 0xb8, 0x39, 0x62, 0xca, 0xeb, 0x5b, 0xe0, 0x64, 0x53, 0x9e, 0xde, 0x60, 0x9c, 0xc4, 0xfb, 0xb3, - 0xbd, 0xdb, 0x75, 0x38, 0xbc, 0xbb, 0x3d, 0xd4, 0xfb, 0x8b, 0xbd, 0xfe, 0x87, 0x78, 0x7f, 0x76, - 0x24, 0x01, 0xfd, 0x12, 0x4c, 0xf3, 0x05, 0xa5, 0x85, 0x3b, 0x23, 0x7c, 0xec, 0xf0, 0x1a, 0x20, - 0xe9, 0x8e, 0x9c, 0x87, 0x19, 0x07, 0xb6, 0x90, 0xc5, 0x8c, 0xdf, 0xdd, 0x11, 0xc6, 0x61, 0x60, - 0x2d, 0x8d, 0x19, 0x87, 0x80, 0x4c, 0x4a, 0xe3, 0xb0, 0x45, 0x98, 0x85, 0x5f, 0x18, 0x5a, 0x9a, - 0xe8, 0x6a, 0x14, 0x29, 0x0d, 0xe7, 0xa1, 0x93, 0x05, 0x9d, 0xab, 0x99, 0x76, 0xbe, 0x31, 0x7c, - 0xb2, 0xe8, 0x87, 0xf5, 0x35, 0x6f, 0xbb, 0x88, 0x69, 0xe5, 0xaf, 0x0b, 0x70, 0x8d, 0xf5, 0x01, - 0xba, 0x58, 0xde, 0x53, 0xfc, 0xbd, 0x8e, 0xd0, 0x9a, 0xc5, 0x7d, 0x2a, 0xfe, 0xfd, 0xf3, 0x2f, - 0xcd, 0x7b, 0x6f, 0x7c, 0x5b, 0x1d, 0x95, 0x8f, 0x28, 0xa3, 0xcd, 0xd0, 0xdd, 0xc2, 0x83, 0xa1, - 0xca, 0x88, 0x22, 0x52, 0xa2, 0x0c, 0xce, 0x83, 0x5a, 0xb0, 0xc0, 0x86, 0x44, 0x80, 0x7e, 0xfc, - 0xa2, 0x3f, 0x1c, 0x1a, 0x34, 0x38, 0x12, 0xf7, 0xd5, 0x26, 0xe4, 0x4b, 0x2f, 0x63, 0x33, 0x94, - 0xa7, 0xf9, 0xe6, 0xb3, 0x7f, 0xd0, 0xb4, 0x28, 0x8a, 0xeb, 0x99, 0xec, 0x65, 0x71, 0x61, 0x3d, - 0x93, 0xbd, 0x22, 0x2e, 0xae, 0x67, 0xb2, 0x57, 0xc5, 0xb7, 0xd6, 0x33, 0xd9, 0x65, 0xf1, 0xda, - 0x7a, 0x26, 0x2b, 0x89, 0x37, 0xa4, 0xdf, 0x59, 0x84, 0x59, 0x0f, 0xbd, 0x31, 0x14, 0xf5, 0x20, - 0x8c, 0xa2, 0x96, 0x86, 0xa1, 0x28, 0x8e, 0xf7, 0x38, 0x8c, 0x7a, 0x10, 0x86, 0x51, 0x4b, 0xc3, - 0x60, 0x54, 0xc0, 0x43, 0x70, 0x54, 0x73, 0x18, 0x8e, 0xba, 0x3b, 0x06, 0x8e, 0xf2, 0x45, 0xf5, - 0x03, 0xa9, 0xb5, 0x41, 0x20, 0xf5, 0xce, 0x68, 0x20, 0xe5, 0x8b, 0x0a, 0x21, 0xa9, 0x8f, 0xfa, - 0x90, 0xd4, 0xf5, 0x11, 0x48, 0xca, 0xe7, 0xf7, 0xa0, 0xd4, 0x46, 0x2c, 0x94, 0xba, 0x75, 0x16, - 0x94, 0xf2, 0xe5, 0x44, 0xb0, 0x54, 0x2d, 0x0e, 0x4b, 0xdd, 0x3c, 0x03, 0x4b, 0xf9, 0xa2, 0xc2, - 0x60, 0x6a, 0x23, 0x16, 0x4c, 0xdd, 0x3a, 0x0b, 0x4c, 0x05, 0xc5, 0x0a, 0xa3, 0xa9, 0x6f, 0x45, - 0xd0, 0xd4, 0xf2, 0x50, 0x34, 0xe5, 0x73, 0x33, 0x38, 0xf5, 0x71, 0x3f, 0x9c, 0xba, 0x3e, 0x02, - 0x4e, 0x05, 0x8a, 0xe5, 0x78, 0xaa, 0x16, 0x87, 0xa7, 0x6e, 0x9e, 0x81, 0xa7, 0x02, 0x5d, 0x84, - 0x00, 0xd5, 0x56, 0x3c, 0xa0, 0xba, 0x7d, 0x26, 0xa0, 0xf2, 0xa5, 0x45, 0x11, 0x55, 0x2d, 0x0e, - 0x51, 0xdd, 0x3c, 0x03, 0x51, 0xf5, 0x95, 0x8c, 0x41, 0x2a, 0x75, 0x24, 0xa4, 0x7a, 0x77, 0x4c, - 0x48, 0xe5, 0x8b, 0x8e, 0xc3, 0x54, 0xfa, 0x68, 0x4c, 0x55, 0x1a, 0x17, 0x53, 0xf9, 0x2f, 0x89, - 0x05, 0x55, 0xea, 0x48, 0x50, 0xf5, 0xee, 0x98, 0xa0, 0xaa, 0xaf, 0x22, 0x51, 0x54, 0xb5, 0x15, - 0x8f, 0xaa, 0x6e, 0x9f, 0x89, 0xaa, 0x82, 0x56, 0x8c, 0xc0, 0xaa, 0x95, 0x10, 0xac, 0x7a, 0x7b, - 0x08, 0xac, 0xf2, 0x59, 0x09, 0xae, 0xfa, 0xf6, 0x00, 0xae, 0x92, 0x46, 0xe1, 0x2a, 0x9f, 0xd7, - 0x07, 0x56, 0xb5, 0x38, 0x60, 0x75, 0xf3, 0x0c, 0x60, 0x15, 0xf4, 0x9b, 0x10, 0xb2, 0x7a, 0x36, - 0x04, 0x59, 0xdd, 0x39, 0x1b, 0x59, 0xf9, 0xf2, 0xfa, 0xa0, 0x95, 0x3a, 0x12, 0x5a, 0xbd, 0x3b, - 0x26, 0xb4, 0x0a, 0x5a, 0x30, 0x06, 0x5b, 0x7d, 0x10, 0xc5, 0x56, 0xd7, 0x86, 0x63, 0x2b, 0x5f, - 0x0c, 0x07, 0x57, 0x1b, 0xb1, 0xe0, 0xea, 0xd6, 0x59, 0xe0, 0x2a, 0xb0, 0x66, 0x61, 0x74, 0xb5, - 0x15, 0x8f, 0xae, 0x6e, 0x9f, 0x89, 0xae, 0x82, 0x8e, 0x14, 0x81, 0x57, 0x1b, 0xb1, 0xf0, 0xea, - 0xd6, 0x59, 0xf0, 0xaa, 0xcf, 0xd4, 0x72, 0x7c, 0xf5, 0x62, 0x28, 0xbe, 0xba, 0x37, 0x0e, 0xbe, - 0xf2, 0x85, 0x0e, 0x00, 0xac, 0xcf, 0x86, 0x03, 0xac, 0x5f, 0x38, 0xc7, 0x65, 0x9d, 0xb1, 0x08, - 0xeb, 0xdb, 0x03, 0x08, 0x4b, 0x1a, 0x85, 0xb0, 0x82, 0x91, 0xe1, 0x41, 0xac, 0x6a, 0x0c, 0x20, - 0x7a, 0x67, 0x34, 0x20, 0x0a, 0x26, 0xf2, 0x00, 0x11, 0x7d, 0xd4, 0x87, 0x88, 0xae, 0x9f, 0x19, - 0x17, 0x17, 0x82, 0x44, 0xe5, 0x41, 0x48, 0x74, 0x63, 0x24, 0x24, 0xf2, 0x25, 0x04, 0x98, 0x68, - 0x23, 0x16, 0x13, 0xdd, 0x3a, 0x0b, 0x13, 0x05, 0x5d, 0x21, 0x0c, 0x8a, 0xb6, 0xe2, 0x41, 0xd1, - 0xed, 0x33, 0x41, 0x51, 0xdf, 0xb4, 0xe5, 0xa1, 0xa2, 0x5a, 0x1c, 0x2a, 0xba, 0x79, 0x06, 0x2a, - 0x0a, 0x4f, 0x5b, 0x3e, 0x2c, 0x6a, 0x0e, 0x83, 0x45, 0x77, 0xc7, 0x80, 0x45, 0x81, 0x33, 0xd7, - 0x87, 0x8b, 0x3e, 0xe9, 0xc7, 0x45, 0xd2, 0x28, 0x5c, 0x14, 0x74, 0x22, 0x0f, 0x18, 0x6d, 0xc5, - 0x03, 0xa3, 0xdb, 0x67, 0x02, 0xa3, 0xf0, 0xb8, 0x0e, 0x21, 0xa3, 0x4f, 0xfa, 0x91, 0x91, 0x34, - 0x0a, 0x19, 0x05, 0xe5, 0xf1, 0xa0, 0x51, 0x2d, 0x0e, 0x1a, 0xdd, 0x3c, 0x03, 0x1a, 0x85, 0xcc, - 0x7d, 0x80, 0x8d, 0xfe, 0xc6, 0xf8, 0xd8, 0xe8, 0x83, 0xd7, 0x0d, 0x5b, 0x3a, 0x1b, 0x1c, 0x7d, - 0xd2, 0x0f, 0x8e, 0xa4, 0x51, 0xe0, 0x28, 0xd0, 0x87, 0x87, 0x8e, 0xda, 0x67, 0xa2, 0xa3, 0xfb, - 0xe7, 0x40, 0x47, 0xbe, 0xfc, 0x37, 0x86, 0x47, 0x6f, 0x89, 0x6f, 0x47, 0x40, 0xd2, 0x9f, 0x4d, - 0xc1, 0x14, 0xff, 0x4e, 0x55, 0xe4, 0x6e, 0x27, 0xe1, 0x75, 0xee, 0x76, 0x42, 0x6b, 0xa4, 0x57, - 0x53, 0x2f, 0xe9, 0xec, 0x1b, 0x01, 0x07, 0xef, 0xac, 0xe3, 0xac, 0xaf, 0x71, 0xc8, 0x1a, 0x7d, - 0x0b, 0x66, 0xbb, 0x0e, 0xb6, 0x95, 0x8e, 0x6d, 0x58, 0xb6, 0xe1, 0xb2, 0xe3, 0x22, 0x42, 0x59, - 0xfc, 0xf2, 0x64, 0x79, 0x66, 0xc7, 0xc1, 0xf6, 0x36, 0xa7, 0xcb, 0x33, 0xdd, 0xd0, 0x93, 0xf7, - 0x69, 0xae, 0xc9, 0xf1, 0x3f, 0xcd, 0xf5, 0x0c, 0x44, 0x1a, 0x0c, 0x10, 0x9e, 0x58, 0xd8, 0x3d, - 0x4a, 0xf1, 0x73, 0xa0, 0xaa, 0x87, 0xe6, 0x0e, 0x7a, 0x9f, 0x52, 0xd1, 0x8e, 0x12, 0x51, 0x03, - 0xe8, 0x0d, 0x27, 0x4a, 0xc7, 0x6a, 0x19, 0x5a, 0x8f, 0xfa, 0x0b, 0xd1, 0x3b, 0xa5, 0x47, 0xde, - 0xec, 0xfe, 0x42, 0x35, 0xdc, 0x6d, 0xca, 0x29, 0xc3, 0x2b, 0xff, 0x37, 0xba, 0x0f, 0x17, 0xdb, - 0xea, 0x31, 0xbd, 0x6c, 0x57, 0xf1, 0x1c, 0x00, 0x7a, 0xbd, 0x18, 0xfb, 0x48, 0x17, 0x6a, 0xab, - 0xc7, 0xf4, 0xe3, 0x61, 0x2c, 0x89, 0x7e, 0xf9, 0xe3, 0x3a, 0xcc, 0xf0, 0xb0, 0x7d, 0xf6, 0x61, - 0xa0, 0x22, 0xcd, 0xc9, 0xbf, 0x12, 0xc1, 0xbe, 0x0d, 0x74, 0x13, 0x0a, 0xba, 0xe1, 0xb8, 0x86, - 0xa9, 0xb9, 0xfc, 0x1e, 0x5f, 0x76, 0x13, 0xee, 0xac, 0x47, 0x65, 0x97, 0xf5, 0x36, 0x61, 0x4e, - 0x6b, 0x19, 0xbe, 0x5b, 0xc5, 0x26, 0xba, 0xb9, 0xa1, 0xc3, 0xa8, 0x42, 0xf3, 0xf6, 0x6f, 0x8d, - 0x17, 0xb5, 0x28, 0x19, 0x55, 0xa0, 0xb8, 0xaf, 0xba, 0xf8, 0x95, 0xda, 0x53, 0xbc, 0x53, 0x69, - 0x79, 0x7a, 0x12, 0xf7, 0xea, 0xe9, 0xc9, 0xf2, 0xec, 0x63, 0x96, 0x34, 0x70, 0x38, 0x6d, 0x76, - 0x3f, 0x94, 0xa0, 0xa3, 0xdb, 0x50, 0x54, 0x9d, 0x9e, 0xa9, 0xd1, 0x06, 0xc4, 0xa6, 0xd3, 0x75, - 0xa8, 0x57, 0x9c, 0x95, 0x0b, 0x94, 0x5c, 0xf1, 0xa8, 0xe8, 0x23, 0x58, 0xe4, 0xd7, 0xf5, 0xbf, - 0x52, 0x6d, 0x5d, 0xa1, 0x8d, 0x1e, 0x0c, 0x0f, 0x91, 0xf2, 0x5c, 0x66, 0xd7, 0xf3, 0x93, 0x0c, - 0xa4, 0xa5, 0xc3, 0xd7, 0xe0, 0xb2, 0x6b, 0x7e, 0x41, 0xcc, 0xaf, 0x67, 0xb2, 0x33, 0xe2, 0xec, - 0x7a, 0x26, 0x5b, 0x10, 0x8b, 0xd2, 0xbf, 0x11, 0xa0, 0x48, 0x0c, 0x94, 0xe3, 0x18, 0x96, 0x59, - 0xf3, 0x03, 0x44, 0xfd, 0x5e, 0x2b, 0xd0, 0x03, 0x42, 0xfe, 0x33, 0x5a, 0xa6, 0x07, 0xb1, 0x88, - 0x23, 0xe8, 0x7f, 0xa4, 0x23, 0x2d, 0x03, 0x23, 0xd1, 0x23, 0x31, 0xab, 0x30, 0xe5, 0x58, 0x5d, - 0x5b, 0xf3, 0xae, 0x8e, 0xbf, 0x3b, 0xc4, 0x22, 0x86, 0x5e, 0x58, 0x6a, 0x50, 0x06, 0x99, 0x33, - 0x4a, 0x25, 0x98, 0x62, 0x14, 0x94, 0x83, 0xc9, 0xa7, 0xcd, 0x5a, 0x55, 0x16, 0x27, 0xd0, 0x0c, - 0x64, 0x1f, 0xc9, 0x4f, 0x37, 0x95, 0xc6, 0xb3, 0x27, 0xa2, 0x80, 0xf2, 0x30, 0x2d, 0x3f, 0x7d, - 0xda, 0x54, 0x36, 0x9e, 0x8b, 0x29, 0xe9, 0x4f, 0x05, 0x98, 0x29, 0xb3, 0xbb, 0xf3, 0xd9, 0x66, - 0xfd, 0x47, 0x7d, 0xbb, 0xe8, 0x57, 0xe2, 0x41, 0x4a, 0xfc, 0xee, 0xf9, 0x2a, 0x64, 0x79, 0xf7, - 0xf4, 0xe2, 0xfb, 0x97, 0x87, 0xbb, 0xa6, 0x74, 0x15, 0xc7, 0x8b, 0xd1, 0xf2, 0xd8, 0x50, 0x03, - 0x44, 0xd5, 0xab, 0xa2, 0xc2, 0x4b, 0x32, 0x3c, 0x52, 0xab, 0x4f, 0x1b, 0x5e, 0x67, 0x53, 0xa3, - 0xe4, 0x0f, 0x33, 0x5f, 0xfc, 0x70, 0x79, 0x42, 0xfa, 0x8b, 0x0c, 0xcc, 0x96, 0xc3, 0xdf, 0x09, - 0x40, 0xf5, 0xbe, 0xca, 0xc6, 0x4d, 0xb8, 0x11, 0x8e, 0xd2, 0x88, 0x2f, 0xb0, 0xe4, 0x82, 0x8f, - 0x12, 0xb0, 0xba, 0x5f, 0x1b, 0x11, 0x80, 0x10, 0xae, 0x7c, 0xc0, 0xb8, 0xf8, 0x1f, 0xd2, 0xbe, - 0x01, 0x2f, 0xc1, 0x24, 0x3b, 0x43, 0x26, 0x0c, 0x1c, 0x6f, 0xa7, 0x26, 0x84, 0x38, 0x84, 0x24, - 0x5d, 0x66, 0xd9, 0x88, 0xc1, 0x6f, 0xbe, 0xd6, 0x65, 0x7e, 0xc1, 0x34, 0x79, 0xfe, 0x6f, 0x1b, - 0x76, 0xd9, 0x65, 0x8e, 0xff, 0x0f, 0x83, 0xc3, 0xc8, 0xfb, 0xd0, 0xaf, 0x42, 0x51, 0xb3, 0x5a, - 0x2d, 0xe6, 0x47, 0x30, 0xd3, 0x35, 0x78, 0xbd, 0x0b, 0x2d, 0x02, 0xff, 0x9c, 0x65, 0xc9, 0xff, - 0xac, 0x65, 0x49, 0xe6, 0x9f, 0xb5, 0x0c, 0x45, 0xee, 0x17, 0x7c, 0x61, 0xcc, 0xe2, 0xf5, 0x1d, - 0x22, 0x98, 0x7e, 0x9d, 0x43, 0x04, 0xec, 0xe8, 0x05, 0xef, 0x79, 0x7f, 0x24, 0xf0, 0x10, 0xae, - 0x27, 0x96, 0x75, 0xd8, 0xf5, 0x03, 0x63, 0x16, 0xc3, 0x57, 0x33, 0x06, 0xf1, 0xcd, 0xf4, 0x7c, - 0x4e, 0xdc, 0xd4, 0x94, 0x7a, 0xb3, 0xa9, 0xe9, 0x3a, 0xcc, 0x74, 0x6c, 0xbc, 0x87, 0x5d, 0xed, - 0x40, 0x31, 0xbb, 0x6d, 0x7e, 0x38, 0x29, 0xef, 0xd1, 0xb6, 0xba, 0x6d, 0x74, 0x17, 0x44, 0x3f, - 0x0b, 0xc7, 0x76, 0xde, 0xbd, 0x60, 0x1e, 0x9d, 0x23, 0x41, 0xe9, 0x7f, 0x0a, 0x30, 0x1f, 0xa9, - 0x13, 0x1f, 0x53, 0xeb, 0x90, 0xd7, 0x7d, 0x67, 0xc0, 0x59, 0x10, 0xce, 0x19, 0xf9, 0x1e, 0x66, - 0x46, 0x0a, 0x5c, 0xf2, 0x5e, 0x4b, 0x2f, 0xf2, 0x0f, 0xc4, 0xa6, 0xce, 0x29, 0xf6, 0x62, 0x20, - 0x67, 0x2d, 0xf4, 0x02, 0x7f, 0x90, 0xa5, 0xc7, 0x1a, 0x64, 0xd2, 0xff, 0x12, 0x40, 0xa4, 0x2f, - 0x78, 0x84, 0xb1, 0x9e, 0x88, 0xc9, 0xf4, 0x8e, 0x98, 0xa4, 0xc6, 0x3f, 0x7e, 0x14, 0xf9, 0xf8, - 0x48, 0xba, 0xef, 0xe3, 0x23, 0x71, 0xf6, 0x33, 0xf3, 0x86, 0xf6, 0x53, 0xfa, 0xa1, 0x00, 0x05, - 0xbf, 0xda, 0xec, 0xab, 0x83, 0x23, 0xae, 0x15, 0x7d, 0xbd, 0x2f, 0xeb, 0x79, 0xd7, 0x9f, 0x8c, - 0xf5, 0x21, 0xc4, 0xf0, 0xf5, 0x27, 0xec, 0x8b, 0x70, 0x7f, 0xd7, 0xeb, 0x8e, 0xa4, 0x88, 0x95, - 0xe0, 0xde, 0x89, 0xd7, 0x38, 0xde, 0xf5, 0x55, 0xc4, 0x80, 0x3d, 0x0a, 0x29, 0x90, 0xf6, 0x28, - 0xa2, 0xa5, 0xb1, 0xec, 0xbb, 0xa7, 0x25, 0xd6, 0x01, 0x7f, 0x1c, 0x6e, 0x09, 0x76, 0x6e, 0xf9, - 0x21, 0xa4, 0x8f, 0xd4, 0xd6, 0xa8, 0xa0, 0xb7, 0x48, 0xcb, 0xc9, 0x24, 0x37, 0x7a, 0x14, 0xb9, - 0xae, 0x23, 0x35, 0x7c, 0xdd, 0x67, 0x50, 0xa5, 0x91, 0x6b, 0x3d, 0xde, 0x8f, 0x0e, 0xa0, 0x91, - 0xaf, 0x0f, 0x8f, 0xa4, 0x0f, 0x33, 0x3f, 0xfa, 0xe1, 0xb2, 0x20, 0x7d, 0x0c, 0x48, 0xc6, 0x0e, - 0x76, 0x9f, 0x75, 0x2d, 0x3b, 0xb8, 0xfa, 0xa4, 0xff, 0x28, 0xc9, 0x64, 0xfc, 0x51, 0x12, 0xe9, - 0x22, 0xcc, 0x47, 0xb8, 0x99, 0x05, 0x92, 0xde, 0x87, 0x2b, 0x8f, 0x2d, 0xc7, 0x31, 0x3a, 0x04, - 0xe1, 0xd2, 0xa1, 0x4e, 0xe6, 0x2b, 0xdf, 0xe6, 0x66, 0x3b, 0x74, 0x51, 0xc1, 0x64, 0xb6, 0x29, - 0x27, 0xfb, 0xcf, 0xd2, 0xbf, 0x16, 0xe0, 0xf2, 0x20, 0x27, 0xd3, 0x72, 0xdc, 0x69, 0xd4, 0x69, - 0xcd, 0x0a, 0x6e, 0xe6, 0x3b, 0xbb, 0xb7, 0x7a, 0xd9, 0x89, 0xdb, 0xca, 0xdf, 0xa9, 0xb4, 0x55, - 0x6a, 0x93, 0xf8, 0x41, 0xf1, 0x02, 0x27, 0x6f, 0x32, 0x6a, 0x60, 0x9e, 0x32, 0xe3, 0x99, 0xa7, - 0xdf, 0x4f, 0x03, 0xa2, 0xd7, 0x21, 0x94, 0xe9, 0x7d, 0x02, 0x5e, 0x9d, 0xef, 0x42, 0xce, 0xc5, - 0xa6, 0x6a, 0xba, 0xde, 0xdd, 0x0f, 0x99, 0xf2, 0xcc, 0xe9, 0xc9, 0x72, 0xb6, 0x49, 0x89, 0xf5, - 0x35, 0x39, 0xcb, 0x92, 0xeb, 0x3a, 0xfa, 0x2b, 0xb0, 0x44, 0x66, 0x9c, 0x6e, 0x9b, 0x56, 0x5d, - 0x71, 0x0c, 0x53, 0xc3, 0x2c, 0x7c, 0x97, 0x7b, 0x68, 0xbc, 0x9f, 0xc5, 0xe1, 0xdd, 0xc1, 0x37, - 0x97, 0x2a, 0x81, 0x2c, 0xae, 0x84, 0xab, 0x21, 0xf1, 0x0d, 0x22, 0xfd, 0x89, 0xea, 0x78, 0xd9, - 0x17, 0xff, 0x5c, 0x80, 0x7c, 0x88, 0x05, 0x15, 0x21, 0x6d, 0x2b, 0x5d, 0xfa, 0x4a, 0x41, 0x4e, - 0xd9, 0x3b, 0xe8, 0x06, 0xcc, 0xd2, 0x59, 0x31, 0xe4, 0x65, 0x0a, 0x77, 0x32, 0x32, 0x0d, 0xe9, - 0x96, 0x3d, 0x17, 0xf2, 0x6d, 0x00, 0x9a, 0x89, 0x01, 0x9f, 0x34, 0xcd, 0x91, 0x23, 0x14, 0x1f, - 0xf6, 0xd0, 0x23, 0x32, 0x81, 0x10, 0x16, 0x05, 0x3f, 0x4b, 0xa9, 0xbe, 0x94, 0x65, 0xc8, 0xb3, - 0x6c, 0x4c, 0xcc, 0x24, 0xcd, 0x03, 0x94, 0xc4, 0xe4, 0x54, 0x60, 0xde, 0x79, 0xd9, 0x52, 0x3a, - 0x96, 0xae, 0x68, 0x9d, 0x2e, 0x8f, 0x2e, 0x66, 0x5f, 0x60, 0x15, 0xe8, 0xdd, 0x1a, 0x62, 0xe3, - 0xd9, 0x93, 0x6d, 0x4b, 0xaf, 0x6c, 0xef, 0xb0, 0xd0, 0x62, 0x47, 0x16, 0x9d, 0x97, 0x2d, 0x42, - 0xe9, 0x74, 0x39, 0x45, 0x6a, 0xc0, 0x7c, 0x44, 0x6d, 0x7c, 0x12, 0xfd, 0x38, 0x6a, 0x1c, 0xc2, - 0x9e, 0xa4, 0xf7, 0xcd, 0xf2, 0x52, 0xd5, 0xd4, 0x2c, 0x9d, 0x8f, 0xaa, 0xa8, 0x91, 0x68, 0x42, - 0x71, 0xdd, 0x32, 0x4c, 0x02, 0x92, 0xbc, 0x2e, 0xb0, 0x0a, 0x85, 0x5d, 0xc3, 0x54, 0xed, 0x9e, - 0xe2, 0xc5, 0x0f, 0x0b, 0x67, 0xc5, 0x0f, 0xcb, 0xb3, 0x8c, 0x83, 0x3f, 0x4a, 0x3f, 0x15, 0x40, - 0x0c, 0xc4, 0xf2, 0x82, 0x7e, 0x03, 0x40, 0x6b, 0x75, 0x1d, 0x17, 0xdb, 0xde, 0x60, 0x9d, 0x61, - 0xe7, 0x94, 0x2a, 0x8c, 0x5a, 0x5f, 0x93, 0x73, 0x3c, 0x43, 0x5d, 0x47, 0x37, 0xa2, 0x57, 0x90, - 0x4c, 0x96, 0xe1, 0x74, 0xe0, 0xe2, 0x11, 0x32, 0xfa, 0x1d, 0xd7, 0xb2, 0xfd, 0x05, 0x03, 0x3e, - 0xfa, 0xbd, 0xcb, 0x99, 0xe8, 0x25, 0x04, 0x98, 0x1e, 0x45, 0x2c, 0x10, 0x57, 0xf4, 0x08, 0xfb, - 0x55, 0xca, 0x9c, 0x5d, 0x25, 0xc6, 0xe1, 0x55, 0xe9, 0x0f, 0x04, 0x28, 0x56, 0xd8, 0xa0, 0xf4, - 0x07, 0xfa, 0x88, 0x89, 0x6d, 0x0d, 0xb2, 0xee, 0xb1, 0xa9, 0xb4, 0xb1, 0xff, 0x3d, 0xa1, 0x73, - 0xdc, 0x9e, 0x38, 0xed, 0xb2, 0x47, 0xfa, 0x89, 0x4a, 0xfe, 0x7d, 0x74, 0x6e, 0x35, 0xaf, 0x94, - 0xd8, 0x07, 0xd4, 0x4b, 0xde, 0x07, 0xd4, 0x4b, 0x6b, 0x3c, 0x03, 0x73, 0x18, 0xbe, 0xf8, 0xcf, - 0xcb, 0x82, 0xec, 0x33, 0x31, 0x9f, 0xf2, 0x5e, 0x83, 0x18, 0xbf, 0x01, 0xaf, 0x0f, 0x15, 0x00, - 0x42, 0x1f, 0x8a, 0xe2, 0x9f, 0xe4, 0x5e, 0x5d, 0x53, 0x76, 0xb6, 0x2a, 0x4f, 0x37, 0x37, 0xeb, - 0xcd, 0x66, 0x75, 0x4d, 0x14, 0x90, 0x08, 0x33, 0x91, 0xcf, 0x4c, 0xa5, 0xd8, 0x47, 0xba, 0xef, - 0xfd, 0x25, 0x80, 0xe0, 0x8b, 0x75, 0x44, 0xd6, 0x46, 0xf5, 0x53, 0xe5, 0xf9, 0xea, 0x93, 0x9d, - 0x6a, 0x43, 0x9c, 0x40, 0x08, 0x0a, 0xe5, 0xd5, 0x66, 0xa5, 0xa6, 0xc8, 0xd5, 0xc6, 0xf6, 0xd3, - 0xad, 0x46, 0xd5, 0xfb, 0xb8, 0xf7, 0xbd, 0x35, 0x98, 0x09, 0xdf, 0x09, 0x85, 0xe6, 0xa1, 0x58, - 0xa9, 0x55, 0x2b, 0x1b, 0xca, 0xf3, 0xfa, 0xaa, 0xf2, 0x6c, 0xa7, 0xba, 0x53, 0x15, 0x27, 0x68, - 0xd1, 0x28, 0xf1, 0xd1, 0xce, 0x13, 0x02, 0x44, 0x8b, 0x90, 0x67, 0xcf, 0xf4, 0x93, 0x54, 0x62, - 0xea, 0xde, 0x26, 0xe4, 0x43, 0x77, 0x55, 0x93, 0xd7, 0x6d, 0xef, 0x34, 0x6a, 0x4a, 0xb3, 0xbe, - 0x59, 0x6d, 0x34, 0x57, 0x37, 0xb7, 0x99, 0x0c, 0x4a, 0x5b, 0x2d, 0x3f, 0x95, 0x9b, 0xa2, 0xe0, - 0x3f, 0x37, 0x9f, 0xee, 0x54, 0x6a, 0x5e, 0x35, 0xa4, 0x4c, 0x36, 0x2d, 0xa6, 0xef, 0x1d, 0xc3, - 0xe5, 0x21, 0xd7, 0x23, 0x11, 0x0c, 0xbc, 0x63, 0xd2, 0x7b, 0x7b, 0xc5, 0x09, 0x34, 0x0b, 0x39, - 0xd2, 0xf5, 0xe8, 0xe1, 0x69, 0x51, 0x40, 0x59, 0xc8, 0x1c, 0xb8, 0x6e, 0x47, 0x4c, 0xa1, 0x29, - 0x48, 0x39, 0x0f, 0xc5, 0x34, 0xf9, 0xbf, 0xef, 0x88, 0x19, 0x02, 0xa9, 0xd5, 0xcf, 0xbb, 0x36, - 0x16, 0x27, 0x09, 0xa4, 0xee, 0x3a, 0xd8, 0xde, 0x33, 0x5a, 0x58, 0x9c, 0x26, 0x2c, 0x66, 0xb7, - 0xd5, 0x12, 0xb3, 0x52, 0x26, 0x3b, 0x25, 0x4e, 0xdd, 0xbb, 0x0e, 0xa1, 0x5b, 0x2a, 0x10, 0xc0, - 0xd4, 0x13, 0xd5, 0xc5, 0x8e, 0x2b, 0x4e, 0xa0, 0x69, 0x48, 0xaf, 0xb6, 0x5a, 0xa2, 0xf0, 0xe0, - 0x8b, 0x49, 0xc8, 0x7a, 0x5f, 0x5c, 0x42, 0x4f, 0x60, 0x92, 0xc2, 0x4c, 0xb4, 0x3c, 0x1c, 0x80, - 0x32, 0x0b, 0x79, 0xed, 0x2c, 0x84, 0x2a, 0x4d, 0xa0, 0xbf, 0x0c, 0xf9, 0x90, 0x63, 0x8e, 0x86, - 0xae, 0xdb, 0x46, 0xc0, 0xc8, 0xe2, 0xad, 0xb3, 0xb2, 0xf9, 0xf2, 0x5f, 0x40, 0xce, 0x9f, 0xd3, - 0xd1, 0x8d, 0x51, 0x33, 0xbe, 0x27, 0x7b, 0xb4, 0x5b, 0x40, 0x86, 0x9d, 0x34, 0xf1, 0x9e, 0x80, - 0x6c, 0x40, 0x83, 0xd3, 0x2f, 0x8a, 0x8b, 0x8d, 0x1c, 0x3a, 0xbf, 0x2f, 0xde, 0x1b, 0x2b, 0x77, - 0xf0, 0x4e, 0xa2, 0xac, 0xc0, 0x87, 0x88, 0x57, 0xd6, 0x80, 0x87, 0x12, 0xaf, 0xac, 0x18, 0x57, - 0x84, 0x36, 0x46, 0xc8, 0xc0, 0xc7, 0xca, 0x1f, 0x9c, 0x37, 0x63, 0xe5, 0xc7, 0xcc, 0x13, 0xd2, - 0x04, 0x7a, 0x06, 0x19, 0x62, 0x94, 0x51, 0x9c, 0x77, 0xdf, 0x37, 0x09, 0x2c, 0xde, 0x18, 0x99, - 0xc7, 0x13, 0x59, 0xbe, 0xfb, 0xa3, 0xff, 0xb2, 0x34, 0xf1, 0xa3, 0xd3, 0x25, 0xe1, 0xa7, 0xa7, - 0x4b, 0xc2, 0x1f, 0x9f, 0x2e, 0x09, 0x7f, 0x72, 0xba, 0x24, 0x7c, 0xff, 0x67, 0x4b, 0x13, 0x3f, - 0xfd, 0xd9, 0xd2, 0xc4, 0x1f, 0xff, 0x6c, 0x69, 0xe2, 0xb3, 0x69, 0xce, 0xbd, 0x3b, 0x45, 0x2d, - 0xd6, 0xc3, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xcc, 0x77, 0xa3, 0x5b, 0x70, 0x83, 0x00, 0x00, + 0x2c, 0x5e, 0xa1, 0xf2, 0xee, 0xc6, 0x4e, 0x88, 0x71, 0x51, 0x59, 0x75, 0x82, 0x28, 0xa2, 0x29, + 0xe8, 0x13, 0x98, 0xa7, 0xf2, 0x14, 0x2d, 0xb8, 0x20, 0x66, 0x71, 0x71, 0xe8, 0xba, 0x91, 0xd1, + 0x77, 0xc9, 0x78, 0x92, 0x45, 0x6d, 0x20, 0x89, 0x8c, 0x07, 0xc3, 0x34, 0x5c, 0x3a, 0x77, 0x2f, + 0x8d, 0x1c, 0x0f, 0xd1, 0xcb, 0x31, 0xc9, 0x78, 0x30, 0x18, 0x85, 0x74, 0xe3, 0x01, 0x8b, 0xf7, + 0xc6, 0xc8, 0x6e, 0x3c, 0xc2, 0xd8, 0x15, 0xdc, 0x88, 0x9d, 0x5b, 0x07, 0x60, 0x38, 0x92, 0xba, + 0xc6, 0xcb, 0x23, 0x1d, 0x80, 0xc1, 0x50, 0x44, 0xe2, 0x00, 0xb4, 0x3d, 0x1a, 0x71, 0x00, 0xd8, + 0xa6, 0xc7, 0xe2, 0xb5, 0xd1, 0x93, 0x55, 0x78, 0x5b, 0x94, 0x4e, 0x56, 0x94, 0x80, 0xd6, 0x20, + 0x47, 0x9c, 0xfa, 0x3e, 0x1d, 0xe1, 0xd7, 0x47, 0x62, 0xf8, 0x81, 0x33, 0x4a, 0xf5, 0x29, 0x39, + 0xfb, 0x82, 0x93, 0x48, 0xaf, 0x62, 0x22, 0xf8, 0xd8, 0xbe, 0x37, 0xb2, 0x57, 0x0d, 0x1f, 0x4e, + 0x21, 0xbd, 0xea, 0x45, 0x40, 0x0d, 0xa6, 0x3c, 0x87, 0x6d, 0x67, 0x2c, 0xbe, 0x35, 0x7e, 0xca, + 0x8b, 0x6e, 0xbe, 0xf8, 0x53, 0x1e, 0x27, 0xb3, 0x29, 0x4f, 0x57, 0x1c, 0x87, 0x46, 0x38, 0x2c, + 0xde, 0x1c, 0x33, 0xe5, 0x0d, 0x2c, 0x70, 0xb2, 0x29, 0x4f, 0x6f, 0x32, 0x4e, 0xe2, 0xfd, 0xd9, + 0xde, 0xed, 0x3a, 0x1c, 0xde, 0xdd, 0x1e, 0xe9, 0xfd, 0xc5, 0x5e, 0xff, 0x43, 0xbc, 0x3f, 0x3b, + 0x92, 0x80, 0x7e, 0x09, 0x66, 0xf9, 0x82, 0xd2, 0xe2, 0x9d, 0x31, 0x3e, 0x76, 0x78, 0x0d, 0x90, + 0x74, 0x47, 0xce, 0xc3, 0x8c, 0x03, 0x5b, 0xc8, 0x62, 0xc6, 0xef, 0xee, 0x18, 0xe3, 0x30, 0xb4, + 0x96, 0xc6, 0x8c, 0x43, 0x40, 0x26, 0xa5, 0x71, 0xd8, 0x22, 0xcc, 0xe2, 0x2f, 0x8c, 0x2c, 0x4d, + 0x74, 0x35, 0x8a, 0x94, 0x86, 0xf3, 0xd0, 0xc9, 0x82, 0xce, 0xd5, 0x4c, 0x3b, 0xdf, 0x18, 0x3d, + 0x59, 0x0c, 0xc2, 0xfa, 0xba, 0xb7, 0x5d, 0xc4, 0xb4, 0xf2, 0xd7, 0x05, 0xb8, 0xc6, 0xfa, 0x00, + 0x5d, 0x2c, 0xef, 0x2b, 0xfe, 0x5e, 0x47, 0x68, 0xcd, 0xe2, 0x3e, 0x15, 0xff, 0xee, 0xc5, 0x97, + 0xe6, 0xbd, 0x37, 0xbe, 0xa9, 0x8e, 0xcb, 0x47, 0x94, 0xd1, 0x61, 0xe8, 0x6e, 0xf1, 0xc1, 0x48, + 0x65, 0x44, 0x11, 0x29, 0x51, 0x06, 0xe7, 0x41, 0x6d, 0x58, 0x64, 0x43, 0x22, 0x40, 0x3f, 0x7e, + 0xd1, 0x1f, 0x8e, 0x0c, 0x1a, 0x1c, 0x8b, 0xfb, 0xea, 0x53, 0xf2, 0x95, 0x17, 0xb1, 0x19, 0x2a, + 0xb3, 0x7c, 0xf3, 0xd9, 0x3f, 0x68, 0x5a, 0x12, 0xc5, 0x8d, 0x4c, 0xf6, 0xaa, 0xb8, 0xb8, 0x91, + 0xc9, 0xbe, 0x26, 0x2e, 0x6d, 0x64, 0xb2, 0xaf, 0x8b, 0x6f, 0x6c, 0x64, 0xb2, 0x2b, 0xe2, 0xb5, + 0x8d, 0x4c, 0x56, 0x12, 0x6f, 0x48, 0xbf, 0xbb, 0x04, 0x05, 0x0f, 0xbd, 0x31, 0x14, 0xf5, 0x20, + 0x8c, 0xa2, 0x96, 0x47, 0xa1, 0x28, 0x8e, 0xf7, 0x38, 0x8c, 0x7a, 0x10, 0x86, 0x51, 0xcb, 0xa3, + 0x60, 0x54, 0xc0, 0x43, 0x70, 0x54, 0x6b, 0x14, 0x8e, 0xba, 0x3b, 0x01, 0x8e, 0xf2, 0x45, 0x0d, + 0x02, 0xa9, 0xf5, 0x61, 0x20, 0xf5, 0xd6, 0x78, 0x20, 0xe5, 0x8b, 0x0a, 0x21, 0xa9, 0x0f, 0x06, + 0x90, 0xd4, 0xf5, 0x31, 0x48, 0xca, 0xe7, 0xf7, 0xa0, 0xd4, 0x66, 0x2c, 0x94, 0xba, 0x75, 0x1e, + 0x94, 0xf2, 0xe5, 0x44, 0xb0, 0x54, 0x3d, 0x0e, 0x4b, 0xdd, 0x3c, 0x07, 0x4b, 0xf9, 0xa2, 0xc2, + 0x60, 0x6a, 0x33, 0x16, 0x4c, 0xdd, 0x3a, 0x0f, 0x4c, 0x05, 0xc5, 0x0a, 0xa3, 0xa9, 0x6f, 0x45, + 0xd0, 0xd4, 0xca, 0x48, 0x34, 0xe5, 0x73, 0x33, 0x38, 0xf5, 0xe1, 0x20, 0x9c, 0xba, 0x3e, 0x06, + 0x4e, 0x05, 0x8a, 0xe5, 0x78, 0xaa, 0x1e, 0x87, 0xa7, 0x6e, 0x9e, 0x83, 0xa7, 0x02, 0x5d, 0x84, + 0x00, 0xd5, 0x76, 0x3c, 0xa0, 0xba, 0x7d, 0x2e, 0xa0, 0xf2, 0xa5, 0x45, 0x11, 0x55, 0x3d, 0x0e, + 0x51, 0xdd, 0x3c, 0x07, 0x51, 0x0d, 0x94, 0x8c, 0x41, 0x2a, 0x75, 0x2c, 0xa4, 0x7a, 0x7b, 0x42, + 0x48, 0xe5, 0x8b, 0x8e, 0xc3, 0x54, 0xfa, 0x78, 0x4c, 0x55, 0x9e, 0x14, 0x53, 0xf9, 0x2f, 0x89, + 0x05, 0x55, 0xea, 0x58, 0x50, 0xf5, 0xf6, 0x84, 0xa0, 0x6a, 0xa0, 0x22, 0x51, 0x54, 0xb5, 0x1d, + 0x8f, 0xaa, 0x6e, 0x9f, 0x8b, 0xaa, 0x82, 0x56, 0x8c, 0xc0, 0xaa, 0xd5, 0x10, 0xac, 0x7a, 0x73, + 0x04, 0xac, 0xf2, 0x59, 0x09, 0xae, 0xfa, 0xf6, 0x10, 0xae, 0x92, 0xc6, 0xe1, 0x2a, 0x9f, 0xd7, + 0x07, 0x56, 0xf5, 0x38, 0x60, 0x75, 0xf3, 0x1c, 0x60, 0x15, 0xf4, 0x9b, 0x10, 0xb2, 0x7a, 0x36, + 0x02, 0x59, 0xdd, 0x39, 0x1f, 0x59, 0xf9, 0xf2, 0x06, 0xa0, 0x95, 0x3a, 0x16, 0x5a, 0xbd, 0x3d, + 0x21, 0xb4, 0x0a, 0x5a, 0x30, 0x06, 0x5b, 0xbd, 0x17, 0xc5, 0x56, 0xd7, 0x46, 0x63, 0x2b, 0x5f, + 0x0c, 0x07, 0x57, 0x9b, 0xb1, 0xe0, 0xea, 0xd6, 0x79, 0xe0, 0x2a, 0xb0, 0x66, 0x61, 0x74, 0xb5, + 0x1d, 0x8f, 0xae, 0x6e, 0x9f, 0x8b, 0xae, 0x82, 0x8e, 0x14, 0x81, 0x57, 0x9b, 0xb1, 0xf0, 0xea, + 0xd6, 0x79, 0xf0, 0x6a, 0xc0, 0xd4, 0x72, 0x7c, 0xf5, 0xf1, 0x48, 0x7c, 0x75, 0x6f, 0x12, 0x7c, + 0xe5, 0x0b, 0x1d, 0x02, 0x58, 0x9f, 0x8e, 0x06, 0x58, 0xbf, 0x70, 0x81, 0xcb, 0x3a, 0x63, 0x11, + 0xd6, 0xb7, 0x87, 0x10, 0x96, 0x34, 0x0e, 0x61, 0x05, 0x23, 0xc3, 0x83, 0x58, 0xb5, 0x18, 0x40, + 0xf4, 0xd6, 0x78, 0x40, 0x14, 0x4c, 0xe4, 0x01, 0x22, 0xfa, 0x60, 0x00, 0x11, 0x5d, 0x3f, 0x37, + 0x2e, 0x2e, 0x04, 0x89, 0x2a, 0xc3, 0x90, 0xe8, 0xc6, 0x58, 0x48, 0xe4, 0x4b, 0x08, 0x30, 0xd1, + 0x66, 0x2c, 0x26, 0xba, 0x75, 0x1e, 0x26, 0x0a, 0xba, 0x42, 0x18, 0x14, 0x6d, 0xc7, 0x83, 0xa2, + 0xdb, 0xe7, 0x82, 0xa2, 0x81, 0x69, 0xcb, 0x43, 0x45, 0xf5, 0x38, 0x54, 0x74, 0xf3, 0x1c, 0x54, + 0x14, 0x9e, 0xb6, 0x7c, 0x58, 0xd4, 0x1a, 0x05, 0x8b, 0xee, 0x4e, 0x00, 0x8b, 0x02, 0x67, 0x6e, + 0x00, 0x17, 0x7d, 0x34, 0x88, 0x8b, 0xa4, 0x71, 0xb8, 0x28, 0xe8, 0x44, 0x1e, 0x30, 0xda, 0x8e, + 0x07, 0x46, 0xb7, 0xcf, 0x05, 0x46, 0xe1, 0x71, 0x1d, 0x42, 0x46, 0x1f, 0x0d, 0x22, 0x23, 0x69, + 0x1c, 0x32, 0x0a, 0xca, 0xe3, 0x41, 0xa3, 0x7a, 0x1c, 0x34, 0xba, 0x79, 0x0e, 0x34, 0x0a, 0x99, + 0xfb, 0x00, 0x1b, 0xfd, 0x8d, 0xc9, 0xb1, 0xd1, 0x7b, 0xaf, 0x1a, 0xb6, 0x74, 0x3e, 0x38, 0xfa, + 0x68, 0x10, 0x1c, 0x49, 0xe3, 0xc0, 0x51, 0xa0, 0x0f, 0x0f, 0x1d, 0x75, 0xce, 0x45, 0x47, 0xf7, + 0x2f, 0x80, 0x8e, 0x7c, 0xf9, 0x5f, 0x1a, 0x1e, 0xbd, 0x21, 0xbe, 0x19, 0x01, 0x49, 0x7f, 0x36, + 0x03, 0x33, 0xfc, 0x3b, 0x55, 0x91, 0xbb, 0x9d, 0x84, 0x57, 0xb9, 0xdb, 0x09, 0xad, 0x93, 0x5e, + 0x4d, 0xbd, 0xa4, 0xf3, 0x6f, 0x04, 0x1c, 0xbe, 0xb3, 0x8e, 0xb3, 0xbe, 0xc2, 0x21, 0x6b, 0xf4, + 0x2d, 0x28, 0xf4, 0x1c, 0x6c, 0x2b, 0x5d, 0xdb, 0xb0, 0x6c, 0xc3, 0x65, 0xc7, 0x45, 0x84, 0x8a, + 0xf8, 0xc5, 0xe9, 0xca, 0xdc, 0xae, 0x83, 0xed, 0x1d, 0x4e, 0x97, 0xe7, 0x7a, 0xa1, 0x27, 0xef, + 0xd3, 0x5c, 0xd3, 0x93, 0x7f, 0x9a, 0xeb, 0x19, 0x88, 0x34, 0x18, 0x20, 0x3c, 0xb1, 0xb0, 0x7b, + 0x94, 0xe2, 0xe7, 0x40, 0x55, 0x0f, 0xcd, 0x1d, 0xf4, 0x3e, 0xa5, 0x92, 0x1d, 0x25, 0xa2, 0x26, + 0xd0, 0x1b, 0x4e, 0x94, 0xae, 0xd5, 0x36, 0xb4, 0x3e, 0xf5, 0x17, 0xa2, 0x77, 0x4a, 0x8f, 0xbd, + 0xd9, 0xfd, 0x63, 0xd5, 0x70, 0x77, 0x28, 0xa7, 0x0c, 0x2f, 0xfd, 0xdf, 0xe8, 0x3e, 0x5c, 0xee, + 0xa8, 0x27, 0xf4, 0xb2, 0x5d, 0xc5, 0x73, 0x00, 0xe8, 0xf5, 0x62, 0xec, 0x23, 0x5d, 0xa8, 0xa3, + 0x9e, 0xd0, 0x8f, 0x87, 0xb1, 0x24, 0xfa, 0xe5, 0x8f, 0xeb, 0x30, 0xc7, 0xc3, 0xf6, 0xd9, 0x87, + 0x81, 0x4a, 0x34, 0x27, 0xff, 0x4a, 0x04, 0xfb, 0x36, 0xd0, 0x4d, 0x28, 0xea, 0x86, 0xe3, 0x1a, + 0xa6, 0xe6, 0xf2, 0x7b, 0x7c, 0xd9, 0x4d, 0xb8, 0x05, 0x8f, 0xca, 0x2e, 0xeb, 0x6d, 0xc1, 0xbc, + 0xd6, 0x36, 0x7c, 0xb7, 0x8a, 0x4d, 0x74, 0xf3, 0x23, 0x87, 0x51, 0x95, 0xe6, 0x1d, 0xdc, 0x1a, + 0x2f, 0x69, 0x51, 0x32, 0xaa, 0x42, 0xe9, 0x40, 0x75, 0xf1, 0x4b, 0xb5, 0xaf, 0x78, 0xa7, 0xd2, + 0xf2, 0xf4, 0x24, 0xee, 0xeb, 0x67, 0xa7, 0x2b, 0x85, 0xc7, 0x2c, 0x69, 0xe8, 0x70, 0x5a, 0xe1, + 0x20, 0x94, 0xa0, 0xa3, 0xdb, 0x50, 0x52, 0x9d, 0xbe, 0xa9, 0xd1, 0x06, 0xc4, 0xa6, 0xd3, 0x73, + 0xa8, 0x57, 0x9c, 0x95, 0x8b, 0x94, 0x5c, 0xf5, 0xa8, 0xe8, 0x03, 0x58, 0xe2, 0xd7, 0xf5, 0xbf, + 0x54, 0x6d, 0x5d, 0xa1, 0x8d, 0x1e, 0x0c, 0x0f, 0x91, 0xf2, 0x5c, 0x65, 0xd7, 0xf3, 0x93, 0x0c, + 0xa4, 0xa5, 0xc3, 0xd7, 0xe0, 0xb2, 0x6b, 0x7e, 0x41, 0xcc, 0x6f, 0x64, 0xb2, 0x73, 0x62, 0x61, + 0x23, 0x93, 0x2d, 0x8a, 0x25, 0xe9, 0xdf, 0x08, 0x50, 0x22, 0x06, 0xca, 0x71, 0x0c, 0xcb, 0xac, + 0xfb, 0x01, 0xa2, 0x7e, 0xaf, 0x15, 0xe8, 0x01, 0x21, 0xff, 0x19, 0xad, 0xd0, 0x83, 0x58, 0xc4, + 0x11, 0xf4, 0x3f, 0xd2, 0x91, 0x96, 0x81, 0x91, 0xe8, 0x91, 0x98, 0x35, 0x98, 0x71, 0xac, 0x9e, + 0xad, 0x79, 0x57, 0xc7, 0xdf, 0x1d, 0x61, 0x11, 0x43, 0x2f, 0x2c, 0x37, 0x29, 0x83, 0xcc, 0x19, + 0xa5, 0x32, 0xcc, 0x30, 0x0a, 0xca, 0xc1, 0xf4, 0xd3, 0x56, 0xbd, 0x26, 0x8b, 0x53, 0x68, 0x0e, + 0xb2, 0x8f, 0xe4, 0xa7, 0x5b, 0x4a, 0xf3, 0xd9, 0x13, 0x51, 0x40, 0x79, 0x98, 0x95, 0x9f, 0x3e, + 0x6d, 0x29, 0x9b, 0xcf, 0xc5, 0x94, 0xf4, 0xa7, 0x02, 0xcc, 0x55, 0xd8, 0xdd, 0xf9, 0x6c, 0xb3, + 0xfe, 0x83, 0x81, 0x5d, 0xf4, 0xd7, 0xe2, 0x41, 0x4a, 0xfc, 0xee, 0xf9, 0x1a, 0x64, 0x79, 0xf7, + 0xf4, 0xe2, 0xfb, 0x57, 0x46, 0xbb, 0xa6, 0x74, 0x15, 0xc7, 0x8b, 0xd1, 0xf2, 0xd8, 0x50, 0x13, + 0x44, 0xd5, 0xab, 0xa2, 0xc2, 0x4b, 0x32, 0x3a, 0x52, 0x6b, 0x40, 0x1b, 0x5e, 0x67, 0x53, 0xa3, + 0xe4, 0xf7, 0x33, 0x9f, 0xff, 0x70, 0x65, 0x4a, 0xfa, 0x8b, 0x0c, 0x14, 0x2a, 0xe1, 0xef, 0x04, + 0xa0, 0xc6, 0x40, 0x65, 0xe3, 0x26, 0xdc, 0x08, 0x47, 0x79, 0xcc, 0x17, 0x58, 0x72, 0xc1, 0x47, + 0x09, 0x58, 0xdd, 0xaf, 0x8d, 0x09, 0x40, 0x08, 0x57, 0x3e, 0x60, 0x5c, 0xfa, 0x0f, 0x69, 0xdf, + 0x80, 0x97, 0x61, 0x9a, 0x9d, 0x21, 0x13, 0x86, 0x8e, 0xb7, 0x53, 0x13, 0x42, 0x1c, 0x42, 0x92, + 0x2e, 0xb3, 0x6c, 0xc4, 0xe0, 0xb7, 0x5e, 0xe9, 0x32, 0xbf, 0x60, 0x9a, 0xbc, 0xf8, 0xb7, 0x0d, + 0x7b, 0xec, 0x32, 0xc7, 0xff, 0x87, 0xc1, 0x61, 0xe4, 0x7d, 0xe8, 0x57, 0xa1, 0xa4, 0x59, 0xed, + 0x36, 0xf3, 0x23, 0x98, 0xe9, 0x1a, 0xbe, 0xde, 0x85, 0x16, 0x81, 0x7f, 0xce, 0xb2, 0xec, 0x7f, + 0xd6, 0xb2, 0x2c, 0xf3, 0xcf, 0x5a, 0x86, 0x22, 0xf7, 0x8b, 0xbe, 0x30, 0x66, 0xf1, 0x06, 0x0e, + 0x11, 0xcc, 0xbe, 0xca, 0x21, 0x02, 0x76, 0xf4, 0x82, 0xf7, 0xbc, 0x3f, 0x12, 0x78, 0x08, 0xd7, + 0x13, 0xcb, 0x3a, 0xea, 0xf9, 0x81, 0x31, 0x4b, 0xe1, 0xab, 0x19, 0x83, 0xf8, 0x66, 0x7a, 0x3e, + 0x27, 0x6e, 0x6a, 0x4a, 0x7d, 0xb9, 0xa9, 0xe9, 0x3a, 0xcc, 0x75, 0x6d, 0xbc, 0x8f, 0x5d, 0xed, + 0x50, 0x31, 0x7b, 0x1d, 0x7e, 0x38, 0x29, 0xef, 0xd1, 0xb6, 0x7b, 0x1d, 0x74, 0x17, 0x44, 0x3f, + 0x0b, 0xc7, 0x76, 0xde, 0xbd, 0x60, 0x1e, 0x9d, 0x23, 0x41, 0xe9, 0x7f, 0x0a, 0xb0, 0x10, 0xa9, + 0x13, 0x1f, 0x53, 0x1b, 0x90, 0xd7, 0x7d, 0x67, 0xc0, 0x59, 0x14, 0x2e, 0x18, 0xf9, 0x1e, 0x66, + 0x46, 0x0a, 0x5c, 0xf1, 0x5e, 0x4b, 0x2f, 0xf2, 0x0f, 0xc4, 0xa6, 0x2e, 0x28, 0xf6, 0x72, 0x20, + 0x67, 0x3d, 0xf4, 0x02, 0x7f, 0x90, 0xa5, 0x27, 0x1a, 0x64, 0xd2, 0xff, 0x12, 0x40, 0xa4, 0x2f, + 0x78, 0x84, 0xb1, 0x9e, 0x88, 0xc9, 0xf4, 0x8e, 0x98, 0xa4, 0x26, 0x3f, 0x7e, 0x14, 0xf9, 0xf8, + 0x48, 0x7a, 0xe0, 0xe3, 0x23, 0x71, 0xf6, 0x33, 0xf3, 0x25, 0xed, 0xa7, 0xf4, 0x43, 0x01, 0x8a, + 0x7e, 0xb5, 0xd9, 0x57, 0x07, 0xc7, 0x5c, 0x2b, 0xfa, 0x6a, 0x5f, 0xd6, 0xf3, 0xae, 0x3f, 0x99, + 0xe8, 0x43, 0x88, 0xe1, 0xeb, 0x4f, 0xd8, 0x17, 0xe1, 0xfe, 0x8e, 0xd7, 0x1d, 0x49, 0x11, 0xab, + 0xc1, 0xbd, 0x13, 0xaf, 0x70, 0xbc, 0xeb, 0xab, 0x88, 0x01, 0x7b, 0x14, 0x52, 0x20, 0xed, 0x51, + 0x44, 0x4b, 0x13, 0xd9, 0x77, 0x4f, 0x4b, 0xac, 0x03, 0xfe, 0x38, 0xdc, 0x12, 0xec, 0xdc, 0xf2, + 0x43, 0x48, 0x1f, 0xab, 0xed, 0x71, 0x41, 0x6f, 0x91, 0x96, 0x93, 0x49, 0x6e, 0xf4, 0x28, 0x72, + 0x5d, 0x47, 0x6a, 0xf4, 0xba, 0xcf, 0xb0, 0x4a, 0x23, 0xd7, 0x7a, 0xbc, 0x1b, 0x1d, 0x40, 0x63, + 0x5f, 0x1f, 0x1e, 0x49, 0xef, 0x67, 0x7e, 0xf4, 0xc3, 0x15, 0x41, 0xfa, 0x10, 0x90, 0x8c, 0x1d, + 0xec, 0x3e, 0xeb, 0x59, 0x76, 0x70, 0xf5, 0xc9, 0xe0, 0x51, 0x92, 0xe9, 0xf8, 0xa3, 0x24, 0xd2, + 0x65, 0x58, 0x88, 0x70, 0x33, 0x0b, 0x24, 0xbd, 0x0b, 0xaf, 0x3d, 0xb6, 0x1c, 0xc7, 0xe8, 0x12, + 0x84, 0x4b, 0x87, 0x3a, 0x99, 0xaf, 0x7c, 0x9b, 0x9b, 0xed, 0xd2, 0x45, 0x05, 0x93, 0xd9, 0xa6, + 0x9c, 0xec, 0x3f, 0x4b, 0xff, 0x5a, 0x80, 0xab, 0xc3, 0x9c, 0x4c, 0xcb, 0x71, 0xa7, 0x51, 0x67, + 0x35, 0x2b, 0xb8, 0x99, 0xef, 0xfc, 0xde, 0xea, 0x65, 0x27, 0x6e, 0x2b, 0x7f, 0xa7, 0xd2, 0x51, + 0xa9, 0x4d, 0xe2, 0x07, 0xc5, 0x8b, 0x9c, 0xbc, 0xc5, 0xa8, 0x81, 0x79, 0xca, 0x4c, 0x66, 0x9e, + 0x7e, 0x33, 0x03, 0x88, 0x5e, 0x87, 0x50, 0xa1, 0xf7, 0x09, 0x78, 0x75, 0xfe, 0x2b, 0xb0, 0x4c, + 0xa6, 0x91, 0x5e, 0x87, 0xd6, 0x47, 0x71, 0x0c, 0x53, 0xc3, 0x2c, 0x26, 0x97, 0xbb, 0x5d, 0xbc, + 0xf3, 0xc4, 0x81, 0xd8, 0x61, 0x71, 0xe5, 0x6a, 0x20, 0x8b, 0xd7, 0xec, 0xf5, 0x90, 0xf8, 0x26, + 0x91, 0xfe, 0x44, 0x75, 0xfc, 0xb7, 0xdf, 0x85, 0x9c, 0x8b, 0x4d, 0xd5, 0x74, 0xbd, 0x9b, 0x27, + 0x32, 0x95, 0xb9, 0xb3, 0xd3, 0x95, 0x6c, 0x8b, 0x12, 0x1b, 0xeb, 0x72, 0x96, 0x25, 0x37, 0x74, + 0xb4, 0x0a, 0x79, 0xc3, 0x74, 0x5c, 0x95, 0x94, 0x8f, 0xc3, 0xc5, 0x02, 0x3b, 0xe5, 0xd8, 0xe0, + 0xe4, 0xc6, 0xba, 0x0c, 0x5e, 0x16, 0x7a, 0x98, 0xa8, 0xe8, 0x33, 0xb0, 0x15, 0x51, 0x7a, 0xf2, + 0x4d, 0x2e, 0x78, 0x54, 0xba, 0xec, 0xb6, 0xf4, 0xe7, 0x02, 0xe4, 0x43, 0xa5, 0x46, 0x25, 0x48, + 0xdb, 0x4a, 0x8f, 0xd6, 0x5a, 0x90, 0x53, 0xf6, 0x2e, 0xba, 0x01, 0x05, 0x3a, 0xdb, 0x86, 0xbc, + 0x57, 0xe1, 0x4e, 0x46, 0xa6, 0xa1, 0xe2, 0xb2, 0xe7, 0x9a, 0xbe, 0x09, 0x40, 0x33, 0x31, 0x40, + 0x95, 0xa6, 0x39, 0x72, 0x84, 0xe2, 0xc3, 0x29, 0x7a, 0xf4, 0x26, 0x10, 0xc2, 0xa2, 0xeb, 0x0b, + 0x94, 0xea, 0x4b, 0x59, 0x81, 0x3c, 0xcb, 0xc6, 0xc4, 0x4c, 0xd3, 0x3c, 0x40, 0x49, 0x4c, 0x4e, + 0x15, 0x16, 0x9c, 0x17, 0x6d, 0xa5, 0x6b, 0xe9, 0x8a, 0xd6, 0xed, 0xf1, 0xa8, 0x65, 0xf6, 0x65, + 0x57, 0x81, 0xde, 0xd9, 0x21, 0x36, 0x9f, 0x3d, 0xd9, 0xb1, 0xf4, 0xea, 0xce, 0x2e, 0x0b, 0x59, + 0x76, 0x64, 0xd1, 0x79, 0xd1, 0x26, 0x94, 0x6e, 0x8f, 0x53, 0xa4, 0x26, 0x2c, 0x44, 0x5a, 0x8e, + 0x4f, 0xce, 0x1f, 0x46, 0x8d, 0x4e, 0xd8, 0x43, 0xf5, 0xbe, 0x85, 0x5e, 0xae, 0x99, 0x9a, 0xa5, + 0xf3, 0xd1, 0x1a, 0x35, 0x3e, 0x2d, 0x28, 0x6d, 0x58, 0x86, 0x49, 0xc0, 0x97, 0xd7, 0xb8, 0x6b, + 0x50, 0xdc, 0x33, 0x4c, 0xd5, 0xee, 0x2b, 0x5e, 0x5c, 0xb2, 0x70, 0x5e, 0x5c, 0xb2, 0x5c, 0x60, + 0x1c, 0xfc, 0x51, 0xfa, 0xa9, 0x00, 0x62, 0x20, 0x96, 0x17, 0xf4, 0x1b, 0x00, 0x5a, 0xbb, 0xe7, + 0xb8, 0xd8, 0xf6, 0x8c, 0xc0, 0x1c, 0x3b, 0xff, 0x54, 0x65, 0xd4, 0xc6, 0xba, 0x9c, 0xe3, 0x19, + 0x1a, 0x3a, 0xba, 0x11, 0xbd, 0xda, 0x64, 0xba, 0x02, 0x67, 0x43, 0x17, 0x9a, 0x10, 0xab, 0xe2, + 0xb8, 0x96, 0xed, 0xf7, 0x2c, 0x6e, 0x55, 0xbc, 0x4b, 0x9f, 0xe8, 0xe5, 0x06, 0x98, 0x1e, 0x71, + 0x2c, 0x12, 0x17, 0xf7, 0x18, 0xfb, 0x55, 0xca, 0x9c, 0x5f, 0x25, 0xc6, 0xe1, 0x55, 0xe9, 0x0f, + 0x04, 0x28, 0x55, 0xd9, 0x60, 0xf7, 0x0d, 0xc8, 0x98, 0x09, 0x73, 0x1d, 0xb2, 0xee, 0x89, 0xa9, + 0x74, 0xb0, 0xff, 0x9d, 0xa2, 0x0b, 0xdc, 0xca, 0x38, 0xeb, 0xb2, 0x47, 0xfa, 0xe9, 0x4b, 0xfe, + 0xdd, 0x75, 0x6e, 0x8d, 0x5f, 0x2b, 0xb3, 0x0f, 0xb3, 0x97, 0xbd, 0x0f, 0xb3, 0x97, 0xd7, 0x79, + 0x06, 0xe6, 0x88, 0x7c, 0xfe, 0x9f, 0x57, 0x04, 0xd9, 0x67, 0x62, 0xbe, 0xea, 0xbd, 0x26, 0x31, + 0xaa, 0x43, 0xde, 0x24, 0x2a, 0x02, 0x84, 0x3e, 0x40, 0xc5, 0x3f, 0xf5, 0xbd, 0xb6, 0xae, 0xec, + 0x6e, 0x57, 0x9f, 0x6e, 0x6d, 0x35, 0x5a, 0xad, 0xda, 0xba, 0x28, 0x20, 0x11, 0xe6, 0x22, 0x9f, + 0xaf, 0x4a, 0xb1, 0x8f, 0x7f, 0xdf, 0xfb, 0x4b, 0x00, 0xc1, 0x97, 0xf0, 0x88, 0xac, 0xcd, 0xda, + 0x27, 0xca, 0xf3, 0xb5, 0x27, 0xbb, 0xb5, 0xa6, 0x38, 0x85, 0x10, 0x14, 0x2b, 0x6b, 0xad, 0x6a, + 0x5d, 0x91, 0x6b, 0xcd, 0x9d, 0xa7, 0xdb, 0xcd, 0x9a, 0xf7, 0xd1, 0xf0, 0x7b, 0xeb, 0x30, 0x17, + 0xbe, 0x6b, 0x0a, 0x2d, 0x40, 0xa9, 0x5a, 0xaf, 0x55, 0x37, 0x95, 0xe7, 0x8d, 0x35, 0xe5, 0xd9, + 0x6e, 0x6d, 0xb7, 0x26, 0x4e, 0xd1, 0xa2, 0x51, 0xe2, 0xa3, 0xdd, 0x27, 0x04, 0xe0, 0x96, 0x20, + 0xcf, 0x9e, 0xe9, 0xa7, 0xae, 0xc4, 0xd4, 0xbd, 0x2d, 0xc8, 0x87, 0xee, 0xc0, 0x26, 0xaf, 0xdb, + 0xd9, 0x6d, 0xd6, 0x95, 0x56, 0x63, 0xab, 0xd6, 0x6c, 0xad, 0x6d, 0xed, 0x30, 0x19, 0x94, 0xb6, + 0x56, 0x79, 0x2a, 0xb7, 0x44, 0xc1, 0x7f, 0x6e, 0x3d, 0xdd, 0xad, 0xd6, 0xbd, 0x6a, 0x48, 0x99, + 0x6c, 0x5a, 0x4c, 0xdf, 0x3b, 0x81, 0xab, 0x23, 0xae, 0x5d, 0x22, 0xd8, 0x7a, 0xd7, 0xa4, 0xf7, + 0x01, 0x8b, 0x53, 0xa8, 0x00, 0x39, 0xd2, 0xf5, 0xe8, 0xa1, 0x6c, 0x51, 0x40, 0x59, 0xc8, 0x1c, + 0xba, 0x6e, 0x57, 0x4c, 0xa1, 0x19, 0x48, 0x39, 0x0f, 0xc5, 0x34, 0xf9, 0x7f, 0xe0, 0x88, 0x19, + 0x02, 0xd5, 0xd5, 0xcf, 0x7a, 0x36, 0x16, 0xa7, 0x09, 0x54, 0xef, 0x39, 0xd8, 0xde, 0x37, 0xda, + 0x58, 0x9c, 0x25, 0x2c, 0x66, 0xaf, 0xdd, 0x16, 0xb3, 0x52, 0x26, 0x3b, 0x23, 0xce, 0xdc, 0xbb, + 0x0e, 0xa1, 0xdb, 0x2f, 0x10, 0xc0, 0xcc, 0x13, 0xd5, 0xc5, 0x8e, 0x2b, 0x4e, 0xa1, 0x59, 0x48, + 0xaf, 0xb5, 0xdb, 0xa2, 0xf0, 0xe0, 0xf3, 0x69, 0xc8, 0x7a, 0x5f, 0x72, 0x42, 0x4f, 0x60, 0x9a, + 0xc2, 0x57, 0xb4, 0x32, 0x1a, 0xd8, 0xd2, 0x71, 0xbc, 0x74, 0xed, 0x3c, 0xe4, 0x2b, 0x4d, 0xa1, + 0xbf, 0x0c, 0xf9, 0x90, 0xc3, 0x8f, 0x46, 0xae, 0x07, 0x47, 0x40, 0xce, 0xd2, 0xad, 0xf3, 0xb2, + 0xf9, 0xf2, 0x3f, 0x86, 0x9c, 0xef, 0x2b, 0xa0, 0x1b, 0xe3, 0x3c, 0x09, 0x4f, 0xf6, 0x78, 0x77, + 0x83, 0x0c, 0x3b, 0x69, 0xea, 0x1d, 0x01, 0xd9, 0x80, 0x86, 0xa7, 0x75, 0x14, 0x17, 0x73, 0x39, + 0xd2, 0x6f, 0x58, 0xba, 0x37, 0x51, 0xee, 0xe0, 0x9d, 0x44, 0x59, 0x81, 0x6f, 0x12, 0xaf, 0xac, + 0x21, 0xcf, 0x27, 0x5e, 0x59, 0x31, 0x2e, 0x0e, 0x6d, 0x8c, 0x90, 0x81, 0x8f, 0x95, 0x3f, 0x3c, + 0x75, 0xc7, 0xca, 0x8f, 0x99, 0x27, 0xa4, 0x29, 0xf4, 0x0c, 0x32, 0xc4, 0x28, 0xa3, 0x38, 0xd4, + 0x30, 0x30, 0x09, 0x2c, 0xdd, 0x18, 0x9b, 0xc7, 0x13, 0x59, 0xb9, 0xfb, 0xa3, 0xff, 0xb2, 0x3c, + 0xf5, 0xa3, 0xb3, 0x65, 0xe1, 0xa7, 0x67, 0xcb, 0xc2, 0x1f, 0x9f, 0x2d, 0x0b, 0x7f, 0x72, 0xb6, + 0x2c, 0x7c, 0xff, 0x67, 0xcb, 0x53, 0x3f, 0xfd, 0xd9, 0xf2, 0xd4, 0x1f, 0xff, 0x6c, 0x79, 0xea, + 0xd3, 0x59, 0xce, 0xbd, 0x37, 0x43, 0x2d, 0xd6, 0xc3, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x3a, + 0x21, 0xb4, 0x24, 0xc8, 0x83, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -16435,6 +16444,18 @@ func (m *TokenBucketRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.InstanceLease) > 0 { + i -= len(m.InstanceLease) + copy(dAtA[i:], m.InstanceLease) + i = encodeVarintApi(dAtA, i, uint64(len(m.InstanceLease))) + i-- + dAtA[i] = 0x22 + } + if m.InstanceID != 0 { + i = encodeVarintApi(dAtA, i, uint64(m.InstanceID)) + i-- + dAtA[i] = 0x18 + } if m.TenantID != 0 { i = encodeVarintApi(dAtA, i, uint64(m.TenantID)) i-- @@ -19936,6 +19957,13 @@ func (m *TokenBucketRequest) Size() (n int) { if m.TenantID != 0 { n += 1 + sovApi(uint64(m.TenantID)) } + if m.InstanceID != 0 { + n += 1 + sovApi(uint64(m.InstanceID)) + } + l = len(m.InstanceLease) + if l > 0 { + n += 1 + l + sovApi(uint64(l)) + } return n } @@ -39987,6 +40015,59 @@ func (m *TokenBucketRequest) Unmarshal(dAtA []byte) error { break } } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field InstanceID", wireType) + } + m.InstanceID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.InstanceID |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InstanceLease", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthApi + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthApi + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InstanceLease = append(m.InstanceLease[:0], dAtA[iNdEx:postIndex]...) + if m.InstanceLease == nil { + m.InstanceLease = []byte{} + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApi(dAtA[iNdEx:]) diff --git a/pkg/roachpb/api.proto b/pkg/roachpb/api.proto index 8d5535837d27..cd60c583c094 100644 --- a/pkg/roachpb/api.proto +++ b/pkg/roachpb/api.proto @@ -2259,8 +2259,6 @@ message GossipSubscriptionEvent { } message TokenBucketRequest { - uint64 tenant_id = 2 [(gogoproto.customname) = "TenantID"]; - message Consumption { double r_u = 1; uint64 read_requests = 2; @@ -2273,6 +2271,16 @@ message TokenBucketRequest { // Consumption that occurred since this node's last request. Consumption consumption_since_last_request = 1 [(gogoproto.nullable) = false]; + uint64 tenant_id = 2 [(gogoproto.customname) = "TenantID"]; + + // InstanceID is the ID of the SQL pod instance from where the request + // originates. + uint32 instance_id = 3 [(gogoproto.customname) = "InstanceID"]; + + // InstanceLease uniquely identifies the SQL pod instance from where the + // request originates, in light of ID reuse. + bytes instance_lease = 4; + // TODO(radu): add remaining fields. } From 70aa2c26df22bf080253c1274c512c1c0c6a758a Mon Sep 17 00:00:00 2001 From: Radu Berinde Date: Fri, 30 Jul 2021 13:18:42 -0700 Subject: [PATCH 3/3] tenantcostserver: use a per-tenant mutex Use a per-tenant mutex to avoid unnecessary transaction restart and remove the possibility of out-of-order metric updates. Release note: None --- .../tenantcostserver/metrics.go | 5 ++++ .../tenantcostserver/token_bucket.go | 23 +++++++++++-------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/pkg/ccl/multitenantccl/tenantcostserver/metrics.go b/pkg/ccl/multitenantccl/tenantcostserver/metrics.go index 2f65e7057246..009a7c29e79e 100644 --- a/pkg/ccl/multitenantccl/tenantcostserver/metrics.go +++ b/pkg/ccl/multitenantccl/tenantcostserver/metrics.go @@ -106,6 +106,10 @@ type tenantMetrics struct { totalWriteRequests *aggmetric.Gauge totalWriteBytes *aggmetric.Gauge totalSQLPodsCPUSeconds *aggmetric.GaugeFloat64 + + // Mutex is used to atomically update metrics together with a corresponding + // change to the system table. + mutex *syncutil.Mutex } // getTenantMetrics returns the metrics for a tenant. @@ -122,6 +126,7 @@ func (m *Metrics) getTenantMetrics(tenantID roachpb.TenantID) tenantMetrics { totalWriteRequests: m.TotalWriteRequests.AddChild(tid), totalWriteBytes: m.TotalWriteBytes.AddChild(tid), totalSQLPodsCPUSeconds: m.TotalSQLPodsCPUSeconds.AddChild(tid), + mutex: &syncutil.Mutex{}, } m.mu.tenantMetrics[tenantID] = tm } diff --git a/pkg/ccl/multitenantccl/tenantcostserver/token_bucket.go b/pkg/ccl/multitenantccl/tenantcostserver/token_bucket.go index ba8b51f0974b..0031297dc9cd 100644 --- a/pkg/ccl/multitenantccl/tenantcostserver/token_bucket.go +++ b/pkg/ccl/multitenantccl/tenantcostserver/token_bucket.go @@ -37,6 +37,14 @@ func (s *instance) TokenBucketRequest( } } + metrics := s.metrics.getTenantMetrics(tenantID) + // Use a per-tenant mutex to serialize operations to the bucket. The + // transactions will need to be serialized anyway, so this avoids more + // expensive restarts. It also guarantees that the metric updates happen in + // the same order with the system table changes. + metrics.mutex.Lock() + defer metrics.mutex.Unlock() + result := &roachpb.TokenBucketResponse{} var consumption roachpb.TokenBucketRequest_Consumption if err := s.db.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error { @@ -80,14 +88,11 @@ func (s *instance) TokenBucketRequest( } // Report current consumption. - // TODO(radu): there is a possible race here, where two different requests - // update the metrics in opposite order. - m := s.metrics.getTenantMetrics(tenantID) - m.totalRU.Update(consumption.RU) - m.totalReadRequests.Update(int64(consumption.ReadRequests)) - m.totalReadBytes.Update(int64(consumption.ReadBytes)) - m.totalWriteRequests.Update(int64(consumption.WriteRequests)) - m.totalWriteBytes.Update(int64(consumption.WriteBytes)) - m.totalSQLPodsCPUSeconds.Update(consumption.SQLPodCPUSeconds) + metrics.totalRU.Update(consumption.RU) + metrics.totalReadRequests.Update(int64(consumption.ReadRequests)) + metrics.totalReadBytes.Update(int64(consumption.ReadBytes)) + metrics.totalWriteRequests.Update(int64(consumption.WriteRequests)) + metrics.totalWriteBytes.Update(int64(consumption.WriteBytes)) + metrics.totalSQLPodsCPUSeconds.Update(consumption.SQLPodCPUSeconds) return result }