From 8da6a7338a9a4dc0581d172c48061d5ff283d470 Mon Sep 17 00:00:00 2001 From: Brandt Newton Date: Tue, 17 Mar 2026 16:38:13 -0400 Subject: [PATCH 1/3] adds cql function handling --- .../bigtable/bigtable_select.go | 22 +- .../bigtable/utils.go | 34 +- .../docs/limitations.md | 14 +- .../global/types/cql_func_avg.go | 37 + .../global/types/cql_func_count.go | 30 + .../global/types/cql_func_max.go | 33 + .../global/types/cql_func_max_timeuuid.go | 74 + .../global/types/cql_func_min.go | 33 + .../global/types/cql_func_min_timeuuid.go | 69 + .../global/types/cql_func_now.go | 42 + .../global/types/cql_func_sum.go | 33 + .../global/types/cql_func_to_timestamp.go | 50 + .../global/types/cql_func_writetime.go | 31 + .../global/types/cql_funcs.go | 177 + .../global/types/cql_functions.go | 126 - .../global/types/cql_types.go | 39 +- .../global/types/dynamic_value.go | 185 +- .../global/types/queries.go | 15 + .../global/types/query_parameters.go | 118 +- .../global/types/query_parameters_builder.go | 15 +- .../global/types/select_query.go | 29 +- .../global/types/types.go | 21 + .../mem_table/in_mem_select.go | 38 +- .../metadata/table_schemas.go | 11 +- .../metadata/utils.go | 3 +- .../responsehandler/responsehandler_utils.go | 2 +- .../system_tables/system_table_manager.go | 2 +- .../backwards_compatible_data_test.go | 33 + .../compliance/compliance_alter_table_test.go | 4 +- .../compliance/compliance_counters_test.go | 3 + .../compliance_create_table_test.go | 4 +- .../compliance/compliance_uuid_test.go | 305 + .../testing/compliance/schemas_test.go | 17 + .../third_party/cqlparser/CqlParser.g4 | 31 +- .../third_party/cqlparser/CqlParser.interp | 6 +- .../third_party/cqlparser/cql_parser.go | 6116 +++++++++-------- .../cqlparser/cqlparser_base_listener.go | 28 + .../cqlparser/cqlparser_listener.go | 24 + .../third_party/datastax/proxycore/codecs.go | 3 + .../translators/common/binding.go | 54 +- .../translators/common/btql_functions.go | 36 - .../translators/common/rowkeys.go | 8 + .../translators/common/rowkeys_test.go | 13 +- .../translators/common/utils.go | 282 +- .../translators/common/utils_test.go | 148 +- .../translator_create_test.go | 4 +- .../translator_delete_test.go | 24 +- .../insert_translator/translator_insert.go | 2 +- .../translator_insert_test.go | 68 +- .../translators/insert_translator/utils.go | 4 +- .../select_translator/select_query_builder.go | 205 +- .../select_translator/translator_select.go | 11 +- .../translator_select_test.go | 275 +- .../translators/select_translator/utils.go | 10 +- .../translator_update_test.go | 132 +- .../translators/update_translator/utils.go | 4 +- .../utilities/utils.go | 132 +- .../utilities/utils_test.go | 11 +- kafka-connect-bigtable-sink/doc/tests.md | 13 +- .../integration-tests/pom.xml | 10 +- .../integration/BaseDataGeneratorIT.java | 1 - .../connect/bigtable/integration/BaseIT.java | 18 +- .../BaseKafkaConnectBigtableIT.java | 24 +- .../integration/BaseKafkaConnectIT.java | 16 +- .../integration/BigtableClientIT.java | 2 - .../bigtable/integration/ConfigIT.java | 1 - .../integration/DifferentConvertersIT.java | 30 +- .../bigtable/integration/ErrorHandlingIT.java | 4 +- .../integration/ErrorReportingIT.java | 2 - .../integration/FlattenArrayElementIT.java | 133 +- ...{InsertUpsertIT.java => InsertModeIT.java} | 362 +- .../integration/MultipleConnectorTasksIT.java | 2 - .../bigtable/integration/NullHandlingIT.java | 16 +- .../integration/ResourceAutoCreationIT.java | 20 +- .../bigtable/integration/VersionIT.java | 2 - .../bigtable/util/SchemaRegistryTestUtil.java | 2 - .../connect/bigtable/util/TestDataUtil.java | 109 +- kafka-connect-bigtable-sink/pom.xml | 20 +- kafka-connect-bigtable-sink/sink/pom.xml | 28 +- .../connect/bigtable/BigtableSinkTask.java | 82 +- .../bigtable/config/BigtableSinkConfig.java | 77 +- .../connect/bigtable/config/InsertMode.java | 1 + .../connect/bigtable/mapping/ByteUtils.java | 110 - .../bigtable/mapping/MutationData.java | 13 +- .../bigtable/mapping/MutationDataBuilder.java | 16 +- .../connect/bigtable/mapping/ValueMapper.java | 77 +- .../transformations/ApplyJsonSchema.java | 79 +- .../transformations/FlattenArrayElement.java | 68 +- .../BigtableTableAdminClientInterface.java | 17 +- .../BigtableTableAdminClientWrapper.java | 15 + .../bigtable/BigtableSinkConnectorTest.java | 3 - .../bigtable/BigtableSinkTaskTest.java | 253 +- .../autocreate/BigtableSchemaManagerTest.java | 53 +- .../bigtable/mapping/KeyMapperTest.java | 28 +- .../mapping/MutationDataBuilderTest.java | 18 +- .../bigtable/mapping/ValueMapperTest.java | 444 +- .../transformations/ApplyJsonSchemaTest.java | 66 +- .../FlattenArrayElementTest.java | 523 +- .../connect/bigtable/util/ByteUtilsTest.java | 53 +- .../connect/bigtable/util/ProtoUtil.java | 22 +- 100 files changed, 7256 insertions(+), 4857 deletions(-) create mode 100644 cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_avg.go create mode 100644 cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_count.go create mode 100644 cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_max.go create mode 100644 cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_max_timeuuid.go create mode 100644 cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_min.go create mode 100644 cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_min_timeuuid.go create mode 100644 cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_now.go create mode 100644 cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_sum.go create mode 100644 cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_to_timestamp.go create mode 100644 cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_writetime.go create mode 100644 cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_funcs.go delete mode 100644 cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_functions.go create mode 100644 cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_uuid_test.go delete mode 100644 cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/btql_functions.go rename kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/{InsertUpsertIT.java => InsertModeIT.java} (55%) delete mode 100644 kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/ByteUtils.java diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/bigtable/bigtable_select.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/bigtable/bigtable_select.go index 9abad3ff..967d957f 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/bigtable/bigtable_select.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/bigtable/bigtable_select.go @@ -26,6 +26,8 @@ import ( "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/datastax/proxycore" "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/utilities" "github.com/datastax/go-cassandra-native-protocol/message" + "github.com/datastax/go-cassandra-native-protocol/primitive" + "github.com/gocql/gocql" "go.uber.org/zap" "time" ) @@ -131,7 +133,7 @@ func (btc *BigtableAdapter) convertResultRow(resultRow bigtable.ResultRow, query // use the result name because that applies the correct alias key = query.ResultColumnMetadata[i].Name // use the selected column because that has the CQLType - expectedType = query.SelectClause.Columns[i].ResultType + expectedType = query.SelectClause.Columns[i].GetType() } if _, ok := result[key]; ok { @@ -161,7 +163,14 @@ func rowValueToGoValue(val any, expectedType types.CqlDataType) (types.GoValue, } return goVal, nil case []byte: - return v, nil + switch expectedType.Code() { + case types.UUID: + return primitive.UUID(v), nil + case types.TIMEUUID: + return primitive.UUID(v), nil + default: + return v, nil + } case map[string]*int64: // counters are always a column family with a single column with an empty qualifier counterValue, ok := v[""] @@ -271,9 +280,18 @@ func rowValueToGoValue(val any, expectedType types.CqlDataType) (types.GoValue, return nil, fmt.Errorf("unhandled type coersion: %T to %s", v, expectedType.String()) } case time.Time: + if expectedType.Code() == types.TIMEUUID { + // This happens for now() which we translate to CURRENT_TIMESTAMP() + // We must use the time from Bigtable to generate the UUID. + return primitive.UUID(gocql.UUIDFromTime(v)), nil + } return v, nil case nil: return nil, nil + case [16]byte: + return primitive.UUID(v), nil + case primitive.UUID: + return v, nil case []*string: return v, nil default: diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/bigtable/utils.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/bigtable/utils.go index cb11fcf2..880e3a97 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/bigtable/utils.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/bigtable/utils.go @@ -22,6 +22,8 @@ import ( "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types" "github.com/datastax/go-cassandra-native-protocol/datatype" "github.com/datastax/go-cassandra-native-protocol/message" + "github.com/datastax/go-cassandra-native-protocol/primitive" + "github.com/google/uuid" ) const ( @@ -116,15 +118,15 @@ func addBindValueIfNeeded(dynamicValue types.DynamicValue, values *types.QueryPa if dynamicValue == nil { return nil } - param, ok := dynamicValue.(*types.ParameterizedValue) - if !ok { + p := dynamicValue.GetParameter() + if p == "" { return nil } var value any if needsByteConversion { var err error - value, err = param.GetValue(values) + value, err = dynamicValue.GetValue(values) if err != nil { return err } @@ -135,12 +137,26 @@ func addBindValueIfNeeded(dynamicValue types.DynamicValue, values *types.QueryPa } } else { var err error - value, err = param.GetValue(values) + value, err = dynamicValue.GetValue(values) if err != nil { return err } + // ensure UUIDs are converted to []byte for Bigtable SQL + switch v := value.(type) { + case primitive.UUID: + value = v[:] + case [16]byte: + value = v[:] + } + } + if u, ok := value.(uuid.UUID); ok { + b, err := u.MarshalBinary() + if err != nil { + return err + } + value = b } - result[string(param.Parameter)] = value + result[string(p)] = value return nil } @@ -182,12 +198,12 @@ func addParamIfNeeded(value types.DynamicValue, params *types.QueryParameters, n return nil } - param, ok := value.(*types.ParameterizedValue) - if !ok { + p := value.GetParameter() + if p == "" { return nil } - md, err := params.GetMetadata(param.Parameter) + md, err := params.GetMetadata(p) if err != nil { return err } @@ -196,6 +212,6 @@ func addParamIfNeeded(value types.DynamicValue, params *types.QueryParameters, n if needsByteConversion { bigtableType = bigtable.BytesSQLType{} } - result[string(param.Parameter)] = bigtableType + result[string(p)] = bigtableType return nil } diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/docs/limitations.md b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/docs/limitations.md index 74a3d07e..4df28f97 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/docs/limitations.md +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/docs/limitations.md @@ -21,6 +21,8 @@ simply because certain features haven't been fully implemented yet in the proxy. | int | yes | yes | RAW BYTES | | bigint | yes | yes | RAW BYTES | | blob | yes | yes | RAW BYTES | +| uuid | yes | yes | RAW BYTES | +| timeuuid | yes | yes | RAW BYTES | | ascii | yes | yes | RAW BYTES | | float | yes | no | RAW BYTES | | double | yes | no | RAW BYTES | @@ -37,18 +39,18 @@ column qualifier, list items as column value.** ### Non-supported data types The proxy currently doesn't support the following data types: -date, decimal, duration, inet, smallint, time, timeuuid, tinyint, uuid, +date, decimal, duration, inet, smallint, time, tinyint, varint, frozen and user-defined types (UDT). ## 2. Supported Functions We are only supporting these functions as of now. -- **count** - `"select count(colx) from keyspacex.tablex.keyspaceX.tablex` -- **sum** - `"select sum(colx) from keyspacex.tablex.keyspaceX.tablex` -- **avg** - `"select avg(colx) from keyspacex.tablex.keyspaceX.tablex` -- **min** - `"select min(colx) from keyspacex.tablex.keyspaceX.tablex` -- **max** - `"select max(colx) from keyspacex.tablex.keyspaceX.tablex` +- **count** - `"select count(colx) from keyspacex.tablex` +- **sum** - `"select sum(colx) from keyspacex.tablex` +- **avg** - `"select avg(colx) from keyspacex.tablex` +- **min** - `"select min(colx) from keyspacex.tablex` +- **max** - `"select max(colx) from keyspacex.tablex` - **writetime** - `select writetime(colx) from keyspacex.tablex` - **toTimestamp(now())** - `insert into keyspacex.tablex (event_time) values (toTimestamp(now()))` diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_avg.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_avg.go new file mode 100644 index 00000000..4ede9366 --- /dev/null +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_avg.go @@ -0,0 +1,37 @@ +package types + +type FuncAvg struct { +} + +func (f *FuncAvg) GetValidClauses() []QueryClause { + return []QueryClause{QueryClauseSelect} +} + +func (f *FuncAvg) GetName() string { + return "avg" +} + +func (f *FuncAvg) GetCode() CqlFuncCode { + return FuncCodeAvg +} + +func (f *FuncAvg) GetParameterTypes() []CqlFuncParameter { + return []CqlFuncParameter{ + *NewCqlFuncParameter(AllNumericTypes, true, false), + } +} + +func (f *FuncAvg) Apply(_ []DynamicValue, value *QueryParameterValues) (GoValue, error) { + return nil, nil +} + +func (f *FuncAvg) GetReturnType(args []DynamicValue) CqlDataType { + if len(args) != 1 { + return TypeDouble + } + dt := args[0].GetType() + if dt.Code() == INT || dt.Code() == BIGINT { + return TypeFloat + } + return dt +} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_count.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_count.go new file mode 100644 index 00000000..3790740f --- /dev/null +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_count.go @@ -0,0 +1,30 @@ +package types + +type FuncCount struct { +} + +func (f *FuncCount) GetValidClauses() []QueryClause { + return []QueryClause{QueryClauseSelect} +} + +func (f *FuncCount) GetName() string { + return "count" +} + +func (f *FuncCount) GetCode() CqlFuncCode { + return FuncCodeCount +} + +func (f *FuncCount) GetParameterTypes() []CqlFuncParameter { + return []CqlFuncParameter{ + *NewCqlFuncParameter(AllScalarTypes, true, true), + } +} + +func (f *FuncCount) Apply(_ []DynamicValue, _ *QueryParameterValues) (GoValue, error) { + return nil, nil +} + +func (f *FuncCount) GetReturnType(_ []DynamicValue) CqlDataType { + return TypeBigInt +} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_max.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_max.go new file mode 100644 index 00000000..c730d004 --- /dev/null +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_max.go @@ -0,0 +1,33 @@ +package types + +type FuncMax struct { +} + +func (f *FuncMax) GetValidClauses() []QueryClause { + return []QueryClause{QueryClauseSelect} +} + +func (f *FuncMax) GetName() string { + return "max" +} + +func (f *FuncMax) GetCode() CqlFuncCode { + return FuncCodeMax +} + +func (f *FuncMax) GetParameterTypes() []CqlFuncParameter { + return []CqlFuncParameter{ + *NewCqlFuncParameter(AllNumericTypes, true, false), + } +} + +func (f *FuncMax) Apply(_ []DynamicValue, value *QueryParameterValues) (GoValue, error) { + return nil, nil +} + +func (f *FuncMax) GetReturnType(args []DynamicValue) CqlDataType { + if len(args) != 1 { + return TypeDouble + } + return args[0].GetType() +} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_max_timeuuid.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_max_timeuuid.go new file mode 100644 index 00000000..aa0275f6 --- /dev/null +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_max_timeuuid.go @@ -0,0 +1,74 @@ +package types + +import ( + "github.com/google/uuid" + "time" +) + +type FuncMaxTimeuuid struct { +} + +func (f *FuncMaxTimeuuid) GetValidClauses() []QueryClause { + return []QueryClause{QueryClauseWhere, QueryClauseValues} +} + +func (f *FuncMaxTimeuuid) GetName() string { + return "minTimeuuid" +} + +func (f *FuncMaxTimeuuid) GetCode() CqlFuncCode { + return FuncCodeMaxTimeuuid +} + +func (f *FuncMaxTimeuuid) GetParameterTypes() []CqlFuncParameter { + return []CqlFuncParameter{ + *NewCqlFuncParameter( + []CqlDataType{ + TypeTimestamp, + }, + false, + false), + } +} + +func (f *FuncMaxTimeuuid) Apply(args []DynamicValue, values *QueryParameterValues) (GoValue, error) { + u, err := getTimeArg(0, args, values) + if err != nil { + return nil, err + } + return maxUUIDv1ForTime(u) +} + +func (f *FuncMaxTimeuuid) GetReturnType(args []DynamicValue) CqlDataType { + return TypeTimeuuid +} + +// maxUUIDv1ForTime creates the maximum possible UUIDv1 for a given time.Time. +// This is achieved by setting the timestamp fields based on the input time, +// and setting the Clock Sequence and Node ID fields to their maximum values. +func maxUUIDv1ForTime(t time.Time) (uuid.UUID, error) { + // For maxTimeuuid, Cassandra adds 9999 to the 100-nanosecond intervals timestamp. + // 9999 * 100 nanoseconds. + maxT := t.Add(9999 * 100 * time.Nanosecond) + u := setUuidV1Time(maxT, [16]byte{}) + + // --- Clock Sequence & Node ID Fields (Maxed Values) --- + // clock_seq_hi_and_variant (byte 8, 8 bits) + // The variant bits must be 10 (0x80 to 0xBF). We set the clock sequence to max. + // 0xBF is 0b10111111 (variant 10 and max 6 bits for the clock sequence high part) + u[8] = 0x7f + + // clock_seq_low (byte 9, 8 bits) + u[9] = 0x7f + + // Node ID (bytes 10-15, 48 bits) - set to all F's (max) + u[10] = 0x7f + u[11] = 0x7f + u[12] = 0x7f + u[13] = 0x7f + u[14] = 0x7f + u[15] = 0x7f + + // Create the UUID from the byte array + return u, nil +} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_min.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_min.go new file mode 100644 index 00000000..cc2a580b --- /dev/null +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_min.go @@ -0,0 +1,33 @@ +package types + +type FuncMin struct { +} + +func (f *FuncMin) GetValidClauses() []QueryClause { + return []QueryClause{QueryClauseSelect} +} + +func (f *FuncMin) GetName() string { + return "min" +} + +func (f *FuncMin) GetCode() CqlFuncCode { + return FuncCodeMin +} + +func (f *FuncMin) GetParameterTypes() []CqlFuncParameter { + return []CqlFuncParameter{ + *NewCqlFuncParameter(AllNumericTypes, true, false), + } +} + +func (f *FuncMin) Apply(_ []DynamicValue, value *QueryParameterValues) (GoValue, error) { + return nil, nil +} + +func (f *FuncMin) GetReturnType(args []DynamicValue) CqlDataType { + if len(args) != 1 { + return TypeDouble + } + return args[0].GetType() +} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_min_timeuuid.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_min_timeuuid.go new file mode 100644 index 00000000..67f913a4 --- /dev/null +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_min_timeuuid.go @@ -0,0 +1,69 @@ +package types + +import ( + "github.com/google/uuid" + "time" +) + +type FuncMinTimeuuid struct { +} + +func (f *FuncMinTimeuuid) GetValidClauses() []QueryClause { + return []QueryClause{QueryClauseWhere, QueryClauseValues} +} + +func (f *FuncMinTimeuuid) GetName() string { + return "minTimeuuid" +} + +func (f *FuncMinTimeuuid) GetCode() CqlFuncCode { + return FuncCodeMinTimeuuid +} + +func (f *FuncMinTimeuuid) GetParameterTypes() []CqlFuncParameter { + return []CqlFuncParameter{ + *NewCqlFuncParameter( + []CqlDataType{ + TypeTimestamp, + }, + false, + false), + } +} + +func (f *FuncMinTimeuuid) Apply(args []DynamicValue, values *QueryParameterValues) (GoValue, error) { + u, err := getTimeArg(0, args, values) + if err != nil { + return nil, err + } + return minUUIDv1ForTime(u) +} + +func (f *FuncMinTimeuuid) GetReturnType(args []DynamicValue) CqlDataType { + return TypeTimeuuid +} + +func minUUIDv1ForTime(t time.Time) (uuid.UUID, error) { + u := setUuidV1Time(t, [16]byte{}) + + // --- Clock Sequence & Node ID Fields (Minned Values) --- + + // clock_seq_hi_and_variant (byte 8, 8 bits) + // The variant bits must be 10 (0x80 to 0xBF). We set the clock sequence to min (0). + // 0x80 is 0b10000000 (variant 10 and min 6 bits for the clock sequence high part) + u[8] = 0x80 + + // clock_seq_low (byte 9, 8 bits) + u[9] = 0x80 // Min 8 bits + + // Node ID (bytes 10-15, 48 bits) - set to all 0's (min) + u[10] = 0x80 + u[11] = 0x80 + u[12] = 0x80 + u[13] = 0x80 + u[14] = 0x80 + u[15] = 0x80 + + // Create the UUID from the byte array + return u, nil +} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_now.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_now.go new file mode 100644 index 00000000..ef47d78b --- /dev/null +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_now.go @@ -0,0 +1,42 @@ +package types + +import ( + "fmt" + "github.com/google/uuid" +) + +type FuncNow struct { +} + +func (f *FuncNow) GetValidClauses() []QueryClause { + return []QueryClause{QueryClauseWhere, QueryClauseValues} +} + +func (f *FuncNow) GetName() string { + return "now" +} + +func (f *FuncNow) GetCode() CqlFuncCode { + return FuncCodeNow +} + +func (f *FuncNow) GetParameterTypes() []CqlFuncParameter { + return []CqlFuncParameter{} +} + +func (f *FuncNow) Apply(_ []DynamicValue, value *QueryParameterValues) (GoValue, error) { + id, err := uuid.NewUUID() + if err != nil { + return nil, err + } + if id.Version() != 1 { + return nil, fmt.Errorf("internal: timeuuid must be v1") + } + // sync with query "now" + setUuidV1Time(value.time, id) + return id, nil +} + +func (f *FuncNow) GetReturnType(_ []DynamicValue) CqlDataType { + return TypeTimeuuid +} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_sum.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_sum.go new file mode 100644 index 00000000..0ce4003a --- /dev/null +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_sum.go @@ -0,0 +1,33 @@ +package types + +type FuncSum struct { +} + +func (f *FuncSum) GetValidClauses() []QueryClause { + return []QueryClause{QueryClauseSelect} +} + +func (f *FuncSum) GetName() string { + return "sum" +} + +func (f *FuncSum) GetCode() CqlFuncCode { + return FuncCodeSum +} + +func (f *FuncSum) GetParameterTypes() []CqlFuncParameter { + return []CqlFuncParameter{ + *NewCqlFuncParameter(AllNumericTypes, true, false), + } +} + +func (f *FuncSum) Apply(_ []DynamicValue, value *QueryParameterValues) (GoValue, error) { + return nil, nil +} + +func (f *FuncSum) GetReturnType(args []DynamicValue) CqlDataType { + if len(args) != 1 { + return TypeDouble + } + return args[0].GetType() +} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_to_timestamp.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_to_timestamp.go new file mode 100644 index 00000000..821820bb --- /dev/null +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_to_timestamp.go @@ -0,0 +1,50 @@ +package types + +import ( + "github.com/google/uuid" + "time" +) + +type FuncToTimestamp struct { +} + +func (f *FuncToTimestamp) GetValidClauses() []QueryClause { + return []QueryClause{QueryClauseWhere, QueryClauseValues} +} + +func (f *FuncToTimestamp) GetName() string { + return "toTimestamp" +} + +func (f *FuncToTimestamp) GetCode() CqlFuncCode { + return FuncCodeToTimestamp +} + +func (f *FuncToTimestamp) GetParameterTypes() []CqlFuncParameter { + return []CqlFuncParameter{ + *NewCqlFuncParameter( + []CqlDataType{ + TypeTimeuuid, + }, + false, + false, + ), + } +} + +func (f *FuncToTimestamp) Apply(args []DynamicValue, values *QueryParameterValues) (GoValue, error) { + u, err := getUuidArg(0, args, values) + if err != nil { + return nil, err + } + return getTimeFromUUID(u) +} + +func (f *FuncToTimestamp) GetReturnType(_ []DynamicValue) CqlDataType { + return TypeTimeuuid +} + +func getTimeFromUUID(id uuid.UUID) (time.Time, error) { + sec, nsec := id.Time().UnixTime() + return time.Unix(sec, nsec).UTC(), nil +} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_writetime.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_writetime.go new file mode 100644 index 00000000..b6637b5a --- /dev/null +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_writetime.go @@ -0,0 +1,31 @@ +package types + +type FuncWritetime struct { +} + +func (f *FuncWritetime) GetValidClauses() []QueryClause { + return []QueryClause{QueryClauseSelect} +} + +func (f *FuncWritetime) GetName() string { + return "writetime" +} + +func (f *FuncWritetime) GetCode() CqlFuncCode { + return FuncCodeWriteTime +} + +func (f *FuncWritetime) GetParameterTypes() []CqlFuncParameter { + return []CqlFuncParameter{ + // todo what about collections? + *NewCqlFuncParameter(AllScalarTypes, true, false), + } +} + +func (f *FuncWritetime) Apply(_ []DynamicValue, _ *QueryParameterValues) (GoValue, error) { + return nil, nil +} + +func (f *FuncWritetime) GetReturnType(_ []DynamicValue) CqlDataType { + return TypeBigInt +} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_funcs.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_funcs.go new file mode 100644 index 00000000..a0ccbb45 --- /dev/null +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_funcs.go @@ -0,0 +1,177 @@ +package types + +import ( + "encoding/binary" + "fmt" + "github.com/google/uuid" + "time" +) + +type CqlFuncCode int + +const ( + FuncCodeUnknown CqlFuncCode = iota + FuncCodeWriteTime + FuncCodeCount + FuncCodeAvg + FuncCodeSum + FuncCodeMin + FuncCodeMax + FuncCodeNow + FuncCodeToTimestamp + FuncCodeMinTimeuuid + FuncCodeMaxTimeuuid + FuncCodeUUID +) + +type CqlFunc interface { + GetName() string + GetCode() CqlFuncCode + GetValidClauses() []QueryClause + GetParameterTypes() []CqlFuncParameter + Apply(args []DynamicValue, value *QueryParameterValues) (GoValue, error) + GetReturnType(args []DynamicValue) CqlDataType +} + +type CqlFuncParameter struct { + Types []CqlDataType + AllowColumn bool + AllowStar bool +} + +func NewCqlFuncParameter(Types []CqlDataType, allowColumn bool, allowStar bool) *CqlFuncParameter { + return &CqlFuncParameter{Types: Types, AllowColumn: allowColumn, AllowStar: allowStar} +} + +var ( + WriteTime CqlFunc = &FuncWritetime{} + Count CqlFunc = &FuncCount{} + Avg CqlFunc = &FuncAvg{} + Sum CqlFunc = &FuncSum{} + Min CqlFunc = &FuncMin{} + Max CqlFunc = &FuncMax{} + Now CqlFunc = &FuncNow{} + ToTimestamp CqlFunc = &FuncToTimestamp{} + MinTimeuuid CqlFunc = &FuncMinTimeuuid{} + MaxTimeuuid CqlFunc = &FuncMaxTimeuuid{} +) + +func GetFunc(c CqlFuncCode) (CqlFunc, error) { + switch c { + case FuncCodeWriteTime: + return WriteTime, nil + case FuncCodeCount: + return Count, nil + case FuncCodeAvg: + return Avg, nil + case FuncCodeSum: + return Sum, nil + case FuncCodeMin: + return Min, nil + case FuncCodeMax: + return Max, nil + case FuncCodeNow: + return Now, nil + case FuncCodeToTimestamp: + return ToTimestamp, nil + case FuncCodeMinTimeuuid: + return MinTimeuuid, nil + case FuncCodeMaxTimeuuid: + return MaxTimeuuid, nil + default: + return nil, fmt.Errorf("unknown func") + } +} + +func setUuidV1Time(t time.Time, id uuid.UUID) uuid.UUID { + const epochOffset = 122192928000000000 + + // Convert Unix time to 100-ns intervals + unixIntervals := t.Unix()*10000000 + int64(t.Nanosecond()/100) + + // Add the offset + uuidTime := uint64(unixIntervals + epochOffset) + + // 2. Breakdown the 60-bit timestamp into fields + // UUID v1 Layout: + // Time Low (32 bits) + // Time Mid (16 bits) + // Time High & Version (16 bits) + + timeLow := uint32(uuidTime & 0xFFFFFFFF) + timeMid := uint16((uuidTime >> 32) & 0xFFFF) + timeHi := uint16((uuidTime >> 48) & 0x0FFF) + + // 3. Write bytes into the UUID structure (Big Endian) + + // Bytes 0-3: Time Low + binary.BigEndian.PutUint32(id[0:4], timeLow) + + // Bytes 4-5: Time Mid + binary.BigEndian.PutUint16(id[4:6], timeMid) + + // Bytes 6-7: Time High + Version + // We combine the high time bits with the Version 1 identifier (0x1000) + binary.BigEndian.PutUint16(id[6:8], timeHi|0x1000) + return id +} + +func getUuidArg(index int, args []DynamicValue, values *QueryParameterValues) (uuid.UUID, error) { + value, err := args[index].GetValue(values) + if err != nil { + return [16]byte{}, err + } + + u, ok := value.(uuid.UUID) + if !ok { + return [16]byte{}, fmt.Errorf("invalid argment: %T expected uuid", value) + } + return u, nil +} + +func getTimeArg(index int, args []DynamicValue, values *QueryParameterValues) (time.Time, error) { + value, err := args[index].GetValue(values) + if err != nil { + return time.Time{}, err + } + + u, ok := value.(time.Time) + if !ok { + return time.Time{}, fmt.Errorf("invalid argment: %T expected time.Time", value) + } + return u, nil +} + +func ValidateFunctionArgs(f *FunctionValue) error { + if len(f.Func.GetParameterTypes()) != len(f.Args) { + return fmt.Errorf("function '%s' expects %d args but got %d", f.Func.GetName(), len(f.Func.GetParameterTypes()), len(f.Args)) + } + + for i, arg := range f.Args { + param := f.Func.GetParameterTypes()[i] + star := IsSelectStar(arg) + if !param.AllowStar && star { + return fmt.Errorf("function '%s' doesn't allow '*' args for parameter %d", f.Func.GetName(), i) + } + if !param.AllowColumn && IsColumn(arg) { + return fmt.Errorf("function '%s' doesn't allow column args for parameter %d", f.Func.GetName(), i) + } + + // star is allowed so it's ok + if star { + continue + } + + isValidType := false + for _, paramType := range param.Types { + if paramType == arg.GetType() { + isValidType = true + break + } + } + if !isValidType { + return fmt.Errorf("function '%s' parameter %d doesn't accept type %s", f.Func.GetName(), i, arg.GetType().String()) + } + } + return nil +} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_functions.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_functions.go deleted file mode 100644 index 6bf1a46f..00000000 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_functions.go +++ /dev/null @@ -1,126 +0,0 @@ -package types - -import ( - "encoding/binary" - "fmt" - "github.com/google/uuid" - "time" -) - -type CqlFuncCode int - -const ( - FuncCodeUnknown CqlFuncCode = iota - FuncCodeWriteTime - FuncCodeCount - FuncCodeAvg - FuncCodeSum - FuncCodeMin - FuncCodeMax - FuncCodeNow - FuncCodeToTimestamp -) - -func (c CqlFuncCode) String() string { - switch c { - case FuncCodeWriteTime: - return "writetime" - case FuncCodeCount: - return "count" - case FuncCodeAvg: - return "avg" - case FuncCodeSum: - return "sum" - case FuncCodeMin: - return "min" - case FuncCodeMax: - return "max" - default: - return "unknown" - } -} - -type CqlFuncSpec struct { - Code CqlFuncCode - ParameterTypes []CqlDataType - ReturnType CqlDataType - Apply func(args []GoValue) (GoValue, error) -} - -func NewCqlFuncSpec(code CqlFuncCode, parameterTypes []CqlDataType, returnType CqlDataType, apply func(args []GoValue) (GoValue, error)) *CqlFuncSpec { - return &CqlFuncSpec{Code: code, ParameterTypes: parameterTypes, ReturnType: returnType, Apply: apply} -} - -var ( - FuncNow = NewCqlFuncSpec(FuncCodeNow, nil, TypeTimeuuid, now) - FuncToTimestamp = NewCqlFuncSpec(FuncCodeToTimestamp, []CqlDataType{TypeTimeuuid}, TypeTimestamp, toTimestamp) -) - -func GetCqlFunc(code CqlFuncCode) (*CqlFuncSpec, error) { - switch code { - //case FuncCodeUnknown: - // return FuncUnknown, nil - //case FuncCodeWriteTime: - // return FuncWriteTime, nil - //case FuncCodeCount: - // return FuncCount, nil - //case FuncCodeAvg: - // return FuncAvg, nil - //case FuncCodeSum: - // return FuncSum, nil - //case FuncCodeMin: - // return FuncMin, nil - //case FuncCodeMax: - // return FuncMax, nil - case FuncCodeNow: - return FuncNow, nil - case FuncCodeToTimestamp: - return FuncToTimestamp, nil - default: - return nil, fmt.Errorf("unknown function code %s (%d)", code.String(), code) - } -} - -func now(_ []GoValue) (GoValue, error) { - id, err := uuid.NewV7() - if err != nil { - return nil, err - } - return id[:], nil -} -func toTimestamp(args []GoValue) (GoValue, error) { - if len(args) != 1 { - return nil, fmt.Errorf("invalid argments") - } - - u, ok := args[0].(uuid.UUID) - if !ok { - return nil, fmt.Errorf("invalid argment: %T expected uuid", args[0]) - } - return getTimeFromUUIDv7(u) -} - -func getTimeFromUUIDv7(id uuid.UUID) (time.Time, error) { - // 1. Check the UUID version. UUIDv7 has the '7' in the 4 most significant bits - // of the 7th byte (index 6). This is a good sanity check. - if id.Version() != 7 { - return time.Time{}, fmt.Errorf("uuid version is %d, expected 7", id.Version()) - } - - // UUIDv7 structure: - // Bits 0-47: 48-bit Unix Epoch time in milliseconds (6 bytes) - // Bits 48-51: 4-bit version (7) - // ... rest is reserved/random - timestamp64 := binary.BigEndian.Uint64(id[:8]) - - // 3. Shift right by 16 bits to discard the version/reserved bits and move - // the 48-bit millisecond timestamp to the least significant position. - milliseconds := int64(timestamp64 >> 16) - - // 4. Convert milliseconds to time. - // time.Unix takes seconds and nanoseconds, so we need to divide the milliseconds. - seconds := milliseconds / 1000 - nanos := (milliseconds % 1000) * int64(time.Millisecond) // Remaining millis * 1,000,000 nanosec/millis - - return time.Unix(seconds, nanos), nil -} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_types.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_types.go index 484de573..f5c7f230 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_types.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_types.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/datastax/go-cassandra-native-protocol/datatype" "github.com/datastax/go-cassandra-native-protocol/primitive" - "github.com/google/uuid" "net" "reflect" "time" @@ -141,12 +140,48 @@ var ( TypeText CqlDataType = newScalarType("text", TEXT, datatype.Varchar, reflect.TypeOf(""), bigtable.StringSQLType{}) TypeTime CqlDataType = newScalarType("time", TIME, datatype.Time, reflect.TypeOf(time.Time{}), bigtable.TimestampSQLType{}) TypeTimestamp CqlDataType = newScalarType("timestamp", TIMESTAMP, datatype.Timestamp, reflect.TypeOf(time.Time{}), bigtable.TimestampSQLType{}) - TypeTimeuuid CqlDataType = newScalarType("timeuuid", TIMEUUID, datatype.Timeuuid, reflect.TypeOf(uuid.UUID{}), bigtable.BytesSQLType{}) + TypeTimeuuid CqlDataType = newScalarType("timeuuid", TIMEUUID, datatype.Timeuuid, reflect.TypeOf(primitive.UUID{}), bigtable.BytesSQLType{}) TypeTinyint CqlDataType = newScalarType("tinyint", TINYINT, datatype.Tinyint, reflect.TypeOf(int8(1)), bigtable.Int64SQLType{}) TypeUuid CqlDataType = newScalarType("uuid", UUID, datatype.Uuid, reflect.TypeOf(primitive.UUID{}), bigtable.BytesSQLType{}) TypeVarint CqlDataType = newScalarType("varint", VARINT, datatype.Varint, reflect.TypeOf(1), bigtable.StringSQLType{}) ) +var ( + AllScalarTypes = []CqlDataType{ + TypeAscii, + TypeVarchar, + TypeBigInt, + TypeBlob, + TypeBoolean, + TypeCounter, + TypeDate, + TypeDecimal, + TypeDouble, + TypeFloat, + TypeInet, + TypeInt, + TypeSmallint, + TypeText, + TypeTime, + TypeTimestamp, + TypeTimeuuid, + TypeTinyint, + TypeUuid, + TypeVarint, + } + AllNumericTypes = []CqlDataType{ + TypeBigInt, + TypeCounter, + TypeDecimal, + TypeDouble, + TypeFloat, + TypeInt, + TypeSmallint, + TypeTinyint, + TypeVarint, + } +) + type MapType struct { keyType CqlDataType valueType CqlDataType diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/dynamic_value.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/dynamic_value.go index 4a5f9a2b..54db3afa 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/dynamic_value.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/dynamic_value.go @@ -1,12 +1,27 @@ package types +import ( + "fmt" +) + type DynamicValue interface { GetValue(values *QueryParameterValues) (GoValue, error) IsIdempotent() bool + GetParameter() Parameter + GetType() CqlDataType } type ParameterizedValue struct { - Parameter Parameter + parameter Parameter + dataType CqlDataType +} + +func (p *ParameterizedValue) GetParameter() Parameter { + return p.parameter +} + +func (p *ParameterizedValue) GetType() CqlDataType { + return p.dataType } func (p *ParameterizedValue) IsIdempotent() bool { @@ -14,11 +29,11 @@ func (p *ParameterizedValue) IsIdempotent() bool { } func (p *ParameterizedValue) GetValue(values *QueryParameterValues) (GoValue, error) { - return values.GetValue(p.Parameter) + return values.GetValue(p.parameter) } -func NewParameterizedValue(parameter Parameter) DynamicValue { - return &ParameterizedValue{Parameter: parameter} +func NewParameterizedValue(parameter Parameter, dt CqlDataType) DynamicValue { + return &ParameterizedValue{parameter: parameter, dataType: dt} } type TimestampNowValue struct { @@ -32,12 +47,17 @@ func (f *TimestampNowValue) GetValue(values *QueryParameterValues) (GoValue, err return values.Time(), nil } -func NewTimestampNowValue() DynamicValue { - return &TimestampNowValue{} -} - type LiteralValue struct { Value GoValue + dt CqlDataType +} + +func (l *LiteralValue) GetParameter() Parameter { + return "" +} + +func (l *LiteralValue) GetType() CqlDataType { + return l.dt } func (l *LiteralValue) IsIdempotent() bool { @@ -48,6 +68,151 @@ func (l *LiteralValue) GetValue(values *QueryParameterValues) (GoValue, error) { return l.Value, nil } -func NewLiteralValue(value GoValue) DynamicValue { - return &LiteralValue{Value: value} +func NewLiteralValue(value GoValue, dt CqlDataType) DynamicValue { + return &LiteralValue{Value: value, dt: dt} +} + +type FunctionValue struct { + Parameter Parameter + Func CqlFunc + Args []DynamicValue +} + +func (f FunctionValue) GetType() CqlDataType { + return f.Func.GetReturnType(f.Args) +} + +func (f FunctionValue) GetParameter() Parameter { + return f.Parameter +} + +func (f FunctionValue) GetValue(values *QueryParameterValues) (GoValue, error) { + apply, err := f.Func.Apply(f.Args, values) + if err != nil { + return nil, err + } + return apply, nil +} + +func (f FunctionValue) IsIdempotent() bool { + return false +} + +func NewFunctionValue(p Parameter, f CqlFunc, args ...DynamicValue) *FunctionValue { + return &FunctionValue{ + Parameter: p, + Func: f, + Args: args, + } +} + +type ColumnValue struct { + Column *Column +} + +func (c ColumnValue) GetType() CqlDataType { + return c.Column.CQLType +} + +func (c ColumnValue) GetValue(values *QueryParameterValues) (GoValue, error) { + return nil, fmt.Errorf("cannot get value on a column") +} + +func (c ColumnValue) IsIdempotent() bool { + return true +} + +func (c ColumnValue) GetParameter() Parameter { + return "" +} + +func NewColumnValue(column *Column) DynamicValue { + return &ColumnValue{Column: column} +} + +type SelectStarValue struct { +} + +func (c SelectStarValue) GetType() CqlDataType { + return TypeText +} + +func (c SelectStarValue) GetValue(values *QueryParameterValues) (GoValue, error) { + return nil, fmt.Errorf("cannot get value on a select * value") +} + +func (c SelectStarValue) IsIdempotent() bool { + return true +} + +func (c SelectStarValue) GetParameter() Parameter { + return "" +} + +func NewSelectStarValue() DynamicValue { + return &SelectStarValue{} +} + +type MapAccessValue struct { + Column *Column + mapType *MapType + // placeholders are NOT allowed + MapKey ColumnQualifier +} + +func NewMapAccessValue(column *Column, mapType *MapType, mapKey ColumnQualifier) DynamicValue { + return &MapAccessValue{Column: column, mapType: mapType, MapKey: mapKey} +} + +func (m MapAccessValue) GetValue(values *QueryParameterValues) (GoValue, error) { + return nil, fmt.Errorf("GetValue not allowed") +} + +func (m MapAccessValue) IsIdempotent() bool { + return true +} + +func (m MapAccessValue) GetParameter() Parameter { + return "" +} + +func (m MapAccessValue) GetType() CqlDataType { + return m.mapType.valueType +} + +type ListElementValue struct { + Column *Column + listType *ListType + // placeholders are NOT allowed + ListIndex int64 +} + +func NewListElementValue(column *Column, listType *ListType, listIndex int64) DynamicValue { + return &ListElementValue{Column: column, listType: listType, ListIndex: listIndex} +} + +func (l ListElementValue) GetValue(values *QueryParameterValues) (GoValue, error) { + return nil, fmt.Errorf("GetValue not allowed") +} + +func (l ListElementValue) IsIdempotent() bool { + return true +} + +func (l ListElementValue) GetParameter() Parameter { + return "" +} + +func (l ListElementValue) GetType() CqlDataType { + return l.listType.elementType +} + +func IsSelectStar(v DynamicValue) bool { + _, ok := v.(SelectStarValue) + return ok +} + +func IsColumn(v DynamicValue) bool { + _, ok := v.(ColumnValue) + return ok } diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/queries.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/queries.go index 50b81589..3682501c 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/queries.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/queries.go @@ -80,6 +80,21 @@ const ( CONTAINS_KEY Operator = "CONTAINS KEY" ) +func FlipOperator(op Operator) Operator { + switch op { + case GT: + return LT + case LT: + return GT + case GTE: + return LTE + case LTE: + return LTE + default: + return op + } +} + type ArithmeticOperator string const ( diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/query_parameters.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/query_parameters.go index 28b149a9..4ac7df02 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/query_parameters.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/query_parameters.go @@ -2,6 +2,7 @@ package types import ( "fmt" + "reflect" "time" ) @@ -16,7 +17,8 @@ type ParameterMetadata struct { IsNamed bool Type CqlDataType // can be null if the placeholder is not related to a specific column - Column *Column + Column *Column + IsInternal bool } func newParameterMetadata( @@ -25,8 +27,9 @@ func newParameterMetadata( isNamed bool, tpe CqlDataType, column *Column, + isInternal bool, ) *ParameterMetadata { - return &ParameterMetadata{Key: key, Order: order, IsNamed: isNamed, Type: tpe, Column: column} + return &ParameterMetadata{Key: key, Order: order, IsNamed: isNamed, Type: tpe, Column: column, IsInternal: isInternal} } type QueryParameters struct { @@ -61,6 +64,17 @@ func (q *QueryParameters) Count() int { return len(q.ordered) } +func (q *QueryParameters) CountUserParameters() int { + result := 0 + for _, metadata := range q.params { + if metadata.IsInternal { + continue + } + result++ + } + return result +} + func (q *QueryParameters) Ordered() []*ParameterMetadata { result := make([]*ParameterMetadata, len(q.ordered)) for _, metadata := range q.params { @@ -69,6 +83,19 @@ func (q *QueryParameters) Ordered() []*ParameterMetadata { return result } +func (q *QueryParameters) OrderedUserParams() []*ParameterMetadata { + ordered := q.Ordered() + result := make([]*ParameterMetadata, 0, len(ordered)) + for _, p := range ordered { + // don't return internal params because we don't want the user to bind to them + if p.IsInternal { + continue + } + result = append(result, p) + } + return result +} + type QueryParameterValues struct { params *QueryParameters time time.Time @@ -105,3 +132,90 @@ func (q *QueryParameterValues) AllValuesSet() bool { func (q *QueryParameterValues) AsMap() map[Parameter]GoValue { return q.values } +func (q *QueryParameterValues) GetValueInt32(dv DynamicValue) (int32, error) { + value, err := dv.GetValue(q) + if err != nil { + return 0, err + } + intVal, ok := value.(int32) + if !ok { + return 0, fmt.Errorf("query value is a %T, not an int32", value) + } + return intVal, nil +} + +func (q *QueryParameterValues) GetValueInt64(dv DynamicValue) (int64, error) { + v, err := dv.GetValue(q) + if err != nil { + return 0, err + } + intVal, ok := v.(int64) + if !ok { + return 0, fmt.Errorf("query value is a %T, not an int64", v) + } + return intVal, nil +} + +func (q *QueryParameterValues) GetValueTime(dv DynamicValue) (time.Time, error) { + v, err := dv.GetValue(q) + if err != nil { + return time.Time{}, err + } + t, ok := v.(time.Time) + if !ok { + return time.Time{}, fmt.Errorf("query value is a %T, not a time", v) + } + return t, nil +} + +func (q *QueryParameterValues) GetValueSlice(dv DynamicValue) ([]GoValue, error) { + v, err := dv.GetValue(q) + if err != nil { + return nil, err + } + + val := reflect.ValueOf(v) + + if val.Kind() != reflect.Slice { + return nil, fmt.Errorf("query value is a %T, not a slice", v) + } + + length := val.Len() + result := make([]GoValue, length) + + for i := 0; i < length; i++ { + result[i] = val.Index(i).Interface() + } + + return result, nil +} + +func (q *QueryParameterValues) GetValueMap(dv DynamicValue) (map[GoValue]GoValue, error) { + v, err := dv.GetValue(q) + if err != nil { + return nil, err + } + val := reflect.ValueOf(v) + + if val.Kind() != reflect.Map { + return nil, fmt.Errorf("value is a %T, not a map", v) + } + + result := make(map[GoValue]GoValue, val.Len()) + + // 3. Iterate over the keys of the original map + iter := val.MapRange() + for iter.Next() { + // Get the reflection Placeholder for the key and the value + keyVal := iter.Key() + valueVal := iter.Value() + + // 4. Use .Interface() to convert the concrete key/value to an any (interface{}) + keyAny := keyVal.Interface() + valueAny := valueVal.Interface() + + // 5. Add to the new map[any]any + result[keyAny] = valueAny + } + return result, nil +} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/query_parameters_builder.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/query_parameters_builder.go index 2d4fd11a..828c7b79 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/query_parameters_builder.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/query_parameters_builder.go @@ -29,7 +29,18 @@ func (q *QueryParameterBuilder) AddPositionalParam(dt CqlDataType, c *Column) (P // could happen if named parameters are also used (which is not allowed in cql) return "", errors.New("unexpected positional param key already exists") } - q.metadata[p] = newParameterMetadata(p, q.getNextIndex(), false, dt, c) + q.metadata[p] = newParameterMetadata(p, q.getNextIndex(), false, dt, c, false) + return p, nil +} + +func (q *QueryParameterBuilder) AddInternalParam(dt CqlDataType) (Parameter, error) { + p := q.getNextParameter() + _, exists := q.metadata[p] + if exists { + // could happen if named parameters are also used (which is not allowed in cql) + return "", errors.New("unexpected positional param key already exists") + } + q.metadata[p] = newParameterMetadata(p, q.getNextIndex(), false, dt, nil, true) return p, nil } @@ -41,7 +52,7 @@ func (q *QueryParameterBuilder) AddNamedParam(p Parameter, dt CqlDataType) error // we already have this param so we can return now return nil } - q.metadata[p] = newParameterMetadata(p, q.getNextIndex(), true, dt, nil) + q.metadata[p] = newParameterMetadata(p, q.getNextIndex(), true, dt, nil, false) return nil } diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/select_query.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/select_query.go index 5e208e4a..e3cca16d 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/select_query.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/select_query.go @@ -9,32 +9,17 @@ import ( // SelectedColumn describes a column that was selected as part of a query. It's // an output of query translating, and is also used for response construction. type SelectedColumn struct { - // Sql is the original value of the selected column, including functions, not including alias. e.g. "region" or "count(*)" - Sql string - Func CqlFuncCode - // placeholders are NOT allowed - MapKey ColumnQualifier - // placeholders are NOT allowed - ListIndex int64 - // ColumnName is the name of the underlying column in a function, or map key - // access. e.g. the column name of "max(price)" is "price" - ColumnName ColumnName - Alias string - ResultType CqlDataType + Cql string + Value DynamicValue + Alias string } -func NewSelectedColumn(sql string, columnName ColumnName, alias string, resultType CqlDataType) *SelectedColumn { - return &SelectedColumn{Sql: sql, ColumnName: columnName, Alias: alias, ResultType: resultType, ListIndex: -1} +func (s SelectedColumn) GetType() CqlDataType { + return s.Value.GetType() } -func NewSelectedColumnListElement(sql string, columnName ColumnName, alias string, resultType CqlDataType, listIndex int64) *SelectedColumn { - return &SelectedColumn{Sql: sql, Alias: alias, ColumnName: columnName, ResultType: resultType, ListIndex: listIndex} -} -func NewSelectedColumnMapElement(sql string, columnName ColumnName, alias string, resultType CqlDataType, key ColumnQualifier) *SelectedColumn { - return &SelectedColumn{Sql: sql, Alias: alias, ColumnName: columnName, ResultType: resultType, MapKey: key, ListIndex: -1} -} -func NewSelectedColumnFunction(sql string, columnName ColumnName, alias string, resultType CqlDataType, funcCode CqlFuncCode) *SelectedColumn { - return &SelectedColumn{Sql: sql, Alias: alias, ColumnName: columnName, ResultType: resultType, Func: funcCode, ListIndex: -1} +func NewSelectedColumn(cql string, value DynamicValue, alias string) SelectedColumn { + return SelectedColumn{Cql: cql, Value: value, Alias: alias} } // PreparedSelectQuery represents the mapping of a select query along with its translation details. diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/types.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/types.go index 333a4320..b6f25fc8 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/types.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/types.go @@ -271,3 +271,24 @@ func (r *RawQuery) Header() *frame.Header { type ICassandraClient interface { SetSessionKeyspace(k Keyspace) } + +type QueryClause int + +const ( + QueryClauseSelect QueryClause = iota + QueryClauseWhere + QueryClauseValues +) + +func (c QueryClause) String() string { + switch c { + case QueryClauseSelect: + return "select" + case QueryClauseWhere: + return "where" + case QueryClauseValues: + return "values" + default: + return "unknown" + } +} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/mem_table/in_mem_select.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/mem_table/in_mem_select.go index b8295b9a..3991d440 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/mem_table/in_mem_select.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/mem_table/in_mem_select.go @@ -3,7 +3,6 @@ package mem_table import ( "fmt" "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types" - "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/utilities" "strings" ) @@ -27,7 +26,7 @@ func (e *InMemEngine) Execute(query *types.ExecutableSelectQuery) ([]types.GoRow // apply limit if query.Limit != nil { - limit, err := utilities.GetValueInt32(query.Limit, query.Values) + limit, err := query.Values.GetValueInt32(query.Limit) if err != nil { return nil, err } @@ -36,16 +35,19 @@ func (e *InMemEngine) Execute(query *types.ExecutableSelectQuery) ([]types.GoRow } } + // todo move transformation logic to CqlFunc type // handle aggregates if present for _, col := range query.SelectClause.Columns { - if col.Func == types.FuncCodeCount { - key := col.Sql - if col.Alias != "" { - key = col.Alias + if f, ok := col.Value.(*types.FunctionValue); ok { + if f.Func.GetCode() == types.FuncCodeCount { + key := col.Cql + if col.Alias != "" { + key = col.Alias + } + return []types.GoRow{ + {key: int64(len(filtered))}, + }, nil } - return []types.GoRow{ - {key: int64(len(filtered))}, - }, nil } } @@ -56,7 +58,11 @@ func (e *InMemEngine) Execute(query *types.ExecutableSelectQuery) ([]types.GoRow projectedRows := make([]types.GoRow, len(filtered)) for i, row := range filtered { - projectedRows[i] = projectRow(row, query.SelectClause.Columns) + selectedRow, err := projectRow(row, query.SelectClause.Columns) + if err != nil { + return nil, err + } + projectedRows[i] = selectedRow } return projectedRows, nil @@ -131,18 +137,22 @@ func compareAny(v1, v2 any) (int, error) { return 0, fmt.Errorf("unhandled comparison types: %T and %T", v1, v2) } -func projectRow(source types.GoRow, columns []types.SelectedColumn) types.GoRow { +func projectRow(source types.GoRow, columns []types.SelectedColumn) (types.GoRow, error) { newRow := make(types.GoRow) for _, col := range columns { - val, exists := source[string(col.ColumnName)] + selectedCol, ok := col.Value.(*types.ColumnValue) + if !ok { + return nil, fmt.Errorf("unhandled select column operation: %T", col.Value) + } + val, exists := source[string(selectedCol.Column.Name)] if exists { // Use Alias if present, otherwise use original Family Name targetKey := col.Alias if targetKey == "" { - targetKey = string(col.ColumnName) + targetKey = string(selectedCol.Column.Name) } newRow[targetKey] = val } } - return newRow + return newRow, nil } diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/metadata/table_schemas.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/metadata/table_schemas.go index bca3551f..5876e31f 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/metadata/table_schemas.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/metadata/table_schemas.go @@ -20,6 +20,7 @@ import ( "fmt" "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types" "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/utilities" + "github.com/datastax/go-cassandra-native-protocol/primitive" "github.com/google/uuid" "golang.org/x/exp/maps" "slices" @@ -98,7 +99,7 @@ func (c *SchemaMetadata) Tables() []*TableSchema { // CalculateSchemaVersion creates a deterministic UUID based on all keyspace and table schema information to be used // for Cassandra schema_version. Schema Version must be consistent across all Proxy nodes. Most Cassandra clients care // about all nodes achieving the same schema version. -func (c *SchemaMetadata) CalculateSchemaVersion() (uuid.UUID, error) { +func (c *SchemaMetadata) CalculateSchemaVersion() (primitive.UUID, error) { c.mu.RLock() defer c.mu.RUnlock() var builder strings.Builder @@ -117,7 +118,7 @@ func (c *SchemaMetadata) CalculateSchemaVersion() (uuid.UUID, error) { keyspace := types.Keyspace(k) tables, ok := c.tables[keyspace] if !ok { - return uuid.UUID{}, fmt.Errorf("failed to next schema version") + return primitive.UUID{}, fmt.Errorf("failed to next schema version") } builder.WriteString(fmt.Sprintf("KS:%s|", k)) @@ -130,7 +131,7 @@ func (c *SchemaMetadata) CalculateSchemaVersion() (uuid.UUID, error) { for _, t := range sortedTableNames { table, err := c.GetTableSchema(keyspace, types.TableName(t)) if err != nil { - return uuid.UUID{}, err + return primitive.UUID{}, err } builder.WriteString(fmt.Sprintf("TBL:%s(", table.Name)) @@ -155,9 +156,9 @@ func (c *SchemaMetadata) CalculateSchemaVersion() (uuid.UUID, error) { // We use a fixed Namespace UUID (like Cassandra) namespace, err := uuid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") if err != nil { - return uuid.UUID{}, err + return primitive.UUID{}, err } - return uuid.NewMD5(namespace, []byte(builder.String())), nil + return primitive.UUID(uuid.NewMD5(namespace, []byte(builder.String()))), nil } func (c *SchemaMetadata) ValidateKeyspace(keyspace types.Keyspace) error { diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/metadata/utils.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/metadata/utils.go index a5b2f3d4..3efb34aa 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/metadata/utils.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/metadata/utils.go @@ -96,7 +96,8 @@ func createBigtableRowKeyField(col types.CreateColumn, intRowKeyEncoding types.I switch col.TypeInfo.DataType() { case datatype.Varchar, datatype.Ascii: return bigtable.StructField{FieldName: string(col.Name), FieldType: bigtable.StringType{Encoding: bigtable.StringUtf8BytesEncoding{}}}, nil - case datatype.Blob: + // Google SQL and Bigtable have no UUID type, so we just write it as a blob + case datatype.Blob, datatype.Uuid, datatype.Timeuuid: return bigtable.StructField{FieldName: string(col.Name), FieldType: bigtable.BytesType{Encoding: bigtable.RawBytesEncoding{}}}, nil case datatype.Timestamp: return bigtable.StructField{FieldName: string(col.Name), FieldType: bigtable.TimestampType{Encoding: bigtable.TimestampUnixMicrosInt64Encoding{UnixMicrosInt64Encoding: bigtable.Int64OrderedCodeBytesEncoding{}}}}, nil diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/responsehandler/responsehandler_utils.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/responsehandler/responsehandler_utils.go index 3fe9a17b..dbd604a2 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/responsehandler/responsehandler_utils.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/responsehandler/responsehandler_utils.go @@ -76,7 +76,7 @@ func BuildPreparedResultResponse(id [16]byte, query types.IPreparedQuery) (*mess func buildPreparedResult(query types.IPreparedQuery) ([]*message.ColumnMetadata, []uint16) { var variableMetadata []*message.ColumnMetadata var pkIndices []uint16 - for i, md := range query.Parameters().Ordered() { + for i, md := range query.Parameters().OrderedUserParams() { var col = message.ColumnMetadata{ Keyspace: string(query.Keyspace()), Table: string(query.Table()), diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/system_tables/system_table_manager.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/system_tables/system_table_manager.go index 68b69da6..bb48655f 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/system_tables/system_table_manager.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/system_tables/system_table_manager.go @@ -106,7 +106,7 @@ func (s *SystemTableManager) ReloadSystemTables() error { if err != nil { return err } - s.schemaVersion = primitive.UUID(schemaVersion) + s.schemaVersion = schemaVersion config := s.configProvider.GetSystemTableConfig() err = s.db.SetData(SystemSchemaTableKeyspace, s.getKeyspaceMetadata()) diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/backwards_compatible_data_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/backwards_compatible_data_test.go index 39341092..65fdffe1 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/backwards_compatible_data_test.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/backwards_compatible_data_test.go @@ -3,6 +3,7 @@ package compliance import ( "cloud.google.com/go/bigtable" "fmt" + "github.com/gocql/gocql" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "testing" @@ -137,6 +138,32 @@ func TestBackwardsCompatibleData(t *testing.T) { }, }, }, + { + name: "timeuuid column", + column: "timeuuid_col", + value: parseUuidOrDie(t, "5c09c580-d75d-11f0-8080-808080808080"), + want: bigtable.Row{ + "cf1": []bigtable.ReadItem{ + { + Column: "cf1:timeuuid_col", + Value: parseUuidOrDie(t, "5c09c580-d75d-11f0-8080-808080808080").Bytes(), + }, + }, + }, + }, + { + name: "uuid column", + column: "uuid_col", + value: parseUuidOrDie(t, "7b287b9e-d769-11f0-b949-8e0ad7a51247"), + want: bigtable.Row{ + "cf1": []bigtable.ReadItem{ + { + Column: "cf1:uuid_col", + Value: parseUuidOrDie(t, "7b287b9e-d769-11f0-b949-8e0ad7a51247").Bytes(), + }, + }, + }, + }, // --- MAPS --- { @@ -562,3 +589,9 @@ func TestBackwardsCompatibleData(t *testing.T) { }) } } + +func parseUuidOrDie(t *testing.T, u string) gocql.UUID { + minUuid, err := gocql.ParseUUID(u) + require.NoError(t, err) + return minUuid +} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_alter_table_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_alter_table_test.go index daca0548..95d6bf73 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_alter_table_test.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_alter_table_test.go @@ -91,8 +91,8 @@ func TestNegativeTestCasesForAlterTable(t *testing.T) { }, { name: "Add a column with an unsupported data type", - query: "ALTER TABLE alter_test_table ADD new_col uuid", - expectedError: "column type 'uuid' is not supported", + query: "ALTER TABLE alter_test_table ADD new_col TUPLE", + expectedError: "unknown data type name: 'TUPLE'", skipCassandra: true, }, { diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_counters_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_counters_test.go index a18ce3ef..79698975 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_counters_test.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_counters_test.go @@ -121,6 +121,7 @@ func TestGroupByAndOrderByCounters(t *testing.T) { require.NoError(t, err) results = append(results, likes) } + require.NoError(t, scanner.Err()) assert.ElementsMatch(t, []int32{2, 2, 3, 5}, results) }) @@ -135,6 +136,7 @@ func TestGroupByAndOrderByCounters(t *testing.T) { require.NoError(t, err) results = append(results, likes) } + require.NoError(t, scanner.Err()) assert.ElementsMatch(t, []int32{5, 3, 2, 2}, results) }) @@ -149,6 +151,7 @@ func TestGroupByAndOrderByCounters(t *testing.T) { require.NoError(t, err) results = append(results, likes) } + require.NoError(t, scanner.Err()) assert.ElementsMatch(t, []int32{2, 3, 5}, results) }) } diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_create_table_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_create_table_test.go index 79633475..61ab1ed7 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_create_table_test.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_create_table_test.go @@ -196,8 +196,8 @@ func TestNegativeTestCasesForCreateTable(t *testing.T) { }, { name: "Create table with invalid column type", - query: "CREATE TABLE fail_invalid_col_type (num INT, big_num UUID, PRIMARY KEY (num))", - expectedError: "column type 'uuid' is not supported", + query: "CREATE TABLE fail_invalid_col_type (num INT, big_num TUPLE, PRIMARY KEY (num))", + expectedError: "unknown data type name: 'TUPLE'", skipCassandra: true, }, { diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_uuid_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_uuid_test.go new file mode 100644 index 00000000..f16516fc --- /dev/null +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_uuid_test.go @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package compliance + +import ( + "testing" + "time" + + "github.com/gocql/gocql" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestUuidAndTimeuuid(t *testing.T) { + t.Parallel() + + u, _ := gocql.RandomUUID() + tu := gocql.TimeUUID() + + name := "uuid_test_user" + + // 1. Insert data + err := session.Query(`INSERT INTO bigtabledevinstance.all_columns (name, uuid_col, timeuuid_col) VALUES (?, ?, ?)`, + name, u, tu).Exec() + require.NoError(t, err) + + // 2. Select back + var nameGot string + var uGot gocql.UUID + var tuGot gocql.UUID + + err = session.Query(`SELECT name, uuid_col, timeuuid_col FROM bigtabledevinstance.all_columns WHERE name = ?`, name).Scan(&nameGot, &uGot, &tuGot) + require.NoError(t, err) + + assert.Equal(t, name, nameGot) + assert.Equal(t, u, uGot) + assert.Equal(t, tu, tuGot) +} + +func TestNowFunction(t *testing.T) { + t.Parallel() + + name := "now_test" + + // 1. Insert using now() + err := session.Query(`INSERT INTO bigtabledevinstance.all_columns (name, timeuuid_col) VALUES (?, now())`, name).Exec() + require.NoError(t, err) + + // 2. Select back and verify it's a version 1 or 7 UUID + var tuGot gocql.UUID + err = session.Query(`SELECT timeuuid_col FROM bigtabledevinstance.all_columns WHERE name = ?`, name).Scan(&tuGot) + require.NoError(t, err) + + assert.True(t, tuGot.Version() == 1 || tuGot.Version() == 7, "Expected version 1 or 7 UUID from now(), got %d", tuGot.Version()) +} + +func TestUuidAsPrimaryKey(t *testing.T) { + t.Parallel() + + u, _ := gocql.RandomUUID() + val := "some value" + + // 1. Insert + err := session.Query(`INSERT INTO bigtabledevinstance.uuid_key (id, val) VALUES (?, ?)`, u, val).Exec() + require.NoError(t, err) + + // 2. Select back using the key + var valGot string + err = session.Query(`SELECT val FROM bigtabledevinstance.uuid_key WHERE id = ?`, u).Scan(&valGot) + require.NoError(t, err) + + assert.Equal(t, val, valGot) +} + +func TestTimeuuidAsClusteringKey(t *testing.T) { + t.Parallel() + + pk := "partition1" + tu1 := gocql.TimeUUID() + time.Sleep(10 * time.Millisecond) // ensure different timestamps + tu2 := gocql.TimeUUID() + + // 1. Insert + err := session.Query(`INSERT INTO bigtabledevinstance.timeuuid_key (pk, id, val) VALUES (?, ?, ?)`, pk, tu1, "val1").Exec() + require.NoError(t, err) + err = session.Query(`INSERT INTO bigtabledevinstance.timeuuid_key (pk, id, val) VALUES (?, ?, ?)`, pk, tu2, "val2").Exec() + require.NoError(t, err) + + // 2. Select and verify ordering or just retrieval + iter := session.Query(`SELECT id, val FROM bigtabledevinstance.timeuuid_key WHERE pk = ? ORDER BY id ASC`, pk).Iter() + + var idGot gocql.UUID + var valGot string + + require.True(t, iter.Scan(&idGot, &valGot)) + assert.Equal(t, tu1, idGot) + assert.Equal(t, "val1", valGot) + + require.True(t, iter.Scan(&idGot, &valGot)) + assert.Equal(t, tu2, idGot) + assert.Equal(t, "val2", valGot) + + require.False(t, iter.Scan(&idGot, &valGot)) + require.NoError(t, iter.Close()) +} + +func TestInsertTimeUuidLiteral(t *testing.T) { + t.Parallel() + require.NoError(t, session.Query(`INSERT INTO timeuuid_key (pk, id, val) VALUES ('timeuuid-literal', 6c9b87f6-d764-11f0-8f97-8e0ad7a51247, 'value')`).Exec()) + + var pkGot string + var idGot gocql.UUID + var valGot string + require.NoError(t, session.Query(`SELECT pk, id, val FROM bigtabledevinstance.timeuuid_key WHERE pk = 'timeuuid-literal'`).Scan(&pkGot, &idGot, &valGot)) + + assert.Equal(t, "timeuuid-literal", pkGot) + assert.Equal(t, "6c9b87f6-d764-11f0-8f97-8e0ad7a51247", idGot.String()) + assert.Equal(t, "value", valGot) +} +func TestInsertTimeUuidNull(t *testing.T) { + t.Parallel() + require.NoError(t, session.Query(`INSERT INTO timeuuid_key (pk, id, val, parentEvent) VALUES ('timeuuid-null', 6c9b87f6-d764-11f0-8f97-8e0ad7a51247, 'value', null)`).Exec()) + + got := TimeUuidEvent{} + require.NoError(t, session.Query(`SELECT pk, id, val, parentEvent FROM timeuuid_key WHERE pk = 'timeuuid-null'`).Scan(&got.pk, &got.id, &got.val, &got.parentEvent)) + + assert.Equal(t, "timeuuid-null", got.pk) + assert.Equal(t, "6c9b87f6-d764-11f0-8f97-8e0ad7a51247", got.id.String()) + assert.Equal(t, "value", got.val) + assert.Equal(t, (*gocql.UUID)(nil), got.parentEvent) +} + +func TestValidateMaxAndMin(t *testing.T) { + inputTime := time.Date(2025, 12, 12, 13, 20, 42, 456000000, time.UTC) + + minUuid, err := gocql.ParseUUID("5c09c580-d75d-11f0-8080-808080808080") + require.NoError(t, err) + maxUuid, err := gocql.ParseUUID("5c09ec8f-d75d-11f0-7f7f-7f7f7f7f7f7f") + require.NoError(t, err) + + require.NoError(t, session.Query(`INSERT INTO timeuuid_key (pk, id, val, parentEvent) VALUES ('timeuuid-validate', ?, '3', now())`, minUuid).Exec()) + require.NoError(t, session.Query(`INSERT INTO timeuuid_key (pk, id, val, parentEvent) VALUES ('timeuuid-validate', ?, '3', now())`, maxUuid).Exec()) + + var gotMin gocql.UUID + require.NoError(t, session.Query(`SELECT id FROM timeuuid_key WHERE pk='timeuuid-validate' AND id = minTimeuuid(?)`, inputTime).Scan(&gotMin)) + assert.Equal(t, minUuid, gotMin) + var gotMax gocql.UUID + require.NoError(t, session.Query(`SELECT id FROM timeuuid_key WHERE pk='timeuuid-validate' AND id = maxTimeuuid(?)`, inputTime).Scan(&gotMax)) + assert.Equal(t, maxUuid, gotMax) +} + +func TestMaxAndMinTimestamp(t *testing.T) { + t.Parallel() + + t1, _ := gocql.ParseUUID("7b287b9e-d769-11f0-b949-8e0ad7a51247") + t2, _ := gocql.ParseUUID("7e2fcec8-d769-11f0-b94a-8e0ad7a51247") + // 2025-12-12 14:47:38.769 +0000 + // server: 2025-12-12 14:47:38.769 +0000 OK + // max: 8133f810-d769-11f0-ffff-ffffffffffff WHAT + t3, _ := gocql.ParseUUID("8133fa68-d769-11f0-b94b-8e0ad7a51247") + + t4, _ := gocql.ParseUUID("843a7228-d769-11f0-b94c-8e0ad7a51247") + t5, _ := gocql.ParseUUID("87575e30-d769-11f0-b94d-8e0ad7a51247") + + require.NoError(t, session.Query(`INSERT INTO timeuuid_key (pk, id, val, parentEvent) VALUES ('timeuuid-minmax', ?, '3', now())`, t1).Exec()) + require.NoError(t, session.Query(`INSERT INTO timeuuid_key (pk, id, val, parentEvent) VALUES ('timeuuid-minmax', ?, '3', now())`, t2).Exec()) + require.NoError(t, session.Query(`INSERT INTO timeuuid_key (pk, id, val, parentEvent) VALUES ('timeuuid-minmax', ?, '3', now())`, t3).Exec()) + require.NoError(t, session.Query(`INSERT INTO timeuuid_key (pk, id, val, parentEvent) VALUES ('timeuuid-minmax', ?, '3', now())`, t4).Exec()) + require.NoError(t, session.Query(`INSERT INTO timeuuid_key (pk, id, val, parentEvent) VALUES ('timeuuid-minmax', ?, '3', now())`, t5).Exec()) + + t.Run("< timeuuid", func(t *testing.T) { + t.Parallel() + got, err := scanAllTimeuuids(session.Query(`SELECT id FROM timeuuid_key WHERE pk='timeuuid-minmax' AND id < ?`, t3).Iter().Scanner()) + require.NoError(t, err) + assert.Equal(t, []gocql.UUID{t1, t2}, got) + }) + + t.Run("> timeuuid", func(t *testing.T) { + t.Parallel() + got, err := scanAllTimeuuids(session.Query(`SELECT id FROM timeuuid_key WHERE pk='timeuuid-minmax' AND id > ?`, t3).Iter().Scanner()) + require.NoError(t, err) + assert.Equal(t, []gocql.UUID{t4, t5}, got) + }) + + t.Run(">= timeuuid", func(t *testing.T) { + t.Parallel() + got, err := scanAllTimeuuids(session.Query(`SELECT id FROM timeuuid_key WHERE pk='timeuuid-minmax' AND id >= ?`, t3).Iter().Scanner()) + require.NoError(t, err) + assert.Equal(t, []gocql.UUID{t3, t4, t5}, got) + }) + + t.Run("<= timeuuid", func(t *testing.T) { + t.Parallel() + got, err := scanAllTimeuuids(session.Query(`SELECT id FROM timeuuid_key WHERE pk='timeuuid-minmax' AND id <= ?`, t3).Iter().Scanner()) + require.NoError(t, err) + assert.Equal(t, []gocql.UUID{t1, t2, t3}, got) + }) + + t.Run("< minTimeuuid", func(t *testing.T) { + t.Parallel() + got, err := scanAllTimeuuids(session.Query(`SELECT id FROM timeuuid_key WHERE pk='timeuuid-minmax' AND id < minTimeuuid(?)`, t3.Time()).Iter().Scanner()) + require.NoError(t, err) + assert.NotContains(t, got, t3) + assert.Equal(t, []gocql.UUID{t1, t2}, got) + }) + + t.Run("> minTimeuuid", func(t *testing.T) { + t.Parallel() + got, err := scanAllTimeuuids(session.Query(`SELECT id FROM timeuuid_key WHERE pk='timeuuid-minmax' AND id > minTimeuuid(?)`, t3.Time()).Iter().Scanner()) + require.NoError(t, err) + assert.Equal(t, []gocql.UUID{t3, t4, t5}, got) + }) + + t.Run("> maxTimeuuid", func(t *testing.T) { + t.Parallel() + got, err := scanAllTimeuuids(session.Query(`SELECT id FROM timeuuid_key WHERE pk='timeuuid-minmax' AND id > maxTimeuuid(?)`, t3.Time()).Iter().Scanner()) + require.NoError(t, err) + assert.NotContains(t, got, t3) + assert.Equal(t, []gocql.UUID{t4, t5}, got) + }) + + t.Run("< maxTimeuuid", func(t *testing.T) { + t.Parallel() + got, err := scanAllTimeuuids(session.Query(`SELECT id FROM timeuuid_key WHERE pk='timeuuid-minmax' AND id < maxTimeuuid(?)`, t3.Time()).Iter().Scanner()) + require.NoError(t, err) + assert.Contains(t, got, t1) + assert.Contains(t, got, t2) + assert.Contains(t, got, t3) + assert.Equal(t, []gocql.UUID{t1, t2, t3}, got) + }) + + t.Run("between t1 t3", func(t *testing.T) { + t.Parallel() + got, err := scanAllTimeuuids(session.Query(`SELECT id FROM timeuuid_key WHERE pk='timeuuid-minmax' AND id BETWEEN ? AND ?`, t1, t3).Iter().Scanner()) + require.NoError(t, err) + // between is inclusive + assert.Equal(t, []gocql.UUID{t1, t2, t3}, got) + }) + + t.Run("between min max", func(t *testing.T) { + t.Parallel() + got, err := scanAllTimeuuids(session.Query(`SELECT id FROM timeuuid_key WHERE pk='timeuuid-minmax' AND id BETWEEN minTimeuuid(?) AND maxTimeuuid(?)`, t3.Time(), t3.Time()).Iter().Scanner()) + require.NoError(t, err) + assert.Equal(t, []gocql.UUID{t3}, got) + }) +} + +func scanAllTimeuuids(scanner gocql.Scanner) ([]gocql.UUID, error) { + var results []gocql.UUID = nil + for scanner.Next() { + var t gocql.UUID + err := scanner.Scan( + &t, + ) + if err != nil { + return nil, err + } + results = append(results, t) + } + if err := scanner.Err(); err != nil { + return nil, err + } + return results, nil +} + +func TestInsertTimeUuidPrepared(t *testing.T) { + t.Parallel() + + t1 := gocql.TimeUUID() + t2 := gocql.TimeUUID() + require.NoError(t, session.Query(`INSERT INTO bigtabledevinstance.timeuuid_key (pk, id, val, parentEvent) VALUES ('timeuuid-prepared', ?, '3', ?)`, t1, t2).Exec()) + got := TimeUuidEvent{} + require.NoError(t, session.Query(`SELECT pk, id, val, parentEvent FROM bigtabledevinstance.timeuuid_key WHERE pk = 'timeuuid-prepared'`).Scan(&got.pk, &got.id, &got.val, &got.parentEvent)) + assert.Equal(t, "timeuuid-prepared", got.pk) + assert.Equal(t, &t1, got.id) + assert.Equal(t, "3", got.val) + assert.Equal(t, &t2, got.parentEvent) + + require.NoError(t, session.Query(`SELECT pk, id, val, parentEvent FROM bigtabledevinstance.timeuuid_key WHERE id=? AND parentEvent=?`, t1, t2).Scan(&got.pk, &got.id, &got.val, &got.parentEvent)) + assert.Equal(t, "timeuuid-prepared", got.pk) + assert.Equal(t, &t1, got.id) + assert.Equal(t, "3", got.val) + assert.Equal(t, &t2, got.parentEvent) +} + +type TimeUuidEvent struct { + pk string + id *gocql.UUID + val string + parentEvent *gocql.UUID +} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/schemas_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/schemas_test.go index cece111c..19fbcfd4 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/schemas_test.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/schemas_test.go @@ -105,6 +105,8 @@ CREATE TABLE IF NOT EXISTS bigtabledevinstance.all_columns ( list_double list, list_boolean list, list_timestamp list, + uuid_col uuid, + timeuuid_col timeuuid, PRIMARY KEY (name) ); `, @@ -182,6 +184,21 @@ CREATE TABLE IF NOT EXISTS bigtabledevinstance.timestamp_key ( ); `, ` +CREATE TABLE IF NOT EXISTS bigtabledevinstance.uuid_key ( + id uuid PRIMARY KEY, + val text +); + `, + ` +CREATE TABLE IF NOT EXISTS bigtabledevinstance.timeuuid_key ( + pk text, + id timeuuid, + val text, + parentEvent timeuuid, + PRIMARY KEY (pk, id) +); + `, + ` CREATE TABLE IF NOT EXISTS bigtabledevinstance.ascii_key ( id ascii PRIMARY KEY, measurement int diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/CqlParser.g4 b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/CqlParser.g4 index 95efcd37..a3415f7f 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/CqlParser.g4 +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/CqlParser.g4 @@ -789,6 +789,8 @@ relationElement | relationBetween | relationFunctionCompareConstant | relationFunctionCompareFunction + | relationColumnCompareFunction + | relationFunctionCompareColumn | relationContainsKey | relationContains | relationIn @@ -810,8 +812,16 @@ relationFunctionCompareFunction : functionCall compareOperator functionCall ; +relationColumnCompareFunction + : column compareOperator functionCall + ; + +relationFunctionCompareColumn + : functionCall compareOperator column + ; + relationBetween - : column kwBetween constant kwAnd constant + : column kwBetween valueAny kwAnd valueAny ; relationCompare @@ -843,14 +853,23 @@ relationContainsKey ; functionCall - : OBJECT_NAME '(' STAR ')' - | OBJECT_NAME '(' functionArgs? ')' - | K_UUID '(' ')' - | K_WRITETIME '(' functionArgs? ')' + : functionName '(' functionArgs? ')' ; +functionName + : OBJECT_NAME + | K_UUID + | K_WRITETIME + ; + functionArgs - : (constant | OBJECT_NAME | functionCall) (syntaxComma (constant | OBJECT_NAME | functionCall))* + : (functionArg) (syntaxComma functionArg)* + ; + +functionArg + : valueAny + | column + | STAR ; valueAny diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/CqlParser.interp b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/CqlParser.interp index 96365b8a..cab9e62f 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/CqlParser.interp +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/CqlParser.interp @@ -533,6 +533,8 @@ relationElement compareOperator relationFunctionCompareConstant relationFunctionCompareFunction +relationColumnCompareFunction +relationFunctionCompareColumn relationBetween relationCompare relationLike @@ -542,7 +544,9 @@ relationIn relationContains relationContainsKey functionCall +functionName functionArgs +functionArg valueAny constant decimalLiteral @@ -683,4 +687,4 @@ groupSpecElement atn: -[4, 1, 181, 2458, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117, 7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121, 2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126, 7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130, 2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135, 7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 2, 138, 7, 138, 2, 139, 7, 139, 2, 140, 7, 140, 2, 141, 7, 141, 2, 142, 7, 142, 2, 143, 7, 143, 2, 144, 7, 144, 2, 145, 7, 145, 2, 146, 7, 146, 2, 147, 7, 147, 2, 148, 7, 148, 2, 149, 7, 149, 2, 150, 7, 150, 2, 151, 7, 151, 2, 152, 7, 152, 2, 153, 7, 153, 2, 154, 7, 154, 2, 155, 7, 155, 2, 156, 7, 156, 2, 157, 7, 157, 2, 158, 7, 158, 2, 159, 7, 159, 2, 160, 7, 160, 2, 161, 7, 161, 2, 162, 7, 162, 2, 163, 7, 163, 2, 164, 7, 164, 2, 165, 7, 165, 2, 166, 7, 166, 2, 167, 7, 167, 2, 168, 7, 168, 2, 169, 7, 169, 2, 170, 7, 170, 2, 171, 7, 171, 2, 172, 7, 172, 2, 173, 7, 173, 2, 174, 7, 174, 2, 175, 7, 175, 2, 176, 7, 176, 2, 177, 7, 177, 2, 178, 7, 178, 2, 179, 7, 179, 2, 180, 7, 180, 2, 181, 7, 181, 2, 182, 7, 182, 2, 183, 7, 183, 2, 184, 7, 184, 2, 185, 7, 185, 2, 186, 7, 186, 2, 187, 7, 187, 2, 188, 7, 188, 2, 189, 7, 189, 2, 190, 7, 190, 2, 191, 7, 191, 2, 192, 7, 192, 2, 193, 7, 193, 2, 194, 7, 194, 2, 195, 7, 195, 2, 196, 7, 196, 2, 197, 7, 197, 2, 198, 7, 198, 2, 199, 7, 199, 2, 200, 7, 200, 2, 201, 7, 201, 2, 202, 7, 202, 2, 203, 7, 203, 2, 204, 7, 204, 2, 205, 7, 205, 2, 206, 7, 206, 2, 207, 7, 207, 2, 208, 7, 208, 2, 209, 7, 209, 2, 210, 7, 210, 2, 211, 7, 211, 2, 212, 7, 212, 2, 213, 7, 213, 2, 214, 7, 214, 2, 215, 7, 215, 2, 216, 7, 216, 2, 217, 7, 217, 2, 218, 7, 218, 2, 219, 7, 219, 2, 220, 7, 220, 2, 221, 7, 221, 2, 222, 7, 222, 2, 223, 7, 223, 2, 224, 7, 224, 2, 225, 7, 225, 2, 226, 7, 226, 2, 227, 7, 227, 2, 228, 7, 228, 2, 229, 7, 229, 2, 230, 7, 230, 2, 231, 7, 231, 2, 232, 7, 232, 2, 233, 7, 233, 2, 234, 7, 234, 2, 235, 7, 235, 2, 236, 7, 236, 2, 237, 7, 237, 2, 238, 7, 238, 2, 239, 7, 239, 2, 240, 7, 240, 2, 241, 7, 241, 2, 242, 7, 242, 2, 243, 7, 243, 2, 244, 7, 244, 2, 245, 7, 245, 2, 246, 7, 246, 2, 247, 7, 247, 2, 248, 7, 248, 2, 249, 7, 249, 2, 250, 7, 250, 2, 251, 7, 251, 2, 252, 7, 252, 2, 253, 7, 253, 2, 254, 7, 254, 2, 255, 7, 255, 2, 256, 7, 256, 2, 257, 7, 257, 2, 258, 7, 258, 2, 259, 7, 259, 2, 260, 7, 260, 2, 261, 7, 261, 2, 262, 7, 262, 2, 263, 7, 263, 2, 264, 7, 264, 2, 265, 7, 265, 2, 266, 7, 266, 2, 267, 7, 267, 2, 268, 7, 268, 2, 269, 7, 269, 2, 270, 7, 270, 2, 271, 7, 271, 2, 272, 7, 272, 2, 273, 7, 273, 2, 274, 7, 274, 2, 275, 7, 275, 2, 276, 7, 276, 2, 277, 7, 277, 2, 278, 7, 278, 2, 279, 7, 279, 2, 280, 7, 280, 2, 281, 7, 281, 2, 282, 7, 282, 2, 283, 7, 283, 2, 284, 7, 284, 2, 285, 7, 285, 2, 286, 7, 286, 2, 287, 7, 287, 2, 288, 7, 288, 2, 289, 7, 289, 2, 290, 7, 290, 2, 291, 7, 291, 2, 292, 7, 292, 2, 293, 7, 293, 2, 294, 7, 294, 2, 295, 7, 295, 2, 296, 7, 296, 2, 297, 7, 297, 2, 298, 7, 298, 2, 299, 7, 299, 2, 300, 7, 300, 2, 301, 7, 301, 2, 302, 7, 302, 2, 303, 7, 303, 2, 304, 7, 304, 2, 305, 7, 305, 2, 306, 7, 306, 2, 307, 7, 307, 2, 308, 7, 308, 2, 309, 7, 309, 2, 310, 7, 310, 2, 311, 7, 311, 2, 312, 7, 312, 1, 0, 4, 0, 628, 8, 0, 11, 0, 12, 0, 629, 1, 0, 3, 0, 633, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 639, 8, 1, 1, 1, 1, 1, 1, 1, 5, 1, 644, 8, 1, 10, 1, 12, 1, 647, 9, 1, 1, 1, 1, 1, 3, 1, 651, 8, 1, 1, 1, 3, 1, 654, 8, 1, 1, 1, 3, 1, 657, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 3, 4, 701, 8, 4, 1, 5, 1, 5, 3, 5, 705, 8, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 713, 8, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 3, 9, 720, 8, 9, 1, 9, 1, 9, 1, 10, 3, 10, 725, 8, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 741, 8, 12, 1, 12, 3, 12, 744, 8, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 3, 13, 751, 8, 13, 1, 13, 1, 13, 1, 13, 3, 13, 756, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 3, 15, 767, 8, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 777, 8, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 792, 8, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 803, 8, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 812, 8, 16, 1, 17, 1, 17, 1, 17, 3, 17, 817, 8, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 3, 17, 825, 8, 17, 1, 18, 1, 18, 1, 18, 3, 18, 830, 8, 18, 1, 18, 1, 18, 3, 18, 834, 8, 18, 1, 19, 1, 19, 1, 19, 3, 19, 839, 8, 19, 1, 19, 1, 19, 1, 19, 3, 19, 844, 8, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 5, 20, 857, 8, 20, 10, 20, 12, 20, 860, 9, 20, 1, 21, 1, 21, 1, 21, 3, 21, 865, 8, 21, 1, 21, 1, 21, 1, 21, 3, 21, 870, 8, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 880, 8, 22, 1, 22, 1, 22, 1, 22, 3, 22, 885, 8, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 902, 8, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 909, 8, 23, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 915, 8, 24, 10, 24, 12, 24, 918, 9, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 3, 26, 931, 8, 26, 1, 27, 1, 27, 1, 27, 3, 27, 936, 8, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 3, 27, 948, 8, 27, 1, 28, 1, 28, 3, 28, 952, 8, 28, 1, 28, 1, 28, 3, 28, 956, 8, 28, 1, 28, 1, 28, 1, 28, 3, 28, 961, 8, 28, 1, 28, 1, 28, 1, 28, 3, 28, 966, 8, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 5, 30, 983, 8, 30, 10, 30, 12, 30, 986, 9, 30, 1, 31, 1, 31, 1, 31, 1, 31, 3, 31, 992, 8, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 3, 32, 1000, 8, 32, 1, 32, 1, 32, 3, 32, 1004, 8, 32, 1, 32, 1, 32, 1, 32, 3, 32, 1009, 8, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 3, 33, 1028, 8, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 1035, 8, 34, 10, 34, 12, 34, 1038, 9, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 5, 36, 1052, 8, 36, 10, 36, 12, 36, 1055, 9, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 5, 37, 1064, 8, 37, 10, 37, 12, 37, 1067, 9, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 1080, 8, 39, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 3, 41, 1087, 8, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 3, 42, 1094, 8, 42, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 3, 43, 1102, 8, 43, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 5, 45, 1111, 8, 45, 10, 45, 12, 45, 1114, 9, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 5, 47, 1127, 8, 47, 10, 47, 12, 47, 1130, 9, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 3, 50, 1148, 8, 50, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 5, 55, 1169, 8, 55, 10, 55, 12, 55, 1172, 9, 55, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 5, 57, 1181, 8, 57, 10, 57, 12, 57, 1184, 9, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 5, 60, 1197, 8, 60, 10, 60, 12, 60, 1200, 9, 60, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 3, 62, 1209, 8, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 5, 63, 1216, 8, 63, 10, 63, 12, 63, 1219, 9, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 3, 64, 1237, 8, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 1245, 8, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 1251, 8, 65, 1, 66, 1, 66, 1, 66, 3, 66, 1256, 8, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 3, 67, 1263, 8, 67, 1, 67, 1, 67, 1, 67, 3, 67, 1268, 8, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 3, 68, 1276, 8, 68, 1, 68, 1, 68, 1, 68, 3, 68, 1281, 8, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 3, 69, 1288, 8, 69, 1, 69, 1, 69, 1, 69, 3, 69, 1293, 8, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 3, 70, 1300, 8, 70, 1, 70, 1, 70, 1, 70, 3, 70, 1305, 8, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 3, 71, 1312, 8, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 3, 72, 1321, 8, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 3, 73, 1328, 8, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 3, 74, 1335, 8, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 3, 75, 1342, 8, 75, 1, 75, 1, 75, 1, 75, 3, 75, 1347, 8, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 3, 76, 1354, 8, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 3, 76, 1361, 8, 76, 1, 77, 1, 77, 3, 77, 1365, 8, 77, 1, 77, 3, 77, 1368, 8, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 3, 78, 1376, 8, 78, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 79, 5, 79, 1384, 8, 79, 10, 79, 12, 79, 1387, 9, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 3, 80, 1397, 8, 80, 1, 81, 1, 81, 1, 82, 1, 82, 3, 82, 1403, 8, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 5, 83, 1410, 8, 83, 10, 83, 12, 83, 1413, 9, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 86, 1, 86, 3, 86, 1425, 8, 86, 1, 87, 1, 87, 1, 87, 1, 87, 5, 87, 1431, 8, 87, 10, 87, 12, 87, 1434, 9, 87, 1, 87, 1, 87, 1, 87, 3, 87, 1439, 8, 87, 1, 88, 1, 88, 1, 88, 3, 88, 1444, 8, 88, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 91, 1, 91, 1, 91, 3, 91, 1458, 8, 91, 1, 92, 1, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 95, 1, 95, 1, 95, 1, 95, 5, 95, 1476, 8, 95, 10, 95, 12, 95, 1479, 9, 95, 1, 96, 1, 96, 1, 96, 1, 96, 5, 96, 1485, 8, 96, 10, 96, 12, 96, 1488, 9, 96, 1, 97, 1, 97, 1, 98, 1, 98, 1, 99, 1, 99, 1, 99, 1, 100, 1, 100, 3, 100, 1499, 8, 100, 1, 100, 1, 100, 3, 100, 1503, 8, 100, 1, 101, 1, 101, 3, 101, 1507, 8, 101, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 3, 102, 1521, 8, 102, 1, 103, 1, 103, 1, 103, 1, 103, 5, 103, 1527, 8, 103, 10, 103, 12, 103, 1530, 9, 103, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 3, 104, 1538, 8, 104, 1, 105, 1, 105, 1, 105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 3, 107, 1549, 8, 107, 1, 107, 1, 107, 1, 108, 1, 108, 1, 108, 3, 108, 1556, 8, 108, 1, 108, 3, 108, 1559, 8, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 109, 1, 109, 3, 109, 1569, 8, 109, 1, 110, 1, 110, 1, 110, 1, 110, 3, 110, 1575, 8, 110, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 114, 3, 114, 1593, 8, 114, 1, 114, 1, 114, 3, 114, 1597, 8, 114, 1, 114, 1, 114, 3, 114, 1601, 8, 114, 1, 114, 1, 114, 1, 114, 3, 114, 1606, 8, 114, 1, 114, 3, 114, 1609, 8, 114, 1, 115, 1, 115, 1, 115, 1, 115, 5, 115, 1615, 8, 115, 10, 115, 12, 115, 1618, 9, 115, 1, 116, 1, 116, 3, 116, 1622, 8, 116, 1, 116, 1, 116, 3, 116, 1626, 8, 116, 3, 116, 1628, 8, 116, 1, 117, 3, 117, 1631, 8, 117, 1, 117, 1, 117, 1, 117, 3, 117, 1636, 8, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 3, 117, 1643, 8, 117, 1, 117, 3, 117, 1646, 8, 117, 1, 118, 1, 118, 1, 118, 1, 119, 1, 119, 1, 119, 1, 119, 5, 119, 1655, 8, 119, 10, 119, 12, 119, 1658, 9, 119, 1, 120, 1, 120, 1, 120, 1, 120, 1, 121, 1, 121, 1, 121, 1, 121, 5, 121, 1668, 8, 121, 10, 121, 12, 121, 1671, 9, 121, 1, 122, 1, 122, 1, 122, 1, 122, 3, 122, 1677, 8, 122, 1, 123, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 126, 1, 126, 1, 126, 1, 126, 1, 127, 1, 127, 1, 127, 1, 127, 1, 127, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 5, 128, 1709, 8, 128, 10, 128, 12, 128, 1712, 9, 128, 3, 128, 1714, 8, 128, 1, 128, 1, 128, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 5, 129, 1728, 8, 129, 10, 129, 12, 129, 1731, 9, 129, 1, 129, 1, 129, 1, 130, 1, 130, 1, 130, 1, 130, 1, 130, 5, 130, 1740, 8, 130, 10, 130, 12, 130, 1743, 9, 130, 3, 130, 1745, 8, 130, 1, 130, 1, 130, 1, 131, 1, 131, 1, 132, 1, 132, 1, 132, 1, 132, 1, 132, 5, 132, 1756, 8, 132, 10, 132, 12, 132, 1759, 9, 132, 1, 132, 1, 132, 1, 133, 3, 133, 1764, 8, 133, 1, 133, 1, 133, 1, 133, 1, 133, 3, 133, 1770, 8, 133, 1, 133, 1, 133, 3, 133, 1774, 8, 133, 1, 133, 3, 133, 1777, 8, 133, 1, 133, 3, 133, 1780, 8, 133, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 3, 134, 1798, 8, 134, 1, 135, 1, 135, 1, 135, 3, 135, 1803, 8, 135, 1, 136, 1, 136, 1, 136, 1, 137, 1, 137, 1, 137, 1, 138, 1, 138, 1, 138, 1, 138, 1, 139, 1, 139, 1, 139, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 3, 140, 1826, 8, 140, 1, 141, 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1, 142, 1, 142, 5, 142, 1836, 8, 142, 10, 142, 12, 142, 1839, 9, 142, 1, 143, 1, 143, 1, 143, 1, 143, 5, 143, 1845, 8, 143, 10, 143, 12, 143, 1848, 9, 143, 1, 144, 1, 144, 1, 144, 1, 144, 1, 144, 1, 144, 3, 144, 1856, 8, 144, 1, 145, 1, 145, 3, 145, 1860, 8, 145, 1, 145, 3, 145, 1863, 8, 145, 1, 145, 1, 145, 1, 145, 3, 145, 1868, 8, 145, 1, 145, 3, 145, 1871, 8, 145, 1, 145, 3, 145, 1874, 8, 145, 1, 145, 3, 145, 1877, 8, 145, 1, 145, 3, 145, 1880, 8, 145, 1, 145, 3, 145, 1883, 8, 145, 1, 146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 3, 147, 1891, 8, 147, 1, 148, 1, 148, 1, 149, 1, 149, 1, 149, 3, 149, 1898, 8, 149, 1, 149, 1, 149, 1, 150, 1, 150, 1, 150, 1, 151, 1, 151, 1, 151, 1, 151, 1, 151, 1, 151, 5, 151, 1911, 8, 151, 10, 151, 12, 151, 1914, 9, 151, 1, 152, 1, 152, 1, 152, 3, 152, 1919, 8, 152, 1, 153, 1, 153, 1, 153, 1, 154, 1, 154, 1, 155, 1, 155, 3, 155, 1928, 8, 155, 1, 155, 1, 155, 1, 155, 5, 155, 1933, 8, 155, 10, 155, 12, 155, 1936, 9, 155, 1, 156, 1, 156, 3, 156, 1940, 8, 156, 1, 156, 1, 156, 3, 156, 1944, 8, 156, 1, 156, 1, 156, 3, 156, 1948, 8, 156, 3, 156, 1950, 8, 156, 1, 157, 1, 157, 1, 158, 1, 158, 1, 159, 1, 159, 1, 159, 1, 159, 1, 159, 1, 160, 1, 160, 1, 160, 1, 161, 1, 161, 1, 161, 1, 161, 5, 161, 1968, 8, 161, 10, 161, 12, 161, 1971, 9, 161, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 5, 162, 2000, 8, 162, 10, 162, 12, 162, 2003, 9, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 5, 162, 2012, 8, 162, 10, 162, 12, 162, 2015, 9, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 5, 162, 2024, 8, 162, 10, 162, 12, 162, 2027, 9, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 5, 162, 2035, 8, 162, 10, 162, 12, 162, 2038, 9, 162, 3, 162, 2040, 8, 162, 1, 163, 1, 163, 1, 164, 1, 164, 1, 164, 1, 164, 1, 165, 1, 165, 1, 165, 1, 165, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 167, 1, 167, 1, 167, 1, 167, 1, 168, 1, 168, 1, 168, 1, 168, 1, 169, 1, 169, 1, 170, 1, 170, 1, 170, 1, 170, 1, 170, 3, 170, 2073, 8, 170, 1, 171, 1, 171, 1, 171, 1, 171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 173, 1, 173, 1, 173, 1, 173, 1, 173, 1, 173, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 3, 174, 2096, 8, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 3, 174, 2105, 8, 174, 1, 174, 3, 174, 2108, 8, 174, 1, 175, 1, 175, 1, 175, 3, 175, 2113, 8, 175, 1, 175, 1, 175, 1, 175, 1, 175, 3, 175, 2119, 8, 175, 5, 175, 2121, 8, 175, 10, 175, 12, 175, 2124, 9, 175, 1, 176, 1, 176, 1, 176, 1, 176, 1, 176, 1, 176, 1, 176, 3, 176, 2133, 8, 176, 1, 177, 1, 177, 1, 177, 1, 177, 1, 177, 1, 177, 1, 177, 1, 177, 1, 177, 3, 177, 2144, 8, 177, 1, 178, 1, 178, 1, 179, 1, 179, 1, 180, 1, 180, 1, 181, 1, 181, 1, 182, 1, 182, 1, 183, 1, 183, 1, 183, 1, 183, 3, 183, 2160, 8, 183, 1, 184, 1, 184, 1, 184, 1, 184, 1, 184, 1, 184, 1, 184, 3, 184, 2169, 8, 184, 1, 185, 1, 185, 1, 185, 1, 185, 1, 185, 1, 185, 3, 185, 2177, 8, 185, 1, 186, 1, 186, 3, 186, 2181, 8, 186, 1, 187, 1, 187, 1, 188, 1, 188, 1, 188, 1, 188, 1, 188, 5, 188, 2190, 8, 188, 10, 188, 12, 188, 2193, 9, 188, 1, 188, 1, 188, 1, 189, 1, 189, 3, 189, 2199, 8, 189, 1, 190, 1, 190, 1, 191, 1, 191, 1, 192, 1, 192, 1, 193, 1, 193, 1, 194, 1, 194, 1, 195, 1, 195, 1, 196, 1, 196, 1, 197, 1, 197, 1, 198, 1, 198, 1, 199, 1, 199, 1, 200, 1, 200, 1, 201, 1, 201, 1, 201, 1, 202, 1, 202, 1, 203, 1, 203, 1, 204, 1, 204, 1, 205, 1, 205, 1, 206, 1, 206, 1, 206, 1, 207, 1, 207, 1, 208, 1, 208, 1, 209, 1, 209, 1, 210, 1, 210, 1, 211, 1, 211, 1, 212, 1, 212, 1, 213, 1, 213, 1, 214, 1, 214, 1, 215, 1, 215, 1, 216, 1, 216, 1, 217, 1, 217, 1, 218, 1, 218, 1, 219, 1, 219, 1, 220, 1, 220, 1, 221, 1, 221, 1, 222, 1, 222, 1, 223, 1, 223, 1, 224, 1, 224, 1, 225, 1, 225, 1, 226, 1, 226, 1, 227, 1, 227, 1, 228, 1, 228, 1, 229, 1, 229, 1, 230, 1, 230, 1, 231, 1, 231, 1, 232, 1, 232, 1, 233, 1, 233, 1, 234, 1, 234, 1, 235, 1, 235, 1, 236, 1, 236, 1, 237, 1, 237, 1, 238, 1, 238, 1, 239, 1, 239, 1, 240, 1, 240, 1, 241, 1, 241, 1, 242, 1, 242, 1, 243, 1, 243, 1, 244, 1, 244, 1, 245, 1, 245, 1, 246, 1, 246, 1, 247, 1, 247, 1, 248, 1, 248, 1, 249, 1, 249, 1, 250, 1, 250, 1, 251, 1, 251, 1, 252, 1, 252, 1, 253, 1, 253, 1, 254, 1, 254, 1, 255, 1, 255, 1, 256, 1, 256, 1, 257, 1, 257, 1, 258, 1, 258, 1, 259, 1, 259, 1, 260, 1, 260, 1, 261, 1, 261, 1, 262, 1, 262, 1, 263, 1, 263, 1, 264, 1, 264, 1, 265, 1, 265, 1, 266, 1, 266, 1, 267, 1, 267, 1, 268, 1, 268, 1, 269, 1, 269, 1, 270, 1, 270, 1, 271, 1, 271, 1, 272, 1, 272, 1, 273, 1, 273, 1, 274, 1, 274, 1, 275, 1, 275, 1, 276, 1, 276, 1, 277, 1, 277, 1, 278, 1, 278, 1, 279, 1, 279, 1, 280, 1, 280, 1, 281, 1, 281, 1, 282, 1, 282, 1, 283, 1, 283, 1, 284, 1, 284, 1, 285, 1, 285, 1, 286, 1, 286, 1, 287, 1, 287, 1, 288, 1, 288, 1, 289, 1, 289, 1, 290, 1, 290, 1, 291, 1, 291, 1, 292, 1, 292, 1, 293, 1, 293, 1, 294, 1, 294, 1, 295, 1, 295, 1, 296, 1, 296, 1, 297, 1, 297, 1, 298, 1, 298, 1, 299, 1, 299, 1, 300, 1, 300, 1, 301, 1, 301, 1, 302, 1, 302, 1, 303, 1, 303, 1, 304, 1, 304, 1, 305, 1, 305, 1, 306, 1, 306, 1, 307, 1, 307, 1, 308, 1, 308, 1, 309, 1, 309, 1, 310, 1, 310, 1, 311, 1, 311, 1, 311, 1, 311, 1, 311, 1, 311, 5, 311, 2451, 8, 311, 10, 311, 12, 311, 2454, 9, 311, 1, 312, 1, 312, 1, 312, 0, 0, 313, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 254, 256, 258, 260, 262, 264, 266, 268, 270, 272, 274, 276, 278, 280, 282, 284, 286, 288, 290, 292, 294, 296, 298, 300, 302, 304, 306, 308, 310, 312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 332, 334, 336, 338, 340, 342, 344, 346, 348, 350, 352, 354, 356, 358, 360, 362, 364, 366, 368, 370, 372, 374, 376, 378, 380, 382, 384, 386, 388, 390, 392, 394, 396, 398, 400, 402, 404, 406, 408, 410, 412, 414, 416, 418, 420, 422, 424, 426, 428, 430, 432, 434, 436, 438, 440, 442, 444, 446, 448, 450, 452, 454, 456, 458, 460, 462, 464, 466, 468, 470, 472, 474, 476, 478, 480, 482, 484, 486, 488, 490, 492, 494, 496, 498, 500, 502, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, 532, 534, 536, 538, 540, 542, 544, 546, 548, 550, 552, 554, 556, 558, 560, 562, 564, 566, 568, 570, 572, 574, 576, 578, 580, 582, 584, 586, 588, 590, 592, 594, 596, 598, 600, 602, 604, 606, 608, 610, 612, 614, 616, 618, 620, 622, 624, 0, 8, 1, 0, 168, 169, 2, 0, 14, 14, 16, 16, 1, 0, 19, 23, 1, 0, 176, 177, 1, 0, 170, 171, 2, 0, 57, 57, 131, 131, 6, 0, 84, 84, 118, 118, 127, 127, 141, 141, 147, 167, 174, 174, 2, 0, 71, 71, 174, 174, 2435, 0, 627, 1, 0, 0, 0, 2, 645, 1, 0, 0, 0, 4, 658, 1, 0, 0, 0, 6, 660, 1, 0, 0, 0, 8, 700, 1, 0, 0, 0, 10, 704, 1, 0, 0, 0, 12, 712, 1, 0, 0, 0, 14, 714, 1, 0, 0, 0, 16, 716, 1, 0, 0, 0, 18, 719, 1, 0, 0, 0, 20, 724, 1, 0, 0, 0, 22, 728, 1, 0, 0, 0, 24, 735, 1, 0, 0, 0, 26, 745, 1, 0, 0, 0, 28, 757, 1, 0, 0, 0, 30, 776, 1, 0, 0, 0, 32, 811, 1, 0, 0, 0, 34, 813, 1, 0, 0, 0, 36, 826, 1, 0, 0, 0, 38, 835, 1, 0, 0, 0, 40, 850, 1, 0, 0, 0, 42, 861, 1, 0, 0, 0, 44, 875, 1, 0, 0, 0, 46, 903, 1, 0, 0, 0, 48, 910, 1, 0, 0, 0, 50, 919, 1, 0, 0, 0, 52, 930, 1, 0, 0, 0, 54, 932, 1, 0, 0, 0, 56, 949, 1, 0, 0, 0, 58, 976, 1, 0, 0, 0, 60, 978, 1, 0, 0, 0, 62, 991, 1, 0, 0, 0, 64, 997, 1, 0, 0, 0, 66, 1027, 1, 0, 0, 0, 68, 1029, 1, 0, 0, 0, 70, 1041, 1, 0, 0, 0, 72, 1045, 1, 0, 0, 0, 74, 1058, 1, 0, 0, 0, 76, 1070, 1, 0, 0, 0, 78, 1073, 1, 0, 0, 0, 80, 1081, 1, 0, 0, 0, 82, 1086, 1, 0, 0, 0, 84, 1088, 1, 0, 0, 0, 86, 1101, 1, 0, 0, 0, 88, 1103, 1, 0, 0, 0, 90, 1106, 1, 0, 0, 0, 92, 1115, 1, 0, 0, 0, 94, 1119, 1, 0, 0, 0, 96, 1131, 1, 0, 0, 0, 98, 1136, 1, 0, 0, 0, 100, 1147, 1, 0, 0, 0, 102, 1149, 1, 0, 0, 0, 104, 1152, 1, 0, 0, 0, 106, 1157, 1, 0, 0, 0, 108, 1161, 1, 0, 0, 0, 110, 1164, 1, 0, 0, 0, 112, 1173, 1, 0, 0, 0, 114, 1176, 1, 0, 0, 0, 116, 1185, 1, 0, 0, 0, 118, 1189, 1, 0, 0, 0, 120, 1192, 1, 0, 0, 0, 122, 1201, 1, 0, 0, 0, 124, 1204, 1, 0, 0, 0, 126, 1210, 1, 0, 0, 0, 128, 1236, 1, 0, 0, 0, 130, 1238, 1, 0, 0, 0, 132, 1252, 1, 0, 0, 0, 134, 1259, 1, 0, 0, 0, 136, 1271, 1, 0, 0, 0, 138, 1284, 1, 0, 0, 0, 140, 1296, 1, 0, 0, 0, 142, 1308, 1, 0, 0, 0, 144, 1317, 1, 0, 0, 0, 146, 1324, 1, 0, 0, 0, 148, 1331, 1, 0, 0, 0, 150, 1338, 1, 0, 0, 0, 152, 1350, 1, 0, 0, 0, 154, 1362, 1, 0, 0, 0, 156, 1369, 1, 0, 0, 0, 158, 1379, 1, 0, 0, 0, 160, 1396, 1, 0, 0, 0, 162, 1398, 1, 0, 0, 0, 164, 1402, 1, 0, 0, 0, 166, 1404, 1, 0, 0, 0, 168, 1416, 1, 0, 0, 0, 170, 1420, 1, 0, 0, 0, 172, 1424, 1, 0, 0, 0, 174, 1426, 1, 0, 0, 0, 176, 1440, 1, 0, 0, 0, 178, 1445, 1, 0, 0, 0, 180, 1448, 1, 0, 0, 0, 182, 1457, 1, 0, 0, 0, 184, 1459, 1, 0, 0, 0, 186, 1461, 1, 0, 0, 0, 188, 1465, 1, 0, 0, 0, 190, 1471, 1, 0, 0, 0, 192, 1480, 1, 0, 0, 0, 194, 1489, 1, 0, 0, 0, 196, 1491, 1, 0, 0, 0, 198, 1493, 1, 0, 0, 0, 200, 1496, 1, 0, 0, 0, 202, 1506, 1, 0, 0, 0, 204, 1508, 1, 0, 0, 0, 206, 1522, 1, 0, 0, 0, 208, 1537, 1, 0, 0, 0, 210, 1539, 1, 0, 0, 0, 212, 1543, 1, 0, 0, 0, 214, 1546, 1, 0, 0, 0, 216, 1552, 1, 0, 0, 0, 218, 1568, 1, 0, 0, 0, 220, 1574, 1, 0, 0, 0, 222, 1576, 1, 0, 0, 0, 224, 1581, 1, 0, 0, 0, 226, 1586, 1, 0, 0, 0, 228, 1592, 1, 0, 0, 0, 230, 1610, 1, 0, 0, 0, 232, 1627, 1, 0, 0, 0, 234, 1630, 1, 0, 0, 0, 236, 1647, 1, 0, 0, 0, 238, 1650, 1, 0, 0, 0, 240, 1659, 1, 0, 0, 0, 242, 1663, 1, 0, 0, 0, 244, 1676, 1, 0, 0, 0, 246, 1678, 1, 0, 0, 0, 248, 1682, 1, 0, 0, 0, 250, 1688, 1, 0, 0, 0, 252, 1694, 1, 0, 0, 0, 254, 1698, 1, 0, 0, 0, 256, 1703, 1, 0, 0, 0, 258, 1717, 1, 0, 0, 0, 260, 1734, 1, 0, 0, 0, 262, 1748, 1, 0, 0, 0, 264, 1750, 1, 0, 0, 0, 266, 1763, 1, 0, 0, 0, 268, 1797, 1, 0, 0, 0, 270, 1799, 1, 0, 0, 0, 272, 1804, 1, 0, 0, 0, 274, 1807, 1, 0, 0, 0, 276, 1810, 1, 0, 0, 0, 278, 1814, 1, 0, 0, 0, 280, 1825, 1, 0, 0, 0, 282, 1827, 1, 0, 0, 0, 284, 1831, 1, 0, 0, 0, 286, 1840, 1, 0, 0, 0, 288, 1855, 1, 0, 0, 0, 290, 1857, 1, 0, 0, 0, 292, 1884, 1, 0, 0, 0, 294, 1887, 1, 0, 0, 0, 296, 1892, 1, 0, 0, 0, 298, 1897, 1, 0, 0, 0, 300, 1901, 1, 0, 0, 0, 302, 1904, 1, 0, 0, 0, 304, 1915, 1, 0, 0, 0, 306, 1920, 1, 0, 0, 0, 308, 1923, 1, 0, 0, 0, 310, 1927, 1, 0, 0, 0, 312, 1949, 1, 0, 0, 0, 314, 1951, 1, 0, 0, 0, 316, 1953, 1, 0, 0, 0, 318, 1955, 1, 0, 0, 0, 320, 1960, 1, 0, 0, 0, 322, 1963, 1, 0, 0, 0, 324, 2039, 1, 0, 0, 0, 326, 2041, 1, 0, 0, 0, 328, 2043, 1, 0, 0, 0, 330, 2047, 1, 0, 0, 0, 332, 2051, 1, 0, 0, 0, 334, 2057, 1, 0, 0, 0, 336, 2061, 1, 0, 0, 0, 338, 2065, 1, 0, 0, 0, 340, 2072, 1, 0, 0, 0, 342, 2074, 1, 0, 0, 0, 344, 2078, 1, 0, 0, 0, 346, 2082, 1, 0, 0, 0, 348, 2107, 1, 0, 0, 0, 350, 2112, 1, 0, 0, 0, 352, 2132, 1, 0, 0, 0, 354, 2143, 1, 0, 0, 0, 356, 2145, 1, 0, 0, 0, 358, 2147, 1, 0, 0, 0, 360, 2149, 1, 0, 0, 0, 362, 2151, 1, 0, 0, 0, 364, 2153, 1, 0, 0, 0, 366, 2159, 1, 0, 0, 0, 368, 2168, 1, 0, 0, 0, 370, 2176, 1, 0, 0, 0, 372, 2178, 1, 0, 0, 0, 374, 2182, 1, 0, 0, 0, 376, 2184, 1, 0, 0, 0, 378, 2198, 1, 0, 0, 0, 380, 2200, 1, 0, 0, 0, 382, 2202, 1, 0, 0, 0, 384, 2204, 1, 0, 0, 0, 386, 2206, 1, 0, 0, 0, 388, 2208, 1, 0, 0, 0, 390, 2210, 1, 0, 0, 0, 392, 2212, 1, 0, 0, 0, 394, 2214, 1, 0, 0, 0, 396, 2216, 1, 0, 0, 0, 398, 2218, 1, 0, 0, 0, 400, 2220, 1, 0, 0, 0, 402, 2222, 1, 0, 0, 0, 404, 2225, 1, 0, 0, 0, 406, 2227, 1, 0, 0, 0, 408, 2229, 1, 0, 0, 0, 410, 2231, 1, 0, 0, 0, 412, 2233, 1, 0, 0, 0, 414, 2236, 1, 0, 0, 0, 416, 2238, 1, 0, 0, 0, 418, 2240, 1, 0, 0, 0, 420, 2242, 1, 0, 0, 0, 422, 2244, 1, 0, 0, 0, 424, 2246, 1, 0, 0, 0, 426, 2248, 1, 0, 0, 0, 428, 2250, 1, 0, 0, 0, 430, 2252, 1, 0, 0, 0, 432, 2254, 1, 0, 0, 0, 434, 2256, 1, 0, 0, 0, 436, 2258, 1, 0, 0, 0, 438, 2260, 1, 0, 0, 0, 440, 2262, 1, 0, 0, 0, 442, 2264, 1, 0, 0, 0, 444, 2266, 1, 0, 0, 0, 446, 2268, 1, 0, 0, 0, 448, 2270, 1, 0, 0, 0, 450, 2272, 1, 0, 0, 0, 452, 2274, 1, 0, 0, 0, 454, 2276, 1, 0, 0, 0, 456, 2278, 1, 0, 0, 0, 458, 2280, 1, 0, 0, 0, 460, 2282, 1, 0, 0, 0, 462, 2284, 1, 0, 0, 0, 464, 2286, 1, 0, 0, 0, 466, 2288, 1, 0, 0, 0, 468, 2290, 1, 0, 0, 0, 470, 2292, 1, 0, 0, 0, 472, 2294, 1, 0, 0, 0, 474, 2296, 1, 0, 0, 0, 476, 2298, 1, 0, 0, 0, 478, 2300, 1, 0, 0, 0, 480, 2302, 1, 0, 0, 0, 482, 2304, 1, 0, 0, 0, 484, 2306, 1, 0, 0, 0, 486, 2308, 1, 0, 0, 0, 488, 2310, 1, 0, 0, 0, 490, 2312, 1, 0, 0, 0, 492, 2314, 1, 0, 0, 0, 494, 2316, 1, 0, 0, 0, 496, 2318, 1, 0, 0, 0, 498, 2320, 1, 0, 0, 0, 500, 2322, 1, 0, 0, 0, 502, 2324, 1, 0, 0, 0, 504, 2326, 1, 0, 0, 0, 506, 2328, 1, 0, 0, 0, 508, 2330, 1, 0, 0, 0, 510, 2332, 1, 0, 0, 0, 512, 2334, 1, 0, 0, 0, 514, 2336, 1, 0, 0, 0, 516, 2338, 1, 0, 0, 0, 518, 2340, 1, 0, 0, 0, 520, 2342, 1, 0, 0, 0, 522, 2344, 1, 0, 0, 0, 524, 2346, 1, 0, 0, 0, 526, 2348, 1, 0, 0, 0, 528, 2350, 1, 0, 0, 0, 530, 2352, 1, 0, 0, 0, 532, 2354, 1, 0, 0, 0, 534, 2356, 1, 0, 0, 0, 536, 2358, 1, 0, 0, 0, 538, 2360, 1, 0, 0, 0, 540, 2362, 1, 0, 0, 0, 542, 2364, 1, 0, 0, 0, 544, 2366, 1, 0, 0, 0, 546, 2368, 1, 0, 0, 0, 548, 2370, 1, 0, 0, 0, 550, 2372, 1, 0, 0, 0, 552, 2374, 1, 0, 0, 0, 554, 2376, 1, 0, 0, 0, 556, 2378, 1, 0, 0, 0, 558, 2380, 1, 0, 0, 0, 560, 2382, 1, 0, 0, 0, 562, 2384, 1, 0, 0, 0, 564, 2386, 1, 0, 0, 0, 566, 2388, 1, 0, 0, 0, 568, 2390, 1, 0, 0, 0, 570, 2392, 1, 0, 0, 0, 572, 2394, 1, 0, 0, 0, 574, 2396, 1, 0, 0, 0, 576, 2398, 1, 0, 0, 0, 578, 2400, 1, 0, 0, 0, 580, 2402, 1, 0, 0, 0, 582, 2404, 1, 0, 0, 0, 584, 2406, 1, 0, 0, 0, 586, 2408, 1, 0, 0, 0, 588, 2410, 1, 0, 0, 0, 590, 2412, 1, 0, 0, 0, 592, 2414, 1, 0, 0, 0, 594, 2416, 1, 0, 0, 0, 596, 2418, 1, 0, 0, 0, 598, 2420, 1, 0, 0, 0, 600, 2422, 1, 0, 0, 0, 602, 2424, 1, 0, 0, 0, 604, 2426, 1, 0, 0, 0, 606, 2428, 1, 0, 0, 0, 608, 2430, 1, 0, 0, 0, 610, 2432, 1, 0, 0, 0, 612, 2434, 1, 0, 0, 0, 614, 2436, 1, 0, 0, 0, 616, 2438, 1, 0, 0, 0, 618, 2440, 1, 0, 0, 0, 620, 2442, 1, 0, 0, 0, 622, 2444, 1, 0, 0, 0, 624, 2455, 1, 0, 0, 0, 626, 628, 3, 2, 1, 0, 627, 626, 1, 0, 0, 0, 628, 629, 1, 0, 0, 0, 629, 627, 1, 0, 0, 0, 629, 630, 1, 0, 0, 0, 630, 632, 1, 0, 0, 0, 631, 633, 5, 15, 0, 0, 632, 631, 1, 0, 0, 0, 632, 633, 1, 0, 0, 0, 633, 634, 1, 0, 0, 0, 634, 635, 5, 0, 0, 1, 635, 1, 1, 0, 0, 0, 636, 638, 3, 8, 4, 0, 637, 639, 5, 15, 0, 0, 638, 637, 1, 0, 0, 0, 638, 639, 1, 0, 0, 0, 639, 640, 1, 0, 0, 0, 640, 641, 3, 4, 2, 0, 641, 644, 1, 0, 0, 0, 642, 644, 3, 6, 3, 0, 643, 636, 1, 0, 0, 0, 643, 642, 1, 0, 0, 0, 644, 647, 1, 0, 0, 0, 645, 643, 1, 0, 0, 0, 645, 646, 1, 0, 0, 0, 646, 656, 1, 0, 0, 0, 647, 645, 1, 0, 0, 0, 648, 653, 3, 8, 4, 0, 649, 651, 5, 15, 0, 0, 650, 649, 1, 0, 0, 0, 650, 651, 1, 0, 0, 0, 651, 652, 1, 0, 0, 0, 652, 654, 3, 4, 2, 0, 653, 650, 1, 0, 0, 0, 653, 654, 1, 0, 0, 0, 654, 657, 1, 0, 0, 0, 655, 657, 3, 6, 3, 0, 656, 648, 1, 0, 0, 0, 656, 655, 1, 0, 0, 0, 657, 3, 1, 0, 0, 0, 658, 659, 5, 8, 0, 0, 659, 5, 1, 0, 0, 0, 660, 661, 3, 4, 2, 0, 661, 7, 1, 0, 0, 0, 662, 701, 3, 204, 102, 0, 663, 701, 3, 130, 65, 0, 664, 701, 3, 124, 62, 0, 665, 701, 3, 98, 49, 0, 666, 701, 3, 84, 42, 0, 667, 701, 3, 78, 39, 0, 668, 701, 3, 198, 99, 0, 669, 701, 3, 64, 32, 0, 670, 701, 3, 56, 28, 0, 671, 701, 3, 216, 108, 0, 672, 701, 3, 54, 27, 0, 673, 701, 3, 44, 22, 0, 674, 701, 3, 36, 18, 0, 675, 701, 3, 152, 76, 0, 676, 701, 3, 42, 21, 0, 677, 701, 3, 38, 19, 0, 678, 701, 3, 34, 17, 0, 679, 701, 3, 228, 114, 0, 680, 701, 3, 138, 69, 0, 681, 701, 3, 140, 70, 0, 682, 701, 3, 150, 75, 0, 683, 701, 3, 148, 74, 0, 684, 701, 3, 136, 68, 0, 685, 701, 3, 144, 72, 0, 686, 701, 3, 146, 73, 0, 687, 701, 3, 142, 71, 0, 688, 701, 3, 134, 67, 0, 689, 701, 3, 132, 66, 0, 690, 701, 3, 28, 14, 0, 691, 701, 3, 266, 133, 0, 692, 701, 3, 26, 13, 0, 693, 701, 3, 24, 12, 0, 694, 701, 3, 22, 11, 0, 695, 701, 3, 290, 145, 0, 696, 701, 3, 214, 107, 0, 697, 701, 3, 234, 117, 0, 698, 701, 3, 212, 106, 0, 699, 701, 3, 10, 5, 0, 700, 662, 1, 0, 0, 0, 700, 663, 1, 0, 0, 0, 700, 664, 1, 0, 0, 0, 700, 665, 1, 0, 0, 0, 700, 666, 1, 0, 0, 0, 700, 667, 1, 0, 0, 0, 700, 668, 1, 0, 0, 0, 700, 669, 1, 0, 0, 0, 700, 670, 1, 0, 0, 0, 700, 671, 1, 0, 0, 0, 700, 672, 1, 0, 0, 0, 700, 673, 1, 0, 0, 0, 700, 674, 1, 0, 0, 0, 700, 675, 1, 0, 0, 0, 700, 676, 1, 0, 0, 0, 700, 677, 1, 0, 0, 0, 700, 678, 1, 0, 0, 0, 700, 679, 1, 0, 0, 0, 700, 680, 1, 0, 0, 0, 700, 681, 1, 0, 0, 0, 700, 682, 1, 0, 0, 0, 700, 683, 1, 0, 0, 0, 700, 684, 1, 0, 0, 0, 700, 685, 1, 0, 0, 0, 700, 686, 1, 0, 0, 0, 700, 687, 1, 0, 0, 0, 700, 688, 1, 0, 0, 0, 700, 689, 1, 0, 0, 0, 700, 690, 1, 0, 0, 0, 700, 691, 1, 0, 0, 0, 700, 692, 1, 0, 0, 0, 700, 693, 1, 0, 0, 0, 700, 694, 1, 0, 0, 0, 700, 695, 1, 0, 0, 0, 700, 696, 1, 0, 0, 0, 700, 697, 1, 0, 0, 0, 700, 698, 1, 0, 0, 0, 700, 699, 1, 0, 0, 0, 701, 9, 1, 0, 0, 0, 702, 705, 3, 448, 224, 0, 703, 705, 3, 450, 225, 0, 704, 702, 1, 0, 0, 0, 704, 703, 1, 0, 0, 0, 705, 706, 1, 0, 0, 0, 706, 707, 3, 12, 6, 0, 707, 11, 1, 0, 0, 0, 708, 713, 3, 14, 7, 0, 709, 713, 3, 16, 8, 0, 710, 713, 3, 18, 9, 0, 711, 713, 3, 20, 10, 0, 712, 708, 1, 0, 0, 0, 712, 709, 1, 0, 0, 0, 712, 710, 1, 0, 0, 0, 712, 711, 1, 0, 0, 0, 713, 13, 1, 0, 0, 0, 714, 715, 3, 502, 251, 0, 715, 15, 1, 0, 0, 0, 716, 717, 3, 566, 283, 0, 717, 17, 1, 0, 0, 0, 718, 720, 3, 564, 282, 0, 719, 718, 1, 0, 0, 0, 719, 720, 1, 0, 0, 0, 720, 721, 1, 0, 0, 0, 721, 722, 3, 298, 149, 0, 722, 19, 1, 0, 0, 0, 723, 725, 3, 500, 250, 0, 724, 723, 1, 0, 0, 0, 724, 725, 1, 0, 0, 0, 725, 726, 1, 0, 0, 0, 726, 727, 3, 366, 183, 0, 727, 21, 1, 0, 0, 0, 728, 729, 3, 598, 299, 0, 729, 730, 3, 30, 15, 0, 730, 731, 3, 528, 264, 0, 731, 732, 3, 32, 16, 0, 732, 733, 3, 468, 234, 0, 733, 734, 3, 380, 190, 0, 734, 23, 1, 0, 0, 0, 735, 736, 3, 508, 254, 0, 736, 740, 3, 550, 275, 0, 737, 738, 3, 526, 263, 0, 738, 739, 3, 380, 190, 0, 739, 741, 1, 0, 0, 0, 740, 737, 1, 0, 0, 0, 740, 741, 1, 0, 0, 0, 741, 743, 1, 0, 0, 0, 742, 744, 3, 520, 260, 0, 743, 742, 1, 0, 0, 0, 743, 744, 1, 0, 0, 0, 744, 25, 1, 0, 0, 0, 745, 746, 3, 508, 254, 0, 746, 750, 3, 30, 15, 0, 747, 748, 3, 528, 264, 0, 748, 749, 3, 32, 16, 0, 749, 751, 1, 0, 0, 0, 750, 747, 1, 0, 0, 0, 750, 751, 1, 0, 0, 0, 751, 755, 1, 0, 0, 0, 752, 753, 3, 526, 263, 0, 753, 754, 3, 380, 190, 0, 754, 756, 1, 0, 0, 0, 755, 752, 1, 0, 0, 0, 755, 756, 1, 0, 0, 0, 756, 27, 1, 0, 0, 0, 757, 758, 3, 476, 238, 0, 758, 759, 3, 30, 15, 0, 759, 760, 3, 528, 264, 0, 760, 761, 3, 32, 16, 0, 761, 762, 3, 570, 285, 0, 762, 763, 3, 380, 190, 0, 763, 29, 1, 0, 0, 0, 764, 767, 3, 410, 205, 0, 765, 767, 3, 412, 206, 0, 766, 764, 1, 0, 0, 0, 766, 765, 1, 0, 0, 0, 767, 777, 1, 0, 0, 0, 768, 777, 3, 416, 208, 0, 769, 777, 3, 426, 213, 0, 770, 777, 3, 450, 225, 0, 771, 777, 3, 460, 230, 0, 772, 777, 3, 444, 222, 0, 773, 777, 3, 454, 227, 0, 774, 777, 3, 516, 258, 0, 775, 777, 3, 552, 276, 0, 776, 766, 1, 0, 0, 0, 776, 768, 1, 0, 0, 0, 776, 769, 1, 0, 0, 0, 776, 770, 1, 0, 0, 0, 776, 771, 1, 0, 0, 0, 776, 772, 1, 0, 0, 0, 776, 773, 1, 0, 0, 0, 776, 774, 1, 0, 0, 0, 776, 775, 1, 0, 0, 0, 777, 31, 1, 0, 0, 0, 778, 779, 3, 410, 205, 0, 779, 780, 3, 474, 237, 0, 780, 812, 1, 0, 0, 0, 781, 782, 3, 410, 205, 0, 782, 783, 3, 474, 237, 0, 783, 784, 3, 480, 240, 0, 784, 785, 3, 500, 250, 0, 785, 786, 3, 366, 183, 0, 786, 812, 1, 0, 0, 0, 787, 791, 3, 472, 236, 0, 788, 789, 3, 366, 183, 0, 789, 790, 5, 10, 0, 0, 790, 792, 1, 0, 0, 0, 791, 788, 1, 0, 0, 0, 791, 792, 1, 0, 0, 0, 792, 793, 1, 0, 0, 0, 793, 794, 3, 392, 196, 0, 794, 812, 1, 0, 0, 0, 795, 796, 3, 410, 205, 0, 796, 797, 3, 502, 251, 0, 797, 812, 1, 0, 0, 0, 798, 799, 3, 500, 250, 0, 799, 800, 3, 366, 183, 0, 800, 812, 1, 0, 0, 0, 801, 803, 3, 564, 282, 0, 802, 801, 1, 0, 0, 0, 802, 803, 1, 0, 0, 0, 803, 804, 1, 0, 0, 0, 804, 812, 3, 298, 149, 0, 805, 806, 3, 410, 205, 0, 806, 807, 3, 550, 275, 0, 807, 812, 1, 0, 0, 0, 808, 809, 3, 548, 274, 0, 809, 810, 3, 380, 190, 0, 810, 812, 1, 0, 0, 0, 811, 778, 1, 0, 0, 0, 811, 781, 1, 0, 0, 0, 811, 787, 1, 0, 0, 0, 811, 795, 1, 0, 0, 0, 811, 798, 1, 0, 0, 0, 811, 802, 1, 0, 0, 0, 811, 805, 1, 0, 0, 0, 811, 808, 1, 0, 0, 0, 812, 33, 1, 0, 0, 0, 813, 814, 3, 444, 222, 0, 814, 816, 3, 586, 293, 0, 815, 817, 3, 276, 138, 0, 816, 815, 1, 0, 0, 0, 816, 817, 1, 0, 0, 0, 817, 818, 1, 0, 0, 0, 818, 819, 3, 396, 198, 0, 819, 820, 3, 596, 298, 0, 820, 821, 3, 536, 268, 0, 821, 824, 3, 360, 180, 0, 822, 825, 3, 562, 281, 0, 823, 825, 3, 518, 259, 0, 824, 822, 1, 0, 0, 0, 824, 823, 1, 0, 0, 0, 824, 825, 1, 0, 0, 0, 825, 35, 1, 0, 0, 0, 826, 827, 3, 444, 222, 0, 827, 829, 3, 548, 274, 0, 828, 830, 3, 276, 138, 0, 829, 828, 1, 0, 0, 0, 829, 830, 1, 0, 0, 0, 830, 831, 1, 0, 0, 0, 831, 833, 3, 380, 190, 0, 832, 834, 3, 126, 63, 0, 833, 832, 1, 0, 0, 0, 833, 834, 1, 0, 0, 0, 834, 37, 1, 0, 0, 0, 835, 836, 3, 444, 222, 0, 836, 838, 3, 578, 289, 0, 837, 839, 3, 276, 138, 0, 838, 837, 1, 0, 0, 0, 838, 839, 1, 0, 0, 0, 839, 843, 1, 0, 0, 0, 840, 841, 3, 366, 183, 0, 841, 842, 5, 10, 0, 0, 842, 844, 1, 0, 0, 0, 843, 840, 1, 0, 0, 0, 843, 844, 1, 0, 0, 0, 844, 845, 1, 0, 0, 0, 845, 846, 3, 388, 194, 0, 846, 847, 3, 602, 301, 0, 847, 848, 3, 40, 20, 0, 848, 849, 3, 604, 302, 0, 849, 39, 1, 0, 0, 0, 850, 851, 3, 370, 185, 0, 851, 858, 3, 372, 186, 0, 852, 853, 3, 618, 309, 0, 853, 854, 3, 370, 185, 0, 854, 855, 3, 372, 186, 0, 855, 857, 1, 0, 0, 0, 856, 852, 1, 0, 0, 0, 857, 860, 1, 0, 0, 0, 858, 856, 1, 0, 0, 0, 858, 859, 1, 0, 0, 0, 859, 41, 1, 0, 0, 0, 860, 858, 1, 0, 0, 0, 861, 862, 3, 444, 222, 0, 862, 864, 3, 572, 286, 0, 863, 865, 3, 276, 138, 0, 864, 863, 1, 0, 0, 0, 864, 865, 1, 0, 0, 0, 865, 869, 1, 0, 0, 0, 866, 867, 3, 366, 183, 0, 867, 868, 5, 10, 0, 0, 868, 870, 1, 0, 0, 0, 869, 866, 1, 0, 0, 0, 869, 870, 1, 0, 0, 0, 870, 871, 1, 0, 0, 0, 871, 872, 3, 382, 191, 0, 872, 873, 3, 588, 294, 0, 873, 874, 3, 384, 192, 0, 874, 43, 1, 0, 0, 0, 875, 876, 3, 444, 222, 0, 876, 877, 3, 514, 257, 0, 877, 879, 3, 592, 296, 0, 878, 880, 3, 276, 138, 0, 879, 878, 1, 0, 0, 0, 879, 880, 1, 0, 0, 0, 880, 884, 1, 0, 0, 0, 881, 882, 3, 366, 183, 0, 882, 883, 5, 10, 0, 0, 883, 885, 1, 0, 0, 0, 884, 881, 1, 0, 0, 0, 884, 885, 1, 0, 0, 0, 885, 886, 1, 0, 0, 0, 886, 887, 3, 386, 193, 0, 887, 888, 3, 422, 211, 0, 888, 889, 3, 552, 276, 0, 889, 890, 3, 284, 142, 0, 890, 891, 3, 468, 234, 0, 891, 892, 3, 298, 149, 0, 892, 893, 3, 46, 23, 0, 893, 894, 3, 538, 269, 0, 894, 895, 3, 496, 248, 0, 895, 896, 3, 602, 301, 0, 896, 897, 3, 284, 142, 0, 897, 901, 3, 604, 302, 0, 898, 899, 3, 596, 298, 0, 899, 900, 3, 52, 26, 0, 900, 902, 1, 0, 0, 0, 901, 898, 1, 0, 0, 0, 901, 902, 1, 0, 0, 0, 902, 45, 1, 0, 0, 0, 903, 904, 3, 594, 297, 0, 904, 908, 3, 48, 24, 0, 905, 906, 3, 418, 209, 0, 906, 907, 3, 322, 161, 0, 907, 909, 1, 0, 0, 0, 908, 905, 1, 0, 0, 0, 908, 909, 1, 0, 0, 0, 909, 47, 1, 0, 0, 0, 910, 916, 3, 50, 25, 0, 911, 912, 3, 418, 209, 0, 912, 913, 3, 50, 25, 0, 913, 915, 1, 0, 0, 0, 914, 911, 1, 0, 0, 0, 915, 918, 1, 0, 0, 0, 916, 914, 1, 0, 0, 0, 916, 917, 1, 0, 0, 0, 917, 49, 1, 0, 0, 0, 918, 916, 1, 0, 0, 0, 919, 920, 3, 370, 185, 0, 920, 921, 3, 492, 246, 0, 921, 922, 3, 522, 261, 0, 922, 923, 3, 524, 262, 0, 923, 51, 1, 0, 0, 0, 924, 931, 3, 158, 79, 0, 925, 926, 3, 158, 79, 0, 926, 927, 3, 418, 209, 0, 927, 928, 3, 156, 78, 0, 928, 931, 1, 0, 0, 0, 929, 931, 3, 156, 78, 0, 930, 924, 1, 0, 0, 0, 930, 925, 1, 0, 0, 0, 930, 929, 1, 0, 0, 0, 931, 53, 1, 0, 0, 0, 932, 933, 3, 444, 222, 0, 933, 935, 3, 500, 250, 0, 934, 936, 3, 276, 138, 0, 935, 934, 1, 0, 0, 0, 935, 936, 1, 0, 0, 0, 936, 937, 1, 0, 0, 0, 937, 938, 3, 366, 183, 0, 938, 939, 3, 596, 298, 0, 939, 940, 3, 544, 272, 0, 940, 941, 5, 19, 0, 0, 941, 942, 3, 606, 303, 0, 942, 943, 3, 206, 103, 0, 943, 947, 3, 608, 304, 0, 944, 945, 3, 418, 209, 0, 945, 946, 3, 210, 105, 0, 946, 948, 1, 0, 0, 0, 947, 944, 1, 0, 0, 0, 947, 948, 1, 0, 0, 0, 948, 55, 1, 0, 0, 0, 949, 951, 3, 444, 222, 0, 950, 952, 3, 76, 38, 0, 951, 950, 1, 0, 0, 0, 951, 952, 1, 0, 0, 0, 952, 953, 1, 0, 0, 0, 953, 955, 3, 472, 236, 0, 954, 956, 3, 276, 138, 0, 955, 954, 1, 0, 0, 0, 955, 956, 1, 0, 0, 0, 956, 960, 1, 0, 0, 0, 957, 958, 3, 366, 183, 0, 958, 959, 5, 10, 0, 0, 959, 961, 1, 0, 0, 0, 960, 957, 1, 0, 0, 0, 960, 961, 1, 0, 0, 0, 961, 962, 1, 0, 0, 0, 962, 963, 3, 392, 196, 0, 963, 965, 3, 602, 301, 0, 964, 966, 3, 60, 30, 0, 965, 964, 1, 0, 0, 0, 965, 966, 1, 0, 0, 0, 966, 967, 1, 0, 0, 0, 967, 968, 3, 604, 302, 0, 968, 969, 3, 62, 31, 0, 969, 970, 3, 546, 273, 0, 970, 971, 3, 372, 186, 0, 971, 972, 3, 504, 252, 0, 972, 973, 3, 394, 197, 0, 973, 974, 3, 422, 211, 0, 974, 975, 3, 58, 29, 0, 975, 57, 1, 0, 0, 0, 976, 977, 7, 0, 0, 0, 977, 59, 1, 0, 0, 0, 978, 984, 3, 402, 201, 0, 979, 980, 3, 618, 309, 0, 980, 981, 3, 402, 201, 0, 981, 983, 1, 0, 0, 0, 982, 979, 1, 0, 0, 0, 983, 986, 1, 0, 0, 0, 984, 982, 1, 0, 0, 0, 984, 985, 1, 0, 0, 0, 985, 61, 1, 0, 0, 0, 986, 984, 1, 0, 0, 0, 987, 992, 3, 436, 218, 0, 988, 989, 3, 546, 273, 0, 989, 990, 3, 524, 262, 0, 990, 992, 1, 0, 0, 0, 991, 987, 1, 0, 0, 0, 991, 988, 1, 0, 0, 0, 992, 993, 1, 0, 0, 0, 993, 994, 3, 528, 264, 0, 994, 995, 3, 524, 262, 0, 995, 996, 3, 486, 243, 0, 996, 63, 1, 0, 0, 0, 997, 999, 3, 444, 222, 0, 998, 1000, 3, 76, 38, 0, 999, 998, 1, 0, 0, 0, 999, 1000, 1, 0, 0, 0, 1000, 1001, 1, 0, 0, 0, 1001, 1003, 3, 408, 204, 0, 1002, 1004, 3, 276, 138, 0, 1003, 1002, 1, 0, 0, 0, 1003, 1004, 1, 0, 0, 0, 1004, 1008, 1, 0, 0, 0, 1005, 1006, 3, 366, 183, 0, 1006, 1007, 5, 10, 0, 0, 1007, 1009, 1, 0, 0, 0, 1008, 1005, 1, 0, 0, 0, 1008, 1009, 1, 0, 0, 0, 1009, 1010, 1, 0, 0, 0, 1010, 1011, 3, 390, 195, 0, 1011, 1012, 3, 602, 301, 0, 1012, 1013, 3, 372, 186, 0, 1013, 1014, 3, 604, 302, 0, 1014, 1015, 3, 556, 278, 0, 1015, 1016, 3, 392, 196, 0, 1016, 1017, 3, 560, 280, 0, 1017, 1018, 3, 372, 186, 0, 1018, 1019, 3, 466, 233, 0, 1019, 1020, 3, 392, 196, 0, 1020, 1021, 3, 484, 242, 0, 1021, 1022, 3, 66, 33, 0, 1022, 65, 1, 0, 0, 0, 1023, 1028, 3, 354, 177, 0, 1024, 1028, 3, 74, 37, 0, 1025, 1028, 3, 72, 36, 0, 1026, 1028, 3, 68, 34, 0, 1027, 1023, 1, 0, 0, 0, 1027, 1024, 1, 0, 0, 0, 1027, 1025, 1, 0, 0, 0, 1027, 1026, 1, 0, 0, 0, 1028, 67, 1, 0, 0, 0, 1029, 1030, 3, 606, 303, 0, 1030, 1036, 3, 70, 35, 0, 1031, 1032, 3, 618, 309, 0, 1032, 1033, 3, 70, 35, 0, 1033, 1035, 1, 0, 0, 0, 1034, 1031, 1, 0, 0, 0, 1035, 1038, 1, 0, 0, 0, 1036, 1034, 1, 0, 0, 0, 1036, 1037, 1, 0, 0, 0, 1037, 1039, 1, 0, 0, 0, 1038, 1036, 1, 0, 0, 0, 1039, 1040, 3, 608, 304, 0, 1040, 69, 1, 0, 0, 0, 1041, 1042, 3, 400, 200, 0, 1042, 1043, 5, 9, 0, 0, 1043, 1044, 3, 66, 33, 0, 1044, 71, 1, 0, 0, 0, 1045, 1046, 3, 602, 301, 0, 1046, 1053, 3, 74, 37, 0, 1047, 1048, 3, 618, 309, 0, 1048, 1049, 3, 354, 177, 0, 1049, 1052, 1, 0, 0, 0, 1050, 1052, 3, 74, 37, 0, 1051, 1047, 1, 0, 0, 0, 1051, 1050, 1, 0, 0, 0, 1052, 1055, 1, 0, 0, 0, 1053, 1051, 1, 0, 0, 0, 1053, 1054, 1, 0, 0, 0, 1054, 1056, 1, 0, 0, 0, 1055, 1053, 1, 0, 0, 0, 1056, 1057, 3, 604, 302, 0, 1057, 73, 1, 0, 0, 0, 1058, 1059, 3, 602, 301, 0, 1059, 1065, 3, 354, 177, 0, 1060, 1061, 3, 618, 309, 0, 1061, 1062, 3, 354, 177, 0, 1062, 1064, 1, 0, 0, 0, 1063, 1060, 1, 0, 0, 0, 1064, 1067, 1, 0, 0, 0, 1065, 1063, 1, 0, 0, 0, 1065, 1066, 1, 0, 0, 0, 1066, 1068, 1, 0, 0, 0, 1067, 1065, 1, 0, 0, 0, 1068, 1069, 3, 604, 302, 0, 1069, 75, 1, 0, 0, 0, 1070, 1071, 3, 532, 266, 0, 1071, 1072, 3, 542, 271, 0, 1072, 77, 1, 0, 0, 0, 1073, 1074, 3, 416, 208, 0, 1074, 1075, 3, 586, 293, 0, 1075, 1076, 3, 396, 198, 0, 1076, 1077, 3, 596, 298, 0, 1077, 1079, 3, 80, 40, 0, 1078, 1080, 3, 82, 41, 0, 1079, 1078, 1, 0, 0, 0, 1079, 1080, 1, 0, 0, 0, 1080, 79, 1, 0, 0, 0, 1081, 1082, 3, 536, 268, 0, 1082, 1083, 3, 360, 180, 0, 1083, 81, 1, 0, 0, 0, 1084, 1087, 3, 562, 281, 0, 1085, 1087, 3, 518, 259, 0, 1086, 1084, 1, 0, 0, 0, 1086, 1085, 1, 0, 0, 0, 1087, 83, 1, 0, 0, 0, 1088, 1089, 3, 416, 208, 0, 1089, 1093, 3, 578, 289, 0, 1090, 1091, 3, 366, 183, 0, 1091, 1092, 5, 10, 0, 0, 1092, 1094, 1, 0, 0, 0, 1093, 1090, 1, 0, 0, 0, 1093, 1094, 1, 0, 0, 0, 1094, 1095, 1, 0, 0, 0, 1095, 1096, 3, 388, 194, 0, 1096, 1097, 3, 86, 43, 0, 1097, 85, 1, 0, 0, 0, 1098, 1102, 3, 96, 48, 0, 1099, 1102, 3, 94, 47, 0, 1100, 1102, 3, 88, 44, 0, 1101, 1098, 1, 0, 0, 0, 1101, 1099, 1, 0, 0, 0, 1101, 1100, 1, 0, 0, 0, 1102, 87, 1, 0, 0, 0, 1103, 1104, 3, 540, 270, 0, 1104, 1105, 3, 90, 45, 0, 1105, 89, 1, 0, 0, 0, 1106, 1112, 3, 92, 46, 0, 1107, 1108, 3, 418, 209, 0, 1108, 1109, 3, 92, 46, 0, 1109, 1111, 1, 0, 0, 0, 1110, 1107, 1, 0, 0, 0, 1111, 1114, 1, 0, 0, 0, 1112, 1110, 1, 0, 0, 0, 1112, 1113, 1, 0, 0, 0, 1113, 91, 1, 0, 0, 0, 1114, 1112, 1, 0, 0, 0, 1115, 1116, 3, 370, 185, 0, 1116, 1117, 3, 570, 285, 0, 1117, 1118, 3, 370, 185, 0, 1118, 93, 1, 0, 0, 0, 1119, 1120, 3, 406, 203, 0, 1120, 1121, 3, 370, 185, 0, 1121, 1128, 3, 372, 186, 0, 1122, 1123, 3, 618, 309, 0, 1123, 1124, 3, 370, 185, 0, 1124, 1125, 3, 372, 186, 0, 1125, 1127, 1, 0, 0, 0, 1126, 1122, 1, 0, 0, 0, 1127, 1130, 1, 0, 0, 0, 1128, 1126, 1, 0, 0, 0, 1128, 1129, 1, 0, 0, 0, 1129, 95, 1, 0, 0, 0, 1130, 1128, 1, 0, 0, 0, 1131, 1132, 3, 416, 208, 0, 1132, 1133, 3, 370, 185, 0, 1133, 1134, 3, 578, 289, 0, 1134, 1135, 3, 372, 186, 0, 1135, 97, 1, 0, 0, 0, 1136, 1137, 3, 416, 208, 0, 1137, 1138, 3, 564, 282, 0, 1138, 1139, 3, 298, 149, 0, 1139, 1140, 3, 100, 50, 0, 1140, 99, 1, 0, 0, 0, 1141, 1148, 3, 118, 59, 0, 1142, 1148, 3, 108, 54, 0, 1143, 1148, 3, 106, 53, 0, 1144, 1148, 3, 112, 56, 0, 1145, 1148, 3, 104, 52, 0, 1146, 1148, 3, 102, 51, 0, 1147, 1141, 1, 0, 0, 0, 1147, 1142, 1, 0, 0, 0, 1147, 1143, 1, 0, 0, 0, 1147, 1144, 1, 0, 0, 0, 1147, 1145, 1, 0, 0, 0, 1147, 1146, 1, 0, 0, 0, 1148, 101, 1, 0, 0, 0, 1149, 1150, 3, 596, 298, 0, 1150, 1151, 3, 158, 79, 0, 1151, 103, 1, 0, 0, 0, 1152, 1153, 3, 540, 270, 0, 1153, 1154, 3, 370, 185, 0, 1154, 1155, 3, 570, 285, 0, 1155, 1156, 3, 370, 185, 0, 1156, 105, 1, 0, 0, 0, 1157, 1158, 3, 454, 227, 0, 1158, 1159, 3, 440, 220, 0, 1159, 1160, 3, 558, 279, 0, 1160, 107, 1, 0, 0, 0, 1161, 1162, 3, 454, 227, 0, 1162, 1163, 3, 110, 55, 0, 1163, 109, 1, 0, 0, 0, 1164, 1170, 3, 370, 185, 0, 1165, 1166, 3, 618, 309, 0, 1166, 1167, 3, 370, 185, 0, 1167, 1169, 1, 0, 0, 0, 1168, 1165, 1, 0, 0, 0, 1169, 1172, 1, 0, 0, 0, 1170, 1168, 1, 0, 0, 0, 1170, 1171, 1, 0, 0, 0, 1171, 111, 1, 0, 0, 0, 1172, 1170, 1, 0, 0, 0, 1173, 1174, 3, 416, 208, 0, 1174, 1175, 3, 114, 57, 0, 1175, 113, 1, 0, 0, 0, 1176, 1182, 3, 116, 58, 0, 1177, 1178, 3, 618, 309, 0, 1178, 1179, 3, 116, 58, 0, 1179, 1181, 1, 0, 0, 0, 1180, 1177, 1, 0, 0, 0, 1181, 1184, 1, 0, 0, 0, 1182, 1180, 1, 0, 0, 0, 1182, 1183, 1, 0, 0, 0, 1183, 115, 1, 0, 0, 0, 1184, 1182, 1, 0, 0, 0, 1185, 1186, 3, 370, 185, 0, 1186, 1187, 3, 578, 289, 0, 1187, 1188, 3, 372, 186, 0, 1188, 117, 1, 0, 0, 0, 1189, 1190, 3, 406, 203, 0, 1190, 1191, 3, 120, 60, 0, 1191, 119, 1, 0, 0, 0, 1192, 1198, 3, 122, 61, 0, 1193, 1194, 3, 618, 309, 0, 1194, 1195, 3, 122, 61, 0, 1195, 1197, 1, 0, 0, 0, 1196, 1193, 1, 0, 0, 0, 1197, 1200, 1, 0, 0, 0, 1198, 1196, 1, 0, 0, 0, 1198, 1199, 1, 0, 0, 0, 1199, 121, 1, 0, 0, 0, 1200, 1198, 1, 0, 0, 0, 1201, 1202, 3, 370, 185, 0, 1202, 1203, 3, 372, 186, 0, 1203, 123, 1, 0, 0, 0, 1204, 1205, 3, 416, 208, 0, 1205, 1206, 3, 548, 274, 0, 1206, 1208, 3, 380, 190, 0, 1207, 1209, 3, 126, 63, 0, 1208, 1207, 1, 0, 0, 0, 1208, 1209, 1, 0, 0, 0, 1209, 125, 1, 0, 0, 0, 1210, 1211, 3, 596, 298, 0, 1211, 1217, 3, 128, 64, 0, 1212, 1213, 3, 418, 209, 0, 1213, 1214, 3, 128, 64, 0, 1214, 1216, 1, 0, 0, 0, 1215, 1212, 1, 0, 0, 0, 1216, 1219, 1, 0, 0, 0, 1217, 1215, 1, 0, 0, 0, 1217, 1218, 1, 0, 0, 0, 1218, 127, 1, 0, 0, 0, 1219, 1217, 1, 0, 0, 0, 1220, 1221, 3, 536, 268, 0, 1221, 1222, 5, 19, 0, 0, 1222, 1223, 3, 360, 180, 0, 1223, 1237, 1, 0, 0, 0, 1224, 1225, 3, 512, 256, 0, 1225, 1226, 5, 19, 0, 0, 1226, 1227, 3, 362, 181, 0, 1227, 1237, 1, 0, 0, 0, 1228, 1229, 3, 562, 281, 0, 1229, 1230, 5, 19, 0, 0, 1230, 1231, 3, 362, 181, 0, 1231, 1237, 1, 0, 0, 0, 1232, 1233, 3, 530, 265, 0, 1233, 1234, 5, 19, 0, 0, 1234, 1235, 3, 166, 83, 0, 1235, 1237, 1, 0, 0, 0, 1236, 1220, 1, 0, 0, 0, 1236, 1224, 1, 0, 0, 0, 1236, 1228, 1, 0, 0, 0, 1236, 1232, 1, 0, 0, 0, 1237, 129, 1, 0, 0, 0, 1238, 1239, 3, 416, 208, 0, 1239, 1240, 3, 514, 257, 0, 1240, 1244, 3, 592, 296, 0, 1241, 1242, 3, 366, 183, 0, 1242, 1243, 5, 10, 0, 0, 1243, 1245, 1, 0, 0, 0, 1244, 1241, 1, 0, 0, 0, 1244, 1245, 1, 0, 0, 0, 1245, 1246, 1, 0, 0, 0, 1246, 1250, 3, 386, 193, 0, 1247, 1248, 3, 596, 298, 0, 1248, 1249, 3, 158, 79, 0, 1249, 1251, 1, 0, 0, 0, 1250, 1247, 1, 0, 0, 0, 1250, 1251, 1, 0, 0, 0, 1251, 131, 1, 0, 0, 0, 1252, 1253, 3, 454, 227, 0, 1253, 1255, 3, 586, 293, 0, 1254, 1256, 3, 278, 139, 0, 1255, 1254, 1, 0, 0, 0, 1255, 1256, 1, 0, 0, 0, 1256, 1257, 1, 0, 0, 0, 1257, 1258, 3, 396, 198, 0, 1258, 133, 1, 0, 0, 0, 1259, 1260, 3, 454, 227, 0, 1260, 1262, 3, 578, 289, 0, 1261, 1263, 3, 278, 139, 0, 1262, 1261, 1, 0, 0, 0, 1262, 1263, 1, 0, 0, 0, 1263, 1267, 1, 0, 0, 0, 1264, 1265, 3, 366, 183, 0, 1265, 1266, 5, 10, 0, 0, 1266, 1268, 1, 0, 0, 0, 1267, 1264, 1, 0, 0, 0, 1267, 1268, 1, 0, 0, 0, 1268, 1269, 1, 0, 0, 0, 1269, 1270, 3, 388, 194, 0, 1270, 135, 1, 0, 0, 0, 1271, 1272, 3, 454, 227, 0, 1272, 1273, 3, 514, 257, 0, 1273, 1275, 3, 592, 296, 0, 1274, 1276, 3, 278, 139, 0, 1275, 1274, 1, 0, 0, 0, 1275, 1276, 1, 0, 0, 0, 1276, 1280, 1, 0, 0, 0, 1277, 1278, 3, 366, 183, 0, 1278, 1279, 5, 10, 0, 0, 1279, 1281, 1, 0, 0, 0, 1280, 1277, 1, 0, 0, 0, 1280, 1281, 1, 0, 0, 0, 1281, 1282, 1, 0, 0, 0, 1282, 1283, 3, 386, 193, 0, 1283, 137, 1, 0, 0, 0, 1284, 1285, 3, 454, 227, 0, 1285, 1287, 3, 408, 204, 0, 1286, 1288, 3, 278, 139, 0, 1287, 1286, 1, 0, 0, 0, 1287, 1288, 1, 0, 0, 0, 1288, 1292, 1, 0, 0, 0, 1289, 1290, 3, 366, 183, 0, 1290, 1291, 5, 10, 0, 0, 1291, 1293, 1, 0, 0, 0, 1292, 1289, 1, 0, 0, 0, 1292, 1293, 1, 0, 0, 0, 1293, 1294, 1, 0, 0, 0, 1294, 1295, 3, 390, 195, 0, 1295, 139, 1, 0, 0, 0, 1296, 1297, 3, 454, 227, 0, 1297, 1299, 3, 472, 236, 0, 1298, 1300, 3, 278, 139, 0, 1299, 1298, 1, 0, 0, 0, 1299, 1300, 1, 0, 0, 0, 1300, 1304, 1, 0, 0, 0, 1301, 1302, 3, 366, 183, 0, 1302, 1303, 5, 10, 0, 0, 1303, 1305, 1, 0, 0, 0, 1304, 1301, 1, 0, 0, 0, 1304, 1305, 1, 0, 0, 0, 1305, 1306, 1, 0, 0, 0, 1306, 1307, 3, 392, 196, 0, 1307, 141, 1, 0, 0, 0, 1308, 1309, 3, 454, 227, 0, 1309, 1311, 3, 572, 286, 0, 1310, 1312, 3, 278, 139, 0, 1311, 1310, 1, 0, 0, 0, 1311, 1312, 1, 0, 0, 0, 1312, 1313, 1, 0, 0, 0, 1313, 1314, 3, 382, 191, 0, 1314, 1315, 3, 528, 264, 0, 1315, 1316, 3, 298, 149, 0, 1316, 143, 1, 0, 0, 0, 1317, 1318, 3, 454, 227, 0, 1318, 1320, 3, 548, 274, 0, 1319, 1321, 3, 278, 139, 0, 1320, 1319, 1, 0, 0, 0, 1320, 1321, 1, 0, 0, 0, 1321, 1322, 1, 0, 0, 0, 1322, 1323, 3, 380, 190, 0, 1323, 145, 1, 0, 0, 0, 1324, 1325, 3, 454, 227, 0, 1325, 1327, 3, 564, 282, 0, 1326, 1328, 3, 278, 139, 0, 1327, 1326, 1, 0, 0, 0, 1327, 1328, 1, 0, 0, 0, 1328, 1329, 1, 0, 0, 0, 1329, 1330, 3, 298, 149, 0, 1330, 147, 1, 0, 0, 0, 1331, 1332, 3, 454, 227, 0, 1332, 1334, 3, 500, 250, 0, 1333, 1335, 3, 278, 139, 0, 1334, 1333, 1, 0, 0, 0, 1334, 1335, 1, 0, 0, 0, 1335, 1336, 1, 0, 0, 0, 1336, 1337, 3, 366, 183, 0, 1337, 149, 1, 0, 0, 0, 1338, 1339, 3, 454, 227, 0, 1339, 1341, 3, 482, 241, 0, 1340, 1342, 3, 278, 139, 0, 1341, 1340, 1, 0, 0, 0, 1341, 1342, 1, 0, 0, 0, 1342, 1346, 1, 0, 0, 0, 1343, 1344, 3, 366, 183, 0, 1344, 1345, 5, 10, 0, 0, 1345, 1347, 1, 0, 0, 0, 1346, 1343, 1, 0, 0, 0, 1346, 1347, 1, 0, 0, 0, 1347, 1348, 1, 0, 0, 0, 1348, 1349, 3, 218, 109, 0, 1349, 151, 1, 0, 0, 0, 1350, 1351, 3, 444, 222, 0, 1351, 1353, 3, 564, 282, 0, 1352, 1354, 3, 276, 138, 0, 1353, 1352, 1, 0, 0, 0, 1353, 1354, 1, 0, 0, 0, 1354, 1355, 1, 0, 0, 0, 1355, 1356, 3, 298, 149, 0, 1356, 1357, 3, 602, 301, 0, 1357, 1358, 3, 174, 87, 0, 1358, 1360, 3, 604, 302, 0, 1359, 1361, 3, 154, 77, 0, 1360, 1359, 1, 0, 0, 0, 1360, 1361, 1, 0, 0, 0, 1361, 153, 1, 0, 0, 0, 1362, 1364, 3, 596, 298, 0, 1363, 1365, 3, 158, 79, 0, 1364, 1363, 1, 0, 0, 0, 1364, 1365, 1, 0, 0, 0, 1365, 1367, 1, 0, 0, 0, 1366, 1368, 3, 156, 78, 0, 1367, 1366, 1, 0, 0, 0, 1367, 1368, 1, 0, 0, 0, 1368, 155, 1, 0, 0, 0, 1369, 1370, 3, 438, 219, 0, 1370, 1371, 3, 534, 267, 0, 1371, 1372, 3, 434, 217, 0, 1372, 1373, 3, 602, 301, 0, 1373, 1375, 3, 370, 185, 0, 1374, 1376, 3, 378, 189, 0, 1375, 1374, 1, 0, 0, 0, 1375, 1376, 1, 0, 0, 0, 1376, 1377, 1, 0, 0, 0, 1377, 1378, 3, 604, 302, 0, 1378, 157, 1, 0, 0, 0, 1379, 1385, 3, 160, 80, 0, 1380, 1381, 3, 418, 209, 0, 1381, 1382, 3, 160, 80, 0, 1382, 1384, 1, 0, 0, 0, 1383, 1380, 1, 0, 0, 0, 1384, 1387, 1, 0, 0, 0, 1385, 1383, 1, 0, 0, 0, 1385, 1386, 1, 0, 0, 0, 1386, 159, 1, 0, 0, 0, 1387, 1385, 1, 0, 0, 0, 1388, 1389, 3, 162, 81, 0, 1389, 1390, 5, 19, 0, 0, 1390, 1391, 3, 164, 82, 0, 1391, 1397, 1, 0, 0, 0, 1392, 1393, 3, 162, 81, 0, 1393, 1394, 5, 19, 0, 0, 1394, 1395, 3, 166, 83, 0, 1395, 1397, 1, 0, 0, 0, 1396, 1388, 1, 0, 0, 0, 1396, 1392, 1, 0, 0, 0, 1397, 161, 1, 0, 0, 0, 1398, 1399, 5, 174, 0, 0, 1399, 163, 1, 0, 0, 0, 1400, 1403, 3, 360, 180, 0, 1401, 1403, 3, 358, 179, 0, 1402, 1400, 1, 0, 0, 0, 1402, 1401, 1, 0, 0, 0, 1403, 165, 1, 0, 0, 0, 1404, 1405, 3, 606, 303, 0, 1405, 1411, 3, 168, 84, 0, 1406, 1407, 3, 618, 309, 0, 1407, 1408, 3, 168, 84, 0, 1408, 1410, 1, 0, 0, 0, 1409, 1406, 1, 0, 0, 0, 1410, 1413, 1, 0, 0, 0, 1411, 1409, 1, 0, 0, 0, 1411, 1412, 1, 0, 0, 0, 1412, 1414, 1, 0, 0, 0, 1413, 1411, 1, 0, 0, 0, 1414, 1415, 3, 608, 304, 0, 1415, 167, 1, 0, 0, 0, 1416, 1417, 3, 170, 85, 0, 1417, 1418, 5, 9, 0, 0, 1418, 1419, 3, 172, 86, 0, 1419, 169, 1, 0, 0, 0, 1420, 1421, 3, 360, 180, 0, 1421, 171, 1, 0, 0, 0, 1422, 1425, 3, 360, 180, 0, 1423, 1425, 3, 358, 179, 0, 1424, 1422, 1, 0, 0, 0, 1424, 1423, 1, 0, 0, 0, 1425, 173, 1, 0, 0, 0, 1426, 1432, 3, 176, 88, 0, 1427, 1428, 3, 618, 309, 0, 1428, 1429, 3, 176, 88, 0, 1429, 1431, 1, 0, 0, 0, 1430, 1427, 1, 0, 0, 0, 1431, 1434, 1, 0, 0, 0, 1432, 1430, 1, 0, 0, 0, 1432, 1433, 1, 0, 0, 0, 1433, 1438, 1, 0, 0, 0, 1434, 1432, 1, 0, 0, 0, 1435, 1436, 3, 618, 309, 0, 1436, 1437, 3, 180, 90, 0, 1437, 1439, 1, 0, 0, 0, 1438, 1435, 1, 0, 0, 0, 1438, 1439, 1, 0, 0, 0, 1439, 175, 1, 0, 0, 0, 1440, 1441, 3, 370, 185, 0, 1441, 1443, 3, 372, 186, 0, 1442, 1444, 3, 178, 89, 0, 1443, 1442, 1, 0, 0, 0, 1443, 1444, 1, 0, 0, 0, 1444, 177, 1, 0, 0, 0, 1445, 1446, 3, 538, 269, 0, 1446, 1447, 3, 496, 248, 0, 1447, 179, 1, 0, 0, 0, 1448, 1449, 3, 538, 269, 0, 1449, 1450, 3, 496, 248, 0, 1450, 1451, 3, 602, 301, 0, 1451, 1452, 3, 182, 91, 0, 1452, 1453, 3, 604, 302, 0, 1453, 181, 1, 0, 0, 0, 1454, 1458, 3, 184, 92, 0, 1455, 1458, 3, 186, 93, 0, 1456, 1458, 3, 188, 94, 0, 1457, 1454, 1, 0, 0, 0, 1457, 1455, 1, 0, 0, 0, 1457, 1456, 1, 0, 0, 0, 1458, 183, 1, 0, 0, 0, 1459, 1460, 3, 370, 185, 0, 1460, 185, 1, 0, 0, 0, 1461, 1462, 3, 194, 97, 0, 1462, 1463, 3, 618, 309, 0, 1463, 1464, 3, 192, 96, 0, 1464, 187, 1, 0, 0, 0, 1465, 1466, 3, 602, 301, 0, 1466, 1467, 3, 190, 95, 0, 1467, 1468, 3, 604, 302, 0, 1468, 1469, 3, 618, 309, 0, 1469, 1470, 3, 192, 96, 0, 1470, 189, 1, 0, 0, 0, 1471, 1477, 3, 194, 97, 0, 1472, 1473, 3, 618, 309, 0, 1473, 1474, 3, 194, 97, 0, 1474, 1476, 1, 0, 0, 0, 1475, 1472, 1, 0, 0, 0, 1476, 1479, 1, 0, 0, 0, 1477, 1475, 1, 0, 0, 0, 1477, 1478, 1, 0, 0, 0, 1478, 191, 1, 0, 0, 0, 1479, 1477, 1, 0, 0, 0, 1480, 1486, 3, 196, 98, 0, 1481, 1482, 3, 618, 309, 0, 1482, 1483, 3, 196, 98, 0, 1483, 1485, 1, 0, 0, 0, 1484, 1481, 1, 0, 0, 0, 1485, 1488, 1, 0, 0, 0, 1486, 1484, 1, 0, 0, 0, 1486, 1487, 1, 0, 0, 0, 1487, 193, 1, 0, 0, 0, 1488, 1486, 1, 0, 0, 0, 1489, 1490, 3, 370, 185, 0, 1490, 195, 1, 0, 0, 0, 1491, 1492, 3, 370, 185, 0, 1492, 197, 1, 0, 0, 0, 1493, 1494, 3, 420, 210, 0, 1494, 1495, 3, 428, 214, 0, 1495, 199, 1, 0, 0, 0, 1496, 1498, 3, 432, 216, 0, 1497, 1499, 3, 202, 101, 0, 1498, 1497, 1, 0, 0, 0, 1498, 1499, 1, 0, 0, 0, 1499, 1500, 1, 0, 0, 0, 1500, 1502, 3, 428, 214, 0, 1501, 1503, 3, 274, 137, 0, 1502, 1501, 1, 0, 0, 0, 1502, 1503, 1, 0, 0, 0, 1503, 201, 1, 0, 0, 0, 1504, 1507, 3, 510, 255, 0, 1505, 1507, 3, 580, 290, 0, 1506, 1504, 1, 0, 0, 0, 1506, 1505, 1, 0, 0, 0, 1507, 203, 1, 0, 0, 0, 1508, 1509, 3, 416, 208, 0, 1509, 1510, 3, 500, 250, 0, 1510, 1511, 3, 366, 183, 0, 1511, 1512, 3, 596, 298, 0, 1512, 1513, 3, 544, 272, 0, 1513, 1514, 5, 19, 0, 0, 1514, 1515, 3, 606, 303, 0, 1515, 1516, 3, 206, 103, 0, 1516, 1520, 3, 608, 304, 0, 1517, 1518, 3, 418, 209, 0, 1518, 1519, 3, 210, 105, 0, 1519, 1521, 1, 0, 0, 0, 1520, 1517, 1, 0, 0, 0, 1520, 1521, 1, 0, 0, 0, 1521, 205, 1, 0, 0, 0, 1522, 1528, 3, 208, 104, 0, 1523, 1524, 3, 618, 309, 0, 1524, 1525, 3, 208, 104, 0, 1525, 1527, 1, 0, 0, 0, 1526, 1523, 1, 0, 0, 0, 1527, 1530, 1, 0, 0, 0, 1528, 1526, 1, 0, 0, 0, 1528, 1529, 1, 0, 0, 0, 1529, 207, 1, 0, 0, 0, 1530, 1528, 1, 0, 0, 0, 1531, 1532, 5, 169, 0, 0, 1532, 1533, 5, 9, 0, 0, 1533, 1538, 5, 169, 0, 0, 1534, 1535, 5, 169, 0, 0, 1535, 1536, 5, 9, 0, 0, 1536, 1538, 5, 170, 0, 0, 1537, 1531, 1, 0, 0, 0, 1537, 1534, 1, 0, 0, 0, 1538, 209, 1, 0, 0, 0, 1539, 1540, 3, 456, 228, 0, 1540, 1541, 5, 19, 0, 0, 1541, 1542, 3, 362, 181, 0, 1542, 211, 1, 0, 0, 0, 1543, 1544, 3, 584, 292, 0, 1544, 1545, 3, 366, 183, 0, 1545, 213, 1, 0, 0, 0, 1546, 1548, 3, 574, 287, 0, 1547, 1549, 3, 564, 282, 0, 1548, 1547, 1, 0, 0, 0, 1548, 1549, 1, 0, 0, 0, 1549, 1550, 1, 0, 0, 0, 1550, 1551, 3, 298, 149, 0, 1551, 215, 1, 0, 0, 0, 1552, 1553, 3, 444, 222, 0, 1553, 1555, 3, 482, 241, 0, 1554, 1556, 3, 276, 138, 0, 1555, 1554, 1, 0, 0, 0, 1555, 1556, 1, 0, 0, 0, 1556, 1558, 1, 0, 0, 0, 1557, 1559, 3, 218, 109, 0, 1558, 1557, 1, 0, 0, 0, 1558, 1559, 1, 0, 0, 0, 1559, 1560, 1, 0, 0, 0, 1560, 1561, 3, 528, 264, 0, 1561, 1562, 3, 298, 149, 0, 1562, 1563, 3, 602, 301, 0, 1563, 1564, 3, 220, 110, 0, 1564, 1565, 3, 604, 302, 0, 1565, 217, 1, 0, 0, 0, 1566, 1569, 5, 174, 0, 0, 1567, 1569, 3, 360, 180, 0, 1568, 1566, 1, 0, 0, 0, 1568, 1567, 1, 0, 0, 0, 1569, 219, 1, 0, 0, 0, 1570, 1575, 3, 370, 185, 0, 1571, 1575, 3, 222, 111, 0, 1572, 1575, 3, 224, 112, 0, 1573, 1575, 3, 226, 113, 0, 1574, 1570, 1, 0, 0, 0, 1574, 1571, 1, 0, 0, 0, 1574, 1572, 1, 0, 0, 0, 1574, 1573, 1, 0, 0, 0, 1575, 221, 1, 0, 0, 0, 1576, 1577, 3, 498, 249, 0, 1577, 1578, 3, 602, 301, 0, 1578, 1579, 5, 174, 0, 0, 1579, 1580, 3, 604, 302, 0, 1580, 223, 1, 0, 0, 0, 1581, 1582, 3, 458, 229, 0, 1582, 1583, 3, 602, 301, 0, 1583, 1584, 5, 174, 0, 0, 1584, 1585, 3, 604, 302, 0, 1585, 225, 1, 0, 0, 0, 1586, 1587, 3, 470, 235, 0, 1587, 1588, 3, 602, 301, 0, 1588, 1589, 5, 174, 0, 0, 1589, 1590, 3, 604, 302, 0, 1590, 227, 1, 0, 0, 0, 1591, 1593, 3, 200, 100, 0, 1592, 1591, 1, 0, 0, 0, 1592, 1593, 1, 0, 0, 0, 1593, 1594, 1, 0, 0, 0, 1594, 1596, 3, 446, 223, 0, 1595, 1597, 3, 230, 115, 0, 1596, 1595, 1, 0, 0, 0, 1596, 1597, 1, 0, 0, 0, 1597, 1598, 1, 0, 0, 0, 1598, 1600, 3, 300, 150, 0, 1599, 1601, 3, 274, 137, 0, 1600, 1599, 1, 0, 0, 0, 1600, 1601, 1, 0, 0, 0, 1601, 1602, 1, 0, 0, 0, 1602, 1605, 3, 306, 153, 0, 1603, 1606, 3, 278, 139, 0, 1604, 1606, 3, 236, 118, 0, 1605, 1603, 1, 0, 0, 0, 1605, 1604, 1, 0, 0, 0, 1605, 1606, 1, 0, 0, 0, 1606, 1608, 1, 0, 0, 0, 1607, 1609, 3, 4, 2, 0, 1608, 1607, 1, 0, 0, 0, 1608, 1609, 1, 0, 0, 0, 1609, 229, 1, 0, 0, 0, 1610, 1616, 3, 232, 116, 0, 1611, 1612, 3, 618, 309, 0, 1612, 1613, 3, 232, 116, 0, 1613, 1615, 1, 0, 0, 0, 1614, 1611, 1, 0, 0, 0, 1615, 1618, 1, 0, 0, 0, 1616, 1614, 1, 0, 0, 0, 1616, 1617, 1, 0, 0, 0, 1617, 231, 1, 0, 0, 0, 1618, 1616, 1, 0, 0, 0, 1619, 1621, 3, 314, 157, 0, 1620, 1622, 3, 320, 160, 0, 1621, 1620, 1, 0, 0, 0, 1621, 1622, 1, 0, 0, 0, 1622, 1628, 1, 0, 0, 0, 1623, 1625, 3, 318, 159, 0, 1624, 1626, 3, 320, 160, 0, 1625, 1624, 1, 0, 0, 0, 1625, 1626, 1, 0, 0, 0, 1626, 1628, 1, 0, 0, 0, 1627, 1619, 1, 0, 0, 0, 1627, 1623, 1, 0, 0, 0, 1628, 233, 1, 0, 0, 0, 1629, 1631, 3, 200, 100, 0, 1630, 1629, 1, 0, 0, 0, 1630, 1631, 1, 0, 0, 0, 1631, 1632, 1, 0, 0, 0, 1632, 1633, 3, 582, 291, 0, 1633, 1635, 3, 298, 149, 0, 1634, 1636, 3, 268, 134, 0, 1635, 1634, 1, 0, 0, 0, 1635, 1636, 1, 0, 0, 0, 1636, 1637, 1, 0, 0, 0, 1637, 1638, 3, 554, 277, 0, 1638, 1639, 3, 242, 121, 0, 1639, 1642, 3, 306, 153, 0, 1640, 1643, 3, 278, 139, 0, 1641, 1643, 3, 236, 118, 0, 1642, 1640, 1, 0, 0, 0, 1642, 1641, 1, 0, 0, 0, 1642, 1643, 1, 0, 0, 0, 1643, 1645, 1, 0, 0, 0, 1644, 1646, 3, 4, 2, 0, 1645, 1644, 1, 0, 0, 0, 1645, 1646, 1, 0, 0, 0, 1646, 235, 1, 0, 0, 0, 1647, 1648, 3, 478, 239, 0, 1648, 1649, 3, 238, 119, 0, 1649, 237, 1, 0, 0, 0, 1650, 1656, 3, 240, 120, 0, 1651, 1652, 3, 418, 209, 0, 1652, 1653, 3, 240, 120, 0, 1653, 1655, 1, 0, 0, 0, 1654, 1651, 1, 0, 0, 0, 1655, 1658, 1, 0, 0, 0, 1656, 1654, 1, 0, 0, 0, 1656, 1657, 1, 0, 0, 0, 1657, 239, 1, 0, 0, 0, 1658, 1656, 1, 0, 0, 0, 1659, 1660, 5, 174, 0, 0, 1660, 1661, 5, 19, 0, 0, 1661, 1662, 3, 354, 177, 0, 1662, 241, 1, 0, 0, 0, 1663, 1669, 3, 244, 122, 0, 1664, 1665, 3, 618, 309, 0, 1665, 1666, 3, 244, 122, 0, 1666, 1668, 1, 0, 0, 0, 1667, 1664, 1, 0, 0, 0, 1668, 1671, 1, 0, 0, 0, 1669, 1667, 1, 0, 0, 0, 1669, 1670, 1, 0, 0, 0, 1670, 243, 1, 0, 0, 0, 1671, 1669, 1, 0, 0, 0, 1672, 1677, 3, 250, 125, 0, 1673, 1677, 3, 248, 124, 0, 1674, 1677, 3, 246, 123, 0, 1675, 1677, 3, 254, 127, 0, 1676, 1672, 1, 0, 0, 0, 1676, 1673, 1, 0, 0, 0, 1676, 1674, 1, 0, 0, 0, 1676, 1675, 1, 0, 0, 0, 1677, 245, 1, 0, 0, 0, 1678, 1679, 3, 370, 185, 0, 1679, 1680, 5, 19, 0, 0, 1680, 1681, 3, 352, 176, 0, 1681, 247, 1, 0, 0, 0, 1682, 1683, 3, 370, 185, 0, 1683, 1684, 5, 19, 0, 0, 1684, 1685, 3, 352, 176, 0, 1685, 1686, 3, 262, 131, 0, 1686, 1687, 5, 174, 0, 0, 1687, 249, 1, 0, 0, 0, 1688, 1689, 3, 370, 185, 0, 1689, 1690, 5, 19, 0, 0, 1690, 1691, 5, 174, 0, 0, 1691, 1692, 3, 262, 131, 0, 1692, 1693, 3, 352, 176, 0, 1693, 251, 1, 0, 0, 0, 1694, 1695, 3, 614, 307, 0, 1695, 1696, 3, 354, 177, 0, 1696, 1697, 3, 616, 308, 0, 1697, 253, 1, 0, 0, 0, 1698, 1699, 3, 370, 185, 0, 1699, 1700, 3, 252, 126, 0, 1700, 1701, 5, 19, 0, 0, 1701, 1702, 3, 354, 177, 0, 1702, 255, 1, 0, 0, 0, 1703, 1713, 3, 606, 303, 0, 1704, 1710, 3, 354, 177, 0, 1705, 1706, 3, 618, 309, 0, 1706, 1707, 3, 354, 177, 0, 1707, 1709, 1, 0, 0, 0, 1708, 1705, 1, 0, 0, 0, 1709, 1712, 1, 0, 0, 0, 1710, 1708, 1, 0, 0, 0, 1710, 1711, 1, 0, 0, 0, 1711, 1714, 1, 0, 0, 0, 1712, 1710, 1, 0, 0, 0, 1713, 1704, 1, 0, 0, 0, 1713, 1714, 1, 0, 0, 0, 1714, 1715, 1, 0, 0, 0, 1715, 1716, 3, 608, 304, 0, 1716, 257, 1, 0, 0, 0, 1717, 1718, 3, 606, 303, 0, 1718, 1719, 3, 354, 177, 0, 1719, 1720, 3, 620, 310, 0, 1720, 1721, 3, 354, 177, 0, 1721, 1729, 1, 0, 0, 0, 1722, 1723, 3, 618, 309, 0, 1723, 1724, 3, 354, 177, 0, 1724, 1725, 3, 620, 310, 0, 1725, 1726, 3, 354, 177, 0, 1726, 1728, 1, 0, 0, 0, 1727, 1722, 1, 0, 0, 0, 1728, 1731, 1, 0, 0, 0, 1729, 1727, 1, 0, 0, 0, 1729, 1730, 1, 0, 0, 0, 1730, 1732, 1, 0, 0, 0, 1731, 1729, 1, 0, 0, 0, 1732, 1733, 3, 608, 304, 0, 1733, 259, 1, 0, 0, 0, 1734, 1744, 3, 614, 307, 0, 1735, 1741, 3, 354, 177, 0, 1736, 1737, 3, 618, 309, 0, 1737, 1738, 3, 354, 177, 0, 1738, 1740, 1, 0, 0, 0, 1739, 1736, 1, 0, 0, 0, 1740, 1743, 1, 0, 0, 0, 1741, 1739, 1, 0, 0, 0, 1741, 1742, 1, 0, 0, 0, 1742, 1745, 1, 0, 0, 0, 1743, 1741, 1, 0, 0, 0, 1744, 1735, 1, 0, 0, 0, 1744, 1745, 1, 0, 0, 0, 1745, 1746, 1, 0, 0, 0, 1746, 1747, 3, 616, 308, 0, 1747, 261, 1, 0, 0, 0, 1748, 1749, 7, 1, 0, 0, 1749, 263, 1, 0, 0, 0, 1750, 1751, 3, 602, 301, 0, 1751, 1757, 3, 288, 144, 0, 1752, 1753, 3, 618, 309, 0, 1753, 1754, 3, 288, 144, 0, 1754, 1756, 1, 0, 0, 0, 1755, 1752, 1, 0, 0, 0, 1756, 1759, 1, 0, 0, 0, 1757, 1755, 1, 0, 0, 0, 1757, 1758, 1, 0, 0, 0, 1758, 1760, 1, 0, 0, 0, 1759, 1757, 1, 0, 0, 0, 1760, 1761, 3, 604, 302, 0, 1761, 265, 1, 0, 0, 0, 1762, 1764, 3, 200, 100, 0, 1763, 1762, 1, 0, 0, 0, 1763, 1764, 1, 0, 0, 0, 1764, 1765, 1, 0, 0, 0, 1765, 1766, 3, 488, 244, 0, 1766, 1767, 3, 490, 245, 0, 1767, 1769, 3, 298, 149, 0, 1768, 1770, 3, 282, 141, 0, 1769, 1768, 1, 0, 0, 0, 1769, 1770, 1, 0, 0, 0, 1770, 1771, 1, 0, 0, 0, 1771, 1773, 3, 280, 140, 0, 1772, 1774, 3, 276, 138, 0, 1773, 1772, 1, 0, 0, 0, 1773, 1774, 1, 0, 0, 0, 1774, 1776, 1, 0, 0, 0, 1775, 1777, 3, 268, 134, 0, 1776, 1775, 1, 0, 0, 0, 1776, 1777, 1, 0, 0, 0, 1777, 1779, 1, 0, 0, 0, 1778, 1780, 3, 4, 2, 0, 1779, 1778, 1, 0, 0, 0, 1779, 1780, 1, 0, 0, 0, 1780, 267, 1, 0, 0, 0, 1781, 1782, 3, 588, 294, 0, 1782, 1783, 3, 272, 136, 0, 1783, 1798, 1, 0, 0, 0, 1784, 1785, 3, 588, 294, 0, 1785, 1786, 3, 272, 136, 0, 1786, 1787, 3, 418, 209, 0, 1787, 1788, 3, 270, 135, 0, 1788, 1798, 1, 0, 0, 0, 1789, 1790, 3, 588, 294, 0, 1790, 1791, 3, 270, 135, 0, 1791, 1798, 1, 0, 0, 0, 1792, 1793, 3, 588, 294, 0, 1793, 1794, 3, 270, 135, 0, 1794, 1795, 3, 418, 209, 0, 1795, 1796, 3, 272, 136, 0, 1796, 1798, 1, 0, 0, 0, 1797, 1781, 1, 0, 0, 0, 1797, 1784, 1, 0, 0, 0, 1797, 1789, 1, 0, 0, 0, 1797, 1792, 1, 0, 0, 0, 1798, 269, 1, 0, 0, 0, 1799, 1802, 3, 568, 284, 0, 1800, 1803, 3, 338, 169, 0, 1801, 1803, 3, 356, 178, 0, 1802, 1800, 1, 0, 0, 0, 1802, 1801, 1, 0, 0, 0, 1803, 271, 1, 0, 0, 0, 1804, 1805, 3, 576, 288, 0, 1805, 1806, 3, 356, 178, 0, 1806, 273, 1, 0, 0, 0, 1807, 1808, 3, 588, 294, 0, 1808, 1809, 3, 270, 135, 0, 1809, 275, 1, 0, 0, 0, 1810, 1811, 3, 478, 239, 0, 1811, 1812, 3, 522, 261, 0, 1812, 1813, 3, 462, 231, 0, 1813, 277, 1, 0, 0, 0, 1814, 1815, 3, 478, 239, 0, 1815, 1816, 3, 462, 231, 0, 1816, 279, 1, 0, 0, 0, 1817, 1818, 3, 590, 295, 0, 1818, 1819, 5, 1, 0, 0, 1819, 1820, 3, 286, 143, 0, 1820, 1821, 5, 2, 0, 0, 1821, 1826, 1, 0, 0, 0, 1822, 1823, 3, 494, 247, 0, 1823, 1824, 3, 354, 177, 0, 1824, 1826, 1, 0, 0, 0, 1825, 1817, 1, 0, 0, 0, 1825, 1822, 1, 0, 0, 0, 1826, 281, 1, 0, 0, 0, 1827, 1828, 5, 1, 0, 0, 1828, 1829, 3, 284, 142, 0, 1829, 1830, 5, 2, 0, 0, 1830, 283, 1, 0, 0, 0, 1831, 1837, 3, 370, 185, 0, 1832, 1833, 3, 618, 309, 0, 1833, 1834, 3, 370, 185, 0, 1834, 1836, 1, 0, 0, 0, 1835, 1832, 1, 0, 0, 0, 1836, 1839, 1, 0, 0, 0, 1837, 1835, 1, 0, 0, 0, 1837, 1838, 1, 0, 0, 0, 1838, 285, 1, 0, 0, 0, 1839, 1837, 1, 0, 0, 0, 1840, 1846, 3, 352, 176, 0, 1841, 1842, 3, 618, 309, 0, 1842, 1843, 3, 352, 176, 0, 1843, 1845, 1, 0, 0, 0, 1844, 1841, 1, 0, 0, 0, 1845, 1848, 1, 0, 0, 0, 1846, 1844, 1, 0, 0, 0, 1846, 1847, 1, 0, 0, 0, 1847, 287, 1, 0, 0, 0, 1848, 1846, 1, 0, 0, 0, 1849, 1856, 3, 354, 177, 0, 1850, 1856, 3, 348, 174, 0, 1851, 1856, 3, 258, 129, 0, 1852, 1856, 3, 256, 128, 0, 1853, 1856, 3, 260, 130, 0, 1854, 1856, 3, 264, 132, 0, 1855, 1849, 1, 0, 0, 0, 1855, 1850, 1, 0, 0, 0, 1855, 1851, 1, 0, 0, 0, 1855, 1852, 1, 0, 0, 0, 1855, 1853, 1, 0, 0, 0, 1855, 1854, 1, 0, 0, 0, 1856, 289, 1, 0, 0, 0, 1857, 1859, 3, 552, 276, 0, 1858, 1860, 3, 308, 154, 0, 1859, 1858, 1, 0, 0, 0, 1859, 1860, 1, 0, 0, 0, 1860, 1862, 1, 0, 0, 0, 1861, 1863, 3, 494, 247, 0, 1862, 1861, 1, 0, 0, 0, 1862, 1863, 1, 0, 0, 0, 1863, 1864, 1, 0, 0, 0, 1864, 1865, 3, 310, 155, 0, 1865, 1867, 3, 300, 150, 0, 1866, 1868, 3, 306, 153, 0, 1867, 1866, 1, 0, 0, 0, 1867, 1868, 1, 0, 0, 0, 1868, 1870, 1, 0, 0, 0, 1869, 1871, 3, 622, 311, 0, 1870, 1869, 1, 0, 0, 0, 1870, 1871, 1, 0, 0, 0, 1871, 1873, 1, 0, 0, 0, 1872, 1874, 3, 302, 151, 0, 1873, 1872, 1, 0, 0, 0, 1873, 1874, 1, 0, 0, 0, 1874, 1876, 1, 0, 0, 0, 1875, 1877, 3, 294, 147, 0, 1876, 1875, 1, 0, 0, 0, 1876, 1877, 1, 0, 0, 0, 1877, 1879, 1, 0, 0, 0, 1878, 1880, 3, 292, 146, 0, 1879, 1878, 1, 0, 0, 0, 1879, 1880, 1, 0, 0, 0, 1880, 1882, 1, 0, 0, 0, 1881, 1883, 3, 4, 2, 0, 1882, 1881, 1, 0, 0, 0, 1882, 1883, 1, 0, 0, 0, 1883, 291, 1, 0, 0, 0, 1884, 1885, 3, 414, 207, 0, 1885, 1886, 3, 464, 232, 0, 1886, 293, 1, 0, 0, 0, 1887, 1890, 3, 506, 253, 0, 1888, 1891, 3, 338, 169, 0, 1889, 1891, 3, 356, 178, 0, 1890, 1888, 1, 0, 0, 0, 1890, 1889, 1, 0, 0, 0, 1891, 295, 1, 0, 0, 0, 1892, 1893, 5, 83, 0, 0, 1893, 297, 1, 0, 0, 0, 1894, 1895, 3, 366, 183, 0, 1895, 1896, 5, 10, 0, 0, 1896, 1898, 1, 0, 0, 0, 1897, 1894, 1, 0, 0, 0, 1897, 1898, 1, 0, 0, 0, 1898, 1899, 1, 0, 0, 0, 1899, 1900, 3, 368, 184, 0, 1900, 299, 1, 0, 0, 0, 1901, 1902, 3, 468, 234, 0, 1902, 1903, 3, 298, 149, 0, 1903, 301, 1, 0, 0, 0, 1904, 1905, 3, 534, 267, 0, 1905, 1906, 3, 434, 217, 0, 1906, 1912, 3, 304, 152, 0, 1907, 1908, 3, 618, 309, 0, 1908, 1909, 3, 304, 152, 0, 1909, 1911, 1, 0, 0, 0, 1910, 1907, 1, 0, 0, 0, 1911, 1914, 1, 0, 0, 0, 1912, 1910, 1, 0, 0, 0, 1912, 1913, 1, 0, 0, 0, 1913, 303, 1, 0, 0, 0, 1914, 1912, 1, 0, 0, 0, 1915, 1918, 5, 174, 0, 0, 1916, 1919, 3, 424, 212, 0, 1917, 1919, 3, 448, 224, 0, 1918, 1916, 1, 0, 0, 0, 1918, 1917, 1, 0, 0, 0, 1918, 1919, 1, 0, 0, 0, 1919, 305, 1, 0, 0, 0, 1920, 1921, 3, 594, 297, 0, 1921, 1922, 3, 322, 161, 0, 1922, 307, 1, 0, 0, 0, 1923, 1924, 3, 452, 226, 0, 1924, 309, 1, 0, 0, 0, 1925, 1928, 5, 11, 0, 0, 1926, 1928, 3, 312, 156, 0, 1927, 1925, 1, 0, 0, 0, 1927, 1926, 1, 0, 0, 0, 1928, 1934, 1, 0, 0, 0, 1929, 1930, 3, 618, 309, 0, 1930, 1931, 3, 312, 156, 0, 1931, 1933, 1, 0, 0, 0, 1932, 1929, 1, 0, 0, 0, 1933, 1936, 1, 0, 0, 0, 1934, 1932, 1, 0, 0, 0, 1934, 1935, 1, 0, 0, 0, 1935, 311, 1, 0, 0, 0, 1936, 1934, 1, 0, 0, 0, 1937, 1939, 3, 314, 157, 0, 1938, 1940, 3, 320, 160, 0, 1939, 1938, 1, 0, 0, 0, 1939, 1940, 1, 0, 0, 0, 1940, 1950, 1, 0, 0, 0, 1941, 1943, 3, 316, 158, 0, 1942, 1944, 3, 320, 160, 0, 1943, 1942, 1, 0, 0, 0, 1943, 1944, 1, 0, 0, 0, 1944, 1950, 1, 0, 0, 0, 1945, 1947, 3, 318, 159, 0, 1946, 1948, 3, 320, 160, 0, 1947, 1946, 1, 0, 0, 0, 1947, 1948, 1, 0, 0, 0, 1948, 1950, 1, 0, 0, 0, 1949, 1937, 1, 0, 0, 0, 1949, 1941, 1, 0, 0, 0, 1949, 1945, 1, 0, 0, 0, 1950, 313, 1, 0, 0, 0, 1951, 1952, 3, 370, 185, 0, 1952, 315, 1, 0, 0, 0, 1953, 1954, 3, 348, 174, 0, 1954, 317, 1, 0, 0, 0, 1955, 1956, 3, 370, 185, 0, 1956, 1957, 3, 614, 307, 0, 1957, 1958, 3, 354, 177, 0, 1958, 1959, 3, 616, 308, 0, 1959, 319, 1, 0, 0, 0, 1960, 1961, 3, 422, 211, 0, 1961, 1962, 5, 174, 0, 0, 1962, 321, 1, 0, 0, 0, 1963, 1969, 3, 324, 162, 0, 1964, 1965, 3, 418, 209, 0, 1965, 1966, 3, 324, 162, 0, 1966, 1968, 1, 0, 0, 0, 1967, 1964, 1, 0, 0, 0, 1968, 1971, 1, 0, 0, 0, 1969, 1967, 1, 0, 0, 0, 1969, 1970, 1, 0, 0, 0, 1970, 323, 1, 0, 0, 0, 1971, 1969, 1, 0, 0, 0, 1972, 2040, 3, 334, 167, 0, 1973, 2040, 3, 336, 168, 0, 1974, 2040, 3, 332, 166, 0, 1975, 2040, 3, 328, 164, 0, 1976, 2040, 3, 330, 165, 0, 1977, 2040, 3, 346, 173, 0, 1978, 2040, 3, 344, 172, 0, 1979, 2040, 3, 342, 171, 0, 1980, 1981, 5, 174, 0, 0, 1981, 1982, 5, 10, 0, 0, 1982, 1983, 5, 174, 0, 0, 1983, 1984, 3, 296, 148, 0, 1984, 1985, 3, 354, 177, 0, 1985, 2040, 1, 0, 0, 0, 1986, 1987, 5, 174, 0, 0, 1987, 1988, 5, 10, 0, 0, 1988, 1989, 5, 174, 0, 0, 1989, 1990, 3, 430, 215, 0, 1990, 1991, 3, 354, 177, 0, 1991, 1992, 3, 418, 209, 0, 1992, 1993, 3, 354, 177, 0, 1993, 2040, 1, 0, 0, 0, 1994, 1995, 5, 1, 0, 0, 1995, 2001, 5, 174, 0, 0, 1996, 1997, 3, 618, 309, 0, 1997, 1998, 5, 174, 0, 0, 1998, 2000, 1, 0, 0, 0, 1999, 1996, 1, 0, 0, 0, 2000, 2003, 1, 0, 0, 0, 2001, 1999, 1, 0, 0, 0, 2001, 2002, 1, 0, 0, 0, 2002, 2004, 1, 0, 0, 0, 2003, 2001, 1, 0, 0, 0, 2004, 2005, 5, 2, 0, 0, 2005, 2006, 3, 480, 240, 0, 2006, 2007, 5, 1, 0, 0, 2007, 2013, 3, 264, 132, 0, 2008, 2009, 3, 618, 309, 0, 2009, 2010, 3, 264, 132, 0, 2010, 2012, 1, 0, 0, 0, 2011, 2008, 1, 0, 0, 0, 2012, 2015, 1, 0, 0, 0, 2013, 2011, 1, 0, 0, 0, 2013, 2014, 1, 0, 0, 0, 2014, 2016, 1, 0, 0, 0, 2015, 2013, 1, 0, 0, 0, 2016, 2017, 5, 2, 0, 0, 2017, 2040, 1, 0, 0, 0, 2018, 2019, 5, 1, 0, 0, 2019, 2025, 5, 174, 0, 0, 2020, 2021, 3, 618, 309, 0, 2021, 2022, 5, 174, 0, 0, 2022, 2024, 1, 0, 0, 0, 2023, 2020, 1, 0, 0, 0, 2024, 2027, 1, 0, 0, 0, 2025, 2023, 1, 0, 0, 0, 2025, 2026, 1, 0, 0, 0, 2026, 2028, 1, 0, 0, 0, 2027, 2025, 1, 0, 0, 0, 2028, 2029, 5, 2, 0, 0, 2029, 2030, 3, 326, 163, 0, 2030, 2036, 3, 264, 132, 0, 2031, 2032, 3, 618, 309, 0, 2032, 2033, 3, 264, 132, 0, 2033, 2035, 1, 0, 0, 0, 2034, 2031, 1, 0, 0, 0, 2035, 2038, 1, 0, 0, 0, 2036, 2034, 1, 0, 0, 0, 2036, 2037, 1, 0, 0, 0, 2037, 2040, 1, 0, 0, 0, 2038, 2036, 1, 0, 0, 0, 2039, 1972, 1, 0, 0, 0, 2039, 1973, 1, 0, 0, 0, 2039, 1974, 1, 0, 0, 0, 2039, 1975, 1, 0, 0, 0, 2039, 1976, 1, 0, 0, 0, 2039, 1977, 1, 0, 0, 0, 2039, 1978, 1, 0, 0, 0, 2039, 1979, 1, 0, 0, 0, 2039, 1980, 1, 0, 0, 0, 2039, 1986, 1, 0, 0, 0, 2039, 1994, 1, 0, 0, 0, 2039, 2018, 1, 0, 0, 0, 2040, 325, 1, 0, 0, 0, 2041, 2042, 7, 2, 0, 0, 2042, 327, 1, 0, 0, 0, 2043, 2044, 3, 348, 174, 0, 2044, 2045, 3, 326, 163, 0, 2045, 2046, 3, 354, 177, 0, 2046, 329, 1, 0, 0, 0, 2047, 2048, 3, 348, 174, 0, 2048, 2049, 3, 326, 163, 0, 2049, 2050, 3, 348, 174, 0, 2050, 331, 1, 0, 0, 0, 2051, 2052, 3, 370, 185, 0, 2052, 2053, 3, 430, 215, 0, 2053, 2054, 3, 354, 177, 0, 2054, 2055, 3, 418, 209, 0, 2055, 2056, 3, 354, 177, 0, 2056, 333, 1, 0, 0, 0, 2057, 2058, 3, 370, 185, 0, 2058, 2059, 3, 326, 163, 0, 2059, 2060, 3, 354, 177, 0, 2060, 335, 1, 0, 0, 0, 2061, 2062, 3, 370, 185, 0, 2062, 2063, 3, 296, 148, 0, 2063, 2064, 3, 354, 177, 0, 2064, 337, 1, 0, 0, 0, 2065, 2066, 7, 3, 0, 0, 2066, 339, 1, 0, 0, 0, 2067, 2073, 3, 338, 169, 0, 2068, 2069, 5, 1, 0, 0, 2069, 2070, 3, 350, 175, 0, 2070, 2071, 5, 2, 0, 0, 2071, 2073, 1, 0, 0, 0, 2072, 2067, 1, 0, 0, 0, 2072, 2068, 1, 0, 0, 0, 2073, 341, 1, 0, 0, 0, 2074, 2075, 3, 370, 185, 0, 2075, 2076, 3, 480, 240, 0, 2076, 2077, 3, 340, 170, 0, 2077, 343, 1, 0, 0, 0, 2078, 2079, 3, 370, 185, 0, 2079, 2080, 3, 442, 221, 0, 2080, 2081, 3, 354, 177, 0, 2081, 345, 1, 0, 0, 0, 2082, 2083, 3, 370, 185, 0, 2083, 2084, 3, 442, 221, 0, 2084, 2085, 3, 496, 248, 0, 2085, 2086, 1, 0, 0, 0, 2086, 2087, 3, 354, 177, 0, 2087, 347, 1, 0, 0, 0, 2088, 2089, 5, 174, 0, 0, 2089, 2090, 5, 1, 0, 0, 2090, 2091, 5, 11, 0, 0, 2091, 2108, 5, 2, 0, 0, 2092, 2093, 5, 174, 0, 0, 2093, 2095, 5, 1, 0, 0, 2094, 2096, 3, 350, 175, 0, 2095, 2094, 1, 0, 0, 0, 2095, 2096, 1, 0, 0, 0, 2096, 2097, 1, 0, 0, 0, 2097, 2108, 5, 2, 0, 0, 2098, 2099, 5, 141, 0, 0, 2099, 2100, 5, 1, 0, 0, 2100, 2108, 5, 2, 0, 0, 2101, 2102, 5, 146, 0, 0, 2102, 2104, 5, 1, 0, 0, 2103, 2105, 3, 350, 175, 0, 2104, 2103, 1, 0, 0, 0, 2104, 2105, 1, 0, 0, 0, 2105, 2106, 1, 0, 0, 0, 2106, 2108, 5, 2, 0, 0, 2107, 2088, 1, 0, 0, 0, 2107, 2092, 1, 0, 0, 0, 2107, 2098, 1, 0, 0, 0, 2107, 2101, 1, 0, 0, 0, 2108, 349, 1, 0, 0, 0, 2109, 2113, 3, 354, 177, 0, 2110, 2113, 5, 174, 0, 0, 2111, 2113, 3, 348, 174, 0, 2112, 2109, 1, 0, 0, 0, 2112, 2110, 1, 0, 0, 0, 2112, 2111, 1, 0, 0, 0, 2113, 2122, 1, 0, 0, 0, 2114, 2118, 3, 618, 309, 0, 2115, 2119, 3, 354, 177, 0, 2116, 2119, 5, 174, 0, 0, 2117, 2119, 3, 348, 174, 0, 2118, 2115, 1, 0, 0, 0, 2118, 2116, 1, 0, 0, 0, 2118, 2117, 1, 0, 0, 0, 2119, 2121, 1, 0, 0, 0, 2120, 2114, 1, 0, 0, 0, 2121, 2124, 1, 0, 0, 0, 2122, 2120, 1, 0, 0, 0, 2122, 2123, 1, 0, 0, 0, 2123, 351, 1, 0, 0, 0, 2124, 2122, 1, 0, 0, 0, 2125, 2133, 3, 338, 169, 0, 2126, 2133, 3, 354, 177, 0, 2127, 2133, 3, 348, 174, 0, 2128, 2133, 3, 258, 129, 0, 2129, 2133, 3, 256, 128, 0, 2130, 2133, 3, 260, 130, 0, 2131, 2133, 3, 264, 132, 0, 2132, 2125, 1, 0, 0, 0, 2132, 2126, 1, 0, 0, 0, 2132, 2127, 1, 0, 0, 0, 2132, 2128, 1, 0, 0, 0, 2132, 2129, 1, 0, 0, 0, 2132, 2130, 1, 0, 0, 0, 2132, 2131, 1, 0, 0, 0, 2133, 353, 1, 0, 0, 0, 2134, 2144, 3, 338, 169, 0, 2135, 2144, 3, 524, 262, 0, 2136, 2144, 5, 175, 0, 0, 2137, 2144, 3, 360, 180, 0, 2138, 2144, 3, 356, 178, 0, 2139, 2144, 3, 358, 179, 0, 2140, 2144, 3, 364, 182, 0, 2141, 2144, 3, 362, 181, 0, 2142, 2144, 3, 58, 29, 0, 2143, 2134, 1, 0, 0, 0, 2143, 2135, 1, 0, 0, 0, 2143, 2136, 1, 0, 0, 0, 2143, 2137, 1, 0, 0, 0, 2143, 2138, 1, 0, 0, 0, 2143, 2139, 1, 0, 0, 0, 2143, 2140, 1, 0, 0, 0, 2143, 2141, 1, 0, 0, 0, 2143, 2142, 1, 0, 0, 0, 2144, 355, 1, 0, 0, 0, 2145, 2146, 5, 170, 0, 0, 2146, 357, 1, 0, 0, 0, 2147, 2148, 7, 4, 0, 0, 2148, 359, 1, 0, 0, 0, 2149, 2150, 5, 169, 0, 0, 2150, 361, 1, 0, 0, 0, 2151, 2152, 7, 5, 0, 0, 2152, 363, 1, 0, 0, 0, 2153, 2154, 5, 172, 0, 0, 2154, 365, 1, 0, 0, 0, 2155, 2160, 5, 174, 0, 0, 2156, 2157, 5, 17, 0, 0, 2157, 2158, 5, 174, 0, 0, 2158, 2160, 5, 17, 0, 0, 2159, 2155, 1, 0, 0, 0, 2159, 2156, 1, 0, 0, 0, 2160, 367, 1, 0, 0, 0, 2161, 2169, 5, 174, 0, 0, 2162, 2169, 5, 79, 0, 0, 2163, 2169, 5, 125, 0, 0, 2164, 2169, 5, 63, 0, 0, 2165, 2166, 5, 17, 0, 0, 2166, 2167, 5, 174, 0, 0, 2167, 2169, 5, 17, 0, 0, 2168, 2161, 1, 0, 0, 0, 2168, 2162, 1, 0, 0, 0, 2168, 2163, 1, 0, 0, 0, 2168, 2164, 1, 0, 0, 0, 2168, 2165, 1, 0, 0, 0, 2169, 369, 1, 0, 0, 0, 2170, 2177, 5, 174, 0, 0, 2171, 2177, 3, 578, 289, 0, 2172, 2177, 5, 76, 0, 0, 2173, 2174, 5, 17, 0, 0, 2174, 2175, 5, 174, 0, 0, 2175, 2177, 5, 17, 0, 0, 2176, 2170, 1, 0, 0, 0, 2176, 2171, 1, 0, 0, 0, 2176, 2172, 1, 0, 0, 0, 2176, 2173, 1, 0, 0, 0, 2177, 371, 1, 0, 0, 0, 2178, 2180, 3, 374, 187, 0, 2179, 2181, 3, 376, 188, 0, 2180, 2179, 1, 0, 0, 0, 2180, 2181, 1, 0, 0, 0, 2181, 373, 1, 0, 0, 0, 2182, 2183, 7, 6, 0, 0, 2183, 375, 1, 0, 0, 0, 2184, 2185, 3, 610, 305, 0, 2185, 2191, 3, 372, 186, 0, 2186, 2187, 3, 618, 309, 0, 2187, 2188, 3, 372, 186, 0, 2188, 2190, 1, 0, 0, 0, 2189, 2186, 1, 0, 0, 0, 2190, 2193, 1, 0, 0, 0, 2191, 2189, 1, 0, 0, 0, 2191, 2192, 1, 0, 0, 0, 2192, 2194, 1, 0, 0, 0, 2193, 2191, 1, 0, 0, 0, 2194, 2195, 3, 612, 306, 0, 2195, 377, 1, 0, 0, 0, 2196, 2199, 3, 424, 212, 0, 2197, 2199, 3, 448, 224, 0, 2198, 2196, 1, 0, 0, 0, 2198, 2197, 1, 0, 0, 0, 2199, 379, 1, 0, 0, 0, 2200, 2201, 5, 174, 0, 0, 2201, 381, 1, 0, 0, 0, 2202, 2203, 5, 174, 0, 0, 2203, 383, 1, 0, 0, 0, 2204, 2205, 3, 360, 180, 0, 2205, 385, 1, 0, 0, 0, 2206, 2207, 5, 174, 0, 0, 2207, 387, 1, 0, 0, 0, 2208, 2209, 5, 174, 0, 0, 2209, 389, 1, 0, 0, 0, 2210, 2211, 5, 174, 0, 0, 2211, 391, 1, 0, 0, 0, 2212, 2213, 5, 174, 0, 0, 2213, 393, 1, 0, 0, 0, 2214, 2215, 5, 174, 0, 0, 2215, 395, 1, 0, 0, 0, 2216, 2217, 5, 174, 0, 0, 2217, 397, 1, 0, 0, 0, 2218, 2219, 3, 360, 180, 0, 2219, 399, 1, 0, 0, 0, 2220, 2221, 5, 174, 0, 0, 2221, 401, 1, 0, 0, 0, 2222, 2223, 3, 404, 202, 0, 2223, 2224, 3, 372, 186, 0, 2224, 403, 1, 0, 0, 0, 2225, 2226, 7, 7, 0, 0, 2226, 405, 1, 0, 0, 0, 2227, 2228, 5, 24, 0, 0, 2228, 407, 1, 0, 0, 0, 2229, 2230, 5, 25, 0, 0, 2230, 409, 1, 0, 0, 0, 2231, 2232, 5, 26, 0, 0, 2232, 411, 1, 0, 0, 0, 2233, 2234, 5, 26, 0, 0, 2234, 2235, 5, 106, 0, 0, 2235, 413, 1, 0, 0, 0, 2236, 2237, 5, 27, 0, 0, 2237, 415, 1, 0, 0, 0, 2238, 2239, 5, 28, 0, 0, 2239, 417, 1, 0, 0, 0, 2240, 2241, 5, 29, 0, 0, 2241, 419, 1, 0, 0, 0, 2242, 2243, 5, 31, 0, 0, 2243, 421, 1, 0, 0, 0, 2244, 2245, 5, 32, 0, 0, 2245, 423, 1, 0, 0, 0, 2246, 2247, 5, 33, 0, 0, 2247, 425, 1, 0, 0, 0, 2248, 2249, 5, 34, 0, 0, 2249, 427, 1, 0, 0, 0, 2250, 2251, 5, 35, 0, 0, 2251, 429, 1, 0, 0, 0, 2252, 2253, 5, 37, 0, 0, 2253, 431, 1, 0, 0, 0, 2254, 2255, 5, 36, 0, 0, 2255, 433, 1, 0, 0, 0, 2256, 2257, 5, 38, 0, 0, 2257, 435, 1, 0, 0, 0, 2258, 2259, 5, 39, 0, 0, 2259, 437, 1, 0, 0, 0, 2260, 2261, 5, 40, 0, 0, 2261, 439, 1, 0, 0, 0, 2262, 2263, 5, 42, 0, 0, 2263, 441, 1, 0, 0, 0, 2264, 2265, 5, 44, 0, 0, 2265, 443, 1, 0, 0, 0, 2266, 2267, 5, 45, 0, 0, 2267, 445, 1, 0, 0, 0, 2268, 2269, 5, 47, 0, 0, 2269, 447, 1, 0, 0, 0, 2270, 2271, 5, 48, 0, 0, 2271, 449, 1, 0, 0, 0, 2272, 2273, 5, 49, 0, 0, 2273, 451, 1, 0, 0, 0, 2274, 2275, 5, 50, 0, 0, 2275, 453, 1, 0, 0, 0, 2276, 2277, 5, 51, 0, 0, 2277, 455, 1, 0, 0, 0, 2278, 2279, 5, 52, 0, 0, 2279, 457, 1, 0, 0, 0, 2280, 2281, 5, 54, 0, 0, 2281, 459, 1, 0, 0, 0, 2282, 2283, 5, 55, 0, 0, 2283, 461, 1, 0, 0, 0, 2284, 2285, 5, 56, 0, 0, 2285, 463, 1, 0, 0, 0, 2286, 2287, 5, 58, 0, 0, 2287, 465, 1, 0, 0, 0, 2288, 2289, 5, 59, 0, 0, 2289, 467, 1, 0, 0, 0, 2290, 2291, 5, 60, 0, 0, 2291, 469, 1, 0, 0, 0, 2292, 2293, 5, 61, 0, 0, 2293, 471, 1, 0, 0, 0, 2294, 2295, 5, 62, 0, 0, 2295, 473, 1, 0, 0, 0, 2296, 2297, 5, 63, 0, 0, 2297, 475, 1, 0, 0, 0, 2298, 2299, 5, 64, 0, 0, 2299, 477, 1, 0, 0, 0, 2300, 2301, 5, 66, 0, 0, 2301, 479, 1, 0, 0, 0, 2302, 2303, 5, 67, 0, 0, 2303, 481, 1, 0, 0, 0, 2304, 2305, 5, 68, 0, 0, 2305, 483, 1, 0, 0, 0, 2306, 2307, 5, 70, 0, 0, 2307, 485, 1, 0, 0, 0, 2308, 2309, 5, 71, 0, 0, 2309, 487, 1, 0, 0, 0, 2310, 2311, 5, 72, 0, 0, 2311, 489, 1, 0, 0, 0, 2312, 2313, 5, 73, 0, 0, 2313, 491, 1, 0, 0, 0, 2314, 2315, 5, 74, 0, 0, 2315, 493, 1, 0, 0, 0, 2316, 2317, 5, 75, 0, 0, 2317, 495, 1, 0, 0, 0, 2318, 2319, 5, 76, 0, 0, 2319, 497, 1, 0, 0, 0, 2320, 2321, 5, 77, 0, 0, 2321, 499, 1, 0, 0, 0, 2322, 2323, 5, 78, 0, 0, 2323, 501, 1, 0, 0, 0, 2324, 2325, 5, 79, 0, 0, 2325, 503, 1, 0, 0, 0, 2326, 2327, 5, 80, 0, 0, 2327, 505, 1, 0, 0, 0, 2328, 2329, 5, 82, 0, 0, 2329, 507, 1, 0, 0, 0, 2330, 2331, 5, 84, 0, 0, 2331, 509, 1, 0, 0, 0, 2332, 2333, 5, 87, 0, 0, 2333, 511, 1, 0, 0, 0, 2334, 2335, 5, 88, 0, 0, 2335, 513, 1, 0, 0, 0, 2336, 2337, 5, 89, 0, 0, 2337, 515, 1, 0, 0, 0, 2338, 2339, 5, 90, 0, 0, 2339, 517, 1, 0, 0, 0, 2340, 2341, 5, 93, 0, 0, 2341, 519, 1, 0, 0, 0, 2342, 2343, 5, 92, 0, 0, 2343, 521, 1, 0, 0, 0, 2344, 2345, 5, 94, 0, 0, 2345, 523, 1, 0, 0, 0, 2346, 2347, 5, 95, 0, 0, 2347, 525, 1, 0, 0, 0, 2348, 2349, 5, 96, 0, 0, 2349, 527, 1, 0, 0, 0, 2350, 2351, 5, 97, 0, 0, 2351, 529, 1, 0, 0, 0, 2352, 2353, 5, 99, 0, 0, 2353, 531, 1, 0, 0, 0, 2354, 2355, 5, 100, 0, 0, 2355, 533, 1, 0, 0, 0, 2356, 2357, 5, 101, 0, 0, 2357, 535, 1, 0, 0, 0, 2358, 2359, 5, 103, 0, 0, 2359, 537, 1, 0, 0, 0, 2360, 2361, 5, 107, 0, 0, 2361, 539, 1, 0, 0, 0, 2362, 2363, 5, 109, 0, 0, 2363, 541, 1, 0, 0, 0, 2364, 2365, 5, 110, 0, 0, 2365, 543, 1, 0, 0, 0, 2366, 2367, 5, 111, 0, 0, 2367, 545, 1, 0, 0, 0, 2368, 2369, 5, 112, 0, 0, 2369, 547, 1, 0, 0, 0, 2370, 2371, 5, 114, 0, 0, 2371, 549, 1, 0, 0, 0, 2372, 2373, 5, 115, 0, 0, 2373, 551, 1, 0, 0, 0, 2374, 2375, 5, 117, 0, 0, 2375, 553, 1, 0, 0, 0, 2376, 2377, 5, 118, 0, 0, 2377, 555, 1, 0, 0, 0, 2378, 2379, 5, 119, 0, 0, 2379, 557, 1, 0, 0, 0, 2380, 2381, 5, 121, 0, 0, 2381, 559, 1, 0, 0, 0, 2382, 2383, 5, 122, 0, 0, 2383, 561, 1, 0, 0, 0, 2384, 2385, 5, 123, 0, 0, 2385, 563, 1, 0, 0, 0, 2386, 2387, 5, 124, 0, 0, 2387, 565, 1, 0, 0, 0, 2388, 2389, 5, 125, 0, 0, 2389, 567, 1, 0, 0, 0, 2390, 2391, 5, 127, 0, 0, 2391, 569, 1, 0, 0, 0, 2392, 2393, 5, 128, 0, 0, 2393, 571, 1, 0, 0, 0, 2394, 2395, 5, 130, 0, 0, 2395, 573, 1, 0, 0, 0, 2396, 2397, 5, 132, 0, 0, 2397, 575, 1, 0, 0, 0, 2398, 2399, 5, 133, 0, 0, 2399, 577, 1, 0, 0, 0, 2400, 2401, 5, 135, 0, 0, 2401, 579, 1, 0, 0, 0, 2402, 2403, 5, 136, 0, 0, 2403, 581, 1, 0, 0, 0, 2404, 2405, 5, 137, 0, 0, 2405, 583, 1, 0, 0, 0, 2406, 2407, 5, 138, 0, 0, 2407, 585, 1, 0, 0, 0, 2408, 2409, 5, 139, 0, 0, 2409, 587, 1, 0, 0, 0, 2410, 2411, 5, 140, 0, 0, 2411, 589, 1, 0, 0, 0, 2412, 2413, 5, 142, 0, 0, 2413, 591, 1, 0, 0, 0, 2414, 2415, 5, 143, 0, 0, 2415, 593, 1, 0, 0, 0, 2416, 2417, 5, 144, 0, 0, 2417, 595, 1, 0, 0, 0, 2418, 2419, 5, 145, 0, 0, 2419, 597, 1, 0, 0, 0, 2420, 2421, 5, 113, 0, 0, 2421, 599, 1, 0, 0, 0, 2422, 2423, 5, 65, 0, 0, 2423, 601, 1, 0, 0, 0, 2424, 2425, 5, 1, 0, 0, 2425, 603, 1, 0, 0, 0, 2426, 2427, 5, 2, 0, 0, 2427, 605, 1, 0, 0, 0, 2428, 2429, 5, 3, 0, 0, 2429, 607, 1, 0, 0, 0, 2430, 2431, 5, 4, 0, 0, 2431, 609, 1, 0, 0, 0, 2432, 2433, 5, 20, 0, 0, 2433, 611, 1, 0, 0, 0, 2434, 2435, 5, 21, 0, 0, 2435, 613, 1, 0, 0, 0, 2436, 2437, 5, 5, 0, 0, 2437, 615, 1, 0, 0, 0, 2438, 2439, 5, 6, 0, 0, 2439, 617, 1, 0, 0, 0, 2440, 2441, 5, 7, 0, 0, 2441, 619, 1, 0, 0, 0, 2442, 2443, 5, 9, 0, 0, 2443, 621, 1, 0, 0, 0, 2444, 2445, 3, 600, 300, 0, 2445, 2446, 3, 434, 217, 0, 2446, 2452, 3, 624, 312, 0, 2447, 2448, 3, 618, 309, 0, 2448, 2449, 3, 624, 312, 0, 2449, 2451, 1, 0, 0, 0, 2450, 2447, 1, 0, 0, 0, 2451, 2454, 1, 0, 0, 0, 2452, 2450, 1, 0, 0, 0, 2452, 2453, 1, 0, 0, 0, 2453, 623, 1, 0, 0, 0, 2454, 2452, 1, 0, 0, 0, 2455, 2456, 5, 174, 0, 0, 2456, 625, 1, 0, 0, 0, 183, 629, 632, 638, 643, 645, 650, 653, 656, 700, 704, 712, 719, 724, 740, 743, 750, 755, 766, 776, 791, 802, 811, 816, 824, 829, 833, 838, 843, 858, 864, 869, 879, 884, 901, 908, 916, 930, 935, 947, 951, 955, 960, 965, 984, 991, 999, 1003, 1008, 1027, 1036, 1051, 1053, 1065, 1079, 1086, 1093, 1101, 1112, 1128, 1147, 1170, 1182, 1198, 1208, 1217, 1236, 1244, 1250, 1255, 1262, 1267, 1275, 1280, 1287, 1292, 1299, 1304, 1311, 1320, 1327, 1334, 1341, 1346, 1353, 1360, 1364, 1367, 1375, 1385, 1396, 1402, 1411, 1424, 1432, 1438, 1443, 1457, 1477, 1486, 1498, 1502, 1506, 1520, 1528, 1537, 1548, 1555, 1558, 1568, 1574, 1592, 1596, 1600, 1605, 1608, 1616, 1621, 1625, 1627, 1630, 1635, 1642, 1645, 1656, 1669, 1676, 1710, 1713, 1729, 1741, 1744, 1757, 1763, 1769, 1773, 1776, 1779, 1797, 1802, 1825, 1837, 1846, 1855, 1859, 1862, 1867, 1870, 1873, 1876, 1879, 1882, 1890, 1897, 1912, 1918, 1927, 1934, 1939, 1943, 1947, 1949, 1969, 2001, 2013, 2025, 2036, 2039, 2072, 2095, 2104, 2107, 2112, 2118, 2122, 2132, 2143, 2159, 2168, 2176, 2180, 2191, 2198, 2452] \ No newline at end of file +[4, 1, 181, 2462, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117, 7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121, 2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126, 7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130, 2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135, 7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 2, 138, 7, 138, 2, 139, 7, 139, 2, 140, 7, 140, 2, 141, 7, 141, 2, 142, 7, 142, 2, 143, 7, 143, 2, 144, 7, 144, 2, 145, 7, 145, 2, 146, 7, 146, 2, 147, 7, 147, 2, 148, 7, 148, 2, 149, 7, 149, 2, 150, 7, 150, 2, 151, 7, 151, 2, 152, 7, 152, 2, 153, 7, 153, 2, 154, 7, 154, 2, 155, 7, 155, 2, 156, 7, 156, 2, 157, 7, 157, 2, 158, 7, 158, 2, 159, 7, 159, 2, 160, 7, 160, 2, 161, 7, 161, 2, 162, 7, 162, 2, 163, 7, 163, 2, 164, 7, 164, 2, 165, 7, 165, 2, 166, 7, 166, 2, 167, 7, 167, 2, 168, 7, 168, 2, 169, 7, 169, 2, 170, 7, 170, 2, 171, 7, 171, 2, 172, 7, 172, 2, 173, 7, 173, 2, 174, 7, 174, 2, 175, 7, 175, 2, 176, 7, 176, 2, 177, 7, 177, 2, 178, 7, 178, 2, 179, 7, 179, 2, 180, 7, 180, 2, 181, 7, 181, 2, 182, 7, 182, 2, 183, 7, 183, 2, 184, 7, 184, 2, 185, 7, 185, 2, 186, 7, 186, 2, 187, 7, 187, 2, 188, 7, 188, 2, 189, 7, 189, 2, 190, 7, 190, 2, 191, 7, 191, 2, 192, 7, 192, 2, 193, 7, 193, 2, 194, 7, 194, 2, 195, 7, 195, 2, 196, 7, 196, 2, 197, 7, 197, 2, 198, 7, 198, 2, 199, 7, 199, 2, 200, 7, 200, 2, 201, 7, 201, 2, 202, 7, 202, 2, 203, 7, 203, 2, 204, 7, 204, 2, 205, 7, 205, 2, 206, 7, 206, 2, 207, 7, 207, 2, 208, 7, 208, 2, 209, 7, 209, 2, 210, 7, 210, 2, 211, 7, 211, 2, 212, 7, 212, 2, 213, 7, 213, 2, 214, 7, 214, 2, 215, 7, 215, 2, 216, 7, 216, 2, 217, 7, 217, 2, 218, 7, 218, 2, 219, 7, 219, 2, 220, 7, 220, 2, 221, 7, 221, 2, 222, 7, 222, 2, 223, 7, 223, 2, 224, 7, 224, 2, 225, 7, 225, 2, 226, 7, 226, 2, 227, 7, 227, 2, 228, 7, 228, 2, 229, 7, 229, 2, 230, 7, 230, 2, 231, 7, 231, 2, 232, 7, 232, 2, 233, 7, 233, 2, 234, 7, 234, 2, 235, 7, 235, 2, 236, 7, 236, 2, 237, 7, 237, 2, 238, 7, 238, 2, 239, 7, 239, 2, 240, 7, 240, 2, 241, 7, 241, 2, 242, 7, 242, 2, 243, 7, 243, 2, 244, 7, 244, 2, 245, 7, 245, 2, 246, 7, 246, 2, 247, 7, 247, 2, 248, 7, 248, 2, 249, 7, 249, 2, 250, 7, 250, 2, 251, 7, 251, 2, 252, 7, 252, 2, 253, 7, 253, 2, 254, 7, 254, 2, 255, 7, 255, 2, 256, 7, 256, 2, 257, 7, 257, 2, 258, 7, 258, 2, 259, 7, 259, 2, 260, 7, 260, 2, 261, 7, 261, 2, 262, 7, 262, 2, 263, 7, 263, 2, 264, 7, 264, 2, 265, 7, 265, 2, 266, 7, 266, 2, 267, 7, 267, 2, 268, 7, 268, 2, 269, 7, 269, 2, 270, 7, 270, 2, 271, 7, 271, 2, 272, 7, 272, 2, 273, 7, 273, 2, 274, 7, 274, 2, 275, 7, 275, 2, 276, 7, 276, 2, 277, 7, 277, 2, 278, 7, 278, 2, 279, 7, 279, 2, 280, 7, 280, 2, 281, 7, 281, 2, 282, 7, 282, 2, 283, 7, 283, 2, 284, 7, 284, 2, 285, 7, 285, 2, 286, 7, 286, 2, 287, 7, 287, 2, 288, 7, 288, 2, 289, 7, 289, 2, 290, 7, 290, 2, 291, 7, 291, 2, 292, 7, 292, 2, 293, 7, 293, 2, 294, 7, 294, 2, 295, 7, 295, 2, 296, 7, 296, 2, 297, 7, 297, 2, 298, 7, 298, 2, 299, 7, 299, 2, 300, 7, 300, 2, 301, 7, 301, 2, 302, 7, 302, 2, 303, 7, 303, 2, 304, 7, 304, 2, 305, 7, 305, 2, 306, 7, 306, 2, 307, 7, 307, 2, 308, 7, 308, 2, 309, 7, 309, 2, 310, 7, 310, 2, 311, 7, 311, 2, 312, 7, 312, 2, 313, 7, 313, 2, 314, 7, 314, 2, 315, 7, 315, 2, 316, 7, 316, 1, 0, 4, 0, 636, 8, 0, 11, 0, 12, 0, 637, 1, 0, 3, 0, 641, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 647, 8, 1, 1, 1, 1, 1, 1, 1, 5, 1, 652, 8, 1, 10, 1, 12, 1, 655, 9, 1, 1, 1, 1, 1, 3, 1, 659, 8, 1, 1, 1, 3, 1, 662, 8, 1, 1, 1, 3, 1, 665, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 3, 4, 709, 8, 4, 1, 5, 1, 5, 3, 5, 713, 8, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 721, 8, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 3, 9, 728, 8, 9, 1, 9, 1, 9, 1, 10, 3, 10, 733, 8, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 749, 8, 12, 1, 12, 3, 12, 752, 8, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 3, 13, 759, 8, 13, 1, 13, 1, 13, 1, 13, 3, 13, 764, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 3, 15, 775, 8, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 785, 8, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 800, 8, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 811, 8, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 820, 8, 16, 1, 17, 1, 17, 1, 17, 3, 17, 825, 8, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 3, 17, 833, 8, 17, 1, 18, 1, 18, 1, 18, 3, 18, 838, 8, 18, 1, 18, 1, 18, 3, 18, 842, 8, 18, 1, 19, 1, 19, 1, 19, 3, 19, 847, 8, 19, 1, 19, 1, 19, 1, 19, 3, 19, 852, 8, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 5, 20, 865, 8, 20, 10, 20, 12, 20, 868, 9, 20, 1, 21, 1, 21, 1, 21, 3, 21, 873, 8, 21, 1, 21, 1, 21, 1, 21, 3, 21, 878, 8, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 888, 8, 22, 1, 22, 1, 22, 1, 22, 3, 22, 893, 8, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 910, 8, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 917, 8, 23, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 923, 8, 24, 10, 24, 12, 24, 926, 9, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 3, 26, 939, 8, 26, 1, 27, 1, 27, 1, 27, 3, 27, 944, 8, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 3, 27, 956, 8, 27, 1, 28, 1, 28, 3, 28, 960, 8, 28, 1, 28, 1, 28, 3, 28, 964, 8, 28, 1, 28, 1, 28, 1, 28, 3, 28, 969, 8, 28, 1, 28, 1, 28, 1, 28, 3, 28, 974, 8, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 5, 30, 991, 8, 30, 10, 30, 12, 30, 994, 9, 30, 1, 31, 1, 31, 1, 31, 1, 31, 3, 31, 1000, 8, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 3, 32, 1008, 8, 32, 1, 32, 1, 32, 3, 32, 1012, 8, 32, 1, 32, 1, 32, 1, 32, 3, 32, 1017, 8, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 3, 33, 1036, 8, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 1043, 8, 34, 10, 34, 12, 34, 1046, 9, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 5, 36, 1060, 8, 36, 10, 36, 12, 36, 1063, 9, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 5, 37, 1072, 8, 37, 10, 37, 12, 37, 1075, 9, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 1088, 8, 39, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 3, 41, 1095, 8, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 3, 42, 1102, 8, 42, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 3, 43, 1110, 8, 43, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 5, 45, 1119, 8, 45, 10, 45, 12, 45, 1122, 9, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 5, 47, 1135, 8, 47, 10, 47, 12, 47, 1138, 9, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 3, 50, 1156, 8, 50, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 5, 55, 1177, 8, 55, 10, 55, 12, 55, 1180, 9, 55, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 5, 57, 1189, 8, 57, 10, 57, 12, 57, 1192, 9, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 5, 60, 1205, 8, 60, 10, 60, 12, 60, 1208, 9, 60, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 3, 62, 1217, 8, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 5, 63, 1224, 8, 63, 10, 63, 12, 63, 1227, 9, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 3, 64, 1245, 8, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 1253, 8, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 1259, 8, 65, 1, 66, 1, 66, 1, 66, 3, 66, 1264, 8, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 3, 67, 1271, 8, 67, 1, 67, 1, 67, 1, 67, 3, 67, 1276, 8, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 3, 68, 1284, 8, 68, 1, 68, 1, 68, 1, 68, 3, 68, 1289, 8, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 3, 69, 1296, 8, 69, 1, 69, 1, 69, 1, 69, 3, 69, 1301, 8, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 3, 70, 1308, 8, 70, 1, 70, 1, 70, 1, 70, 3, 70, 1313, 8, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 3, 71, 1320, 8, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 3, 72, 1329, 8, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 3, 73, 1336, 8, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 3, 74, 1343, 8, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 3, 75, 1350, 8, 75, 1, 75, 1, 75, 1, 75, 3, 75, 1355, 8, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 3, 76, 1362, 8, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 3, 76, 1369, 8, 76, 1, 77, 1, 77, 3, 77, 1373, 8, 77, 1, 77, 3, 77, 1376, 8, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 3, 78, 1384, 8, 78, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 79, 5, 79, 1392, 8, 79, 10, 79, 12, 79, 1395, 9, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 3, 80, 1405, 8, 80, 1, 81, 1, 81, 1, 82, 1, 82, 3, 82, 1411, 8, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 5, 83, 1418, 8, 83, 10, 83, 12, 83, 1421, 9, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 86, 1, 86, 3, 86, 1433, 8, 86, 1, 87, 1, 87, 1, 87, 1, 87, 5, 87, 1439, 8, 87, 10, 87, 12, 87, 1442, 9, 87, 1, 87, 1, 87, 1, 87, 3, 87, 1447, 8, 87, 1, 88, 1, 88, 1, 88, 3, 88, 1452, 8, 88, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 91, 1, 91, 1, 91, 3, 91, 1466, 8, 91, 1, 92, 1, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 95, 1, 95, 1, 95, 1, 95, 5, 95, 1484, 8, 95, 10, 95, 12, 95, 1487, 9, 95, 1, 96, 1, 96, 1, 96, 1, 96, 5, 96, 1493, 8, 96, 10, 96, 12, 96, 1496, 9, 96, 1, 97, 1, 97, 1, 98, 1, 98, 1, 99, 1, 99, 1, 99, 1, 100, 1, 100, 3, 100, 1507, 8, 100, 1, 100, 1, 100, 3, 100, 1511, 8, 100, 1, 101, 1, 101, 3, 101, 1515, 8, 101, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 3, 102, 1529, 8, 102, 1, 103, 1, 103, 1, 103, 1, 103, 5, 103, 1535, 8, 103, 10, 103, 12, 103, 1538, 9, 103, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 3, 104, 1546, 8, 104, 1, 105, 1, 105, 1, 105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 3, 107, 1557, 8, 107, 1, 107, 1, 107, 1, 108, 1, 108, 1, 108, 3, 108, 1564, 8, 108, 1, 108, 3, 108, 1567, 8, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 109, 1, 109, 3, 109, 1577, 8, 109, 1, 110, 1, 110, 1, 110, 1, 110, 3, 110, 1583, 8, 110, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 114, 3, 114, 1601, 8, 114, 1, 114, 1, 114, 3, 114, 1605, 8, 114, 1, 114, 1, 114, 3, 114, 1609, 8, 114, 1, 114, 1, 114, 1, 114, 3, 114, 1614, 8, 114, 1, 114, 3, 114, 1617, 8, 114, 1, 115, 1, 115, 1, 115, 1, 115, 5, 115, 1623, 8, 115, 10, 115, 12, 115, 1626, 9, 115, 1, 116, 1, 116, 3, 116, 1630, 8, 116, 1, 116, 1, 116, 3, 116, 1634, 8, 116, 3, 116, 1636, 8, 116, 1, 117, 3, 117, 1639, 8, 117, 1, 117, 1, 117, 1, 117, 3, 117, 1644, 8, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 3, 117, 1651, 8, 117, 1, 117, 3, 117, 1654, 8, 117, 1, 118, 1, 118, 1, 118, 1, 119, 1, 119, 1, 119, 1, 119, 5, 119, 1663, 8, 119, 10, 119, 12, 119, 1666, 9, 119, 1, 120, 1, 120, 1, 120, 1, 120, 1, 121, 1, 121, 1, 121, 1, 121, 5, 121, 1676, 8, 121, 10, 121, 12, 121, 1679, 9, 121, 1, 122, 1, 122, 1, 122, 1, 122, 3, 122, 1685, 8, 122, 1, 123, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 126, 1, 126, 1, 126, 1, 126, 1, 127, 1, 127, 1, 127, 1, 127, 1, 127, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 5, 128, 1717, 8, 128, 10, 128, 12, 128, 1720, 9, 128, 3, 128, 1722, 8, 128, 1, 128, 1, 128, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 5, 129, 1736, 8, 129, 10, 129, 12, 129, 1739, 9, 129, 1, 129, 1, 129, 1, 130, 1, 130, 1, 130, 1, 130, 1, 130, 5, 130, 1748, 8, 130, 10, 130, 12, 130, 1751, 9, 130, 3, 130, 1753, 8, 130, 1, 130, 1, 130, 1, 131, 1, 131, 1, 132, 1, 132, 1, 132, 1, 132, 1, 132, 5, 132, 1764, 8, 132, 10, 132, 12, 132, 1767, 9, 132, 1, 132, 1, 132, 1, 133, 3, 133, 1772, 8, 133, 1, 133, 1, 133, 1, 133, 1, 133, 3, 133, 1778, 8, 133, 1, 133, 1, 133, 3, 133, 1782, 8, 133, 1, 133, 3, 133, 1785, 8, 133, 1, 133, 3, 133, 1788, 8, 133, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 3, 134, 1806, 8, 134, 1, 135, 1, 135, 1, 135, 3, 135, 1811, 8, 135, 1, 136, 1, 136, 1, 136, 1, 137, 1, 137, 1, 137, 1, 138, 1, 138, 1, 138, 1, 138, 1, 139, 1, 139, 1, 139, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 3, 140, 1834, 8, 140, 1, 141, 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1, 142, 1, 142, 5, 142, 1844, 8, 142, 10, 142, 12, 142, 1847, 9, 142, 1, 143, 1, 143, 1, 143, 1, 143, 5, 143, 1853, 8, 143, 10, 143, 12, 143, 1856, 9, 143, 1, 144, 1, 144, 1, 144, 1, 144, 1, 144, 1, 144, 3, 144, 1864, 8, 144, 1, 145, 1, 145, 3, 145, 1868, 8, 145, 1, 145, 3, 145, 1871, 8, 145, 1, 145, 1, 145, 1, 145, 3, 145, 1876, 8, 145, 1, 145, 3, 145, 1879, 8, 145, 1, 145, 3, 145, 1882, 8, 145, 1, 145, 3, 145, 1885, 8, 145, 1, 145, 3, 145, 1888, 8, 145, 1, 145, 3, 145, 1891, 8, 145, 1, 146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 3, 147, 1899, 8, 147, 1, 148, 1, 148, 1, 149, 1, 149, 1, 149, 3, 149, 1906, 8, 149, 1, 149, 1, 149, 1, 150, 1, 150, 1, 150, 1, 151, 1, 151, 1, 151, 1, 151, 1, 151, 1, 151, 5, 151, 1919, 8, 151, 10, 151, 12, 151, 1922, 9, 151, 1, 152, 1, 152, 1, 152, 3, 152, 1927, 8, 152, 1, 153, 1, 153, 1, 153, 1, 154, 1, 154, 1, 155, 1, 155, 3, 155, 1936, 8, 155, 1, 155, 1, 155, 1, 155, 5, 155, 1941, 8, 155, 10, 155, 12, 155, 1944, 9, 155, 1, 156, 1, 156, 3, 156, 1948, 8, 156, 1, 156, 1, 156, 3, 156, 1952, 8, 156, 1, 156, 1, 156, 3, 156, 1956, 8, 156, 3, 156, 1958, 8, 156, 1, 157, 1, 157, 1, 158, 1, 158, 1, 159, 1, 159, 1, 159, 1, 159, 1, 159, 1, 160, 1, 160, 1, 160, 1, 161, 1, 161, 1, 161, 1, 161, 5, 161, 1976, 8, 161, 10, 161, 12, 161, 1979, 9, 161, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 5, 162, 2010, 8, 162, 10, 162, 12, 162, 2013, 9, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 5, 162, 2022, 8, 162, 10, 162, 12, 162, 2025, 9, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 5, 162, 2034, 8, 162, 10, 162, 12, 162, 2037, 9, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 5, 162, 2045, 8, 162, 10, 162, 12, 162, 2048, 9, 162, 3, 162, 2050, 8, 162, 1, 163, 1, 163, 1, 164, 1, 164, 1, 164, 1, 164, 1, 165, 1, 165, 1, 165, 1, 165, 1, 166, 1, 166, 1, 166, 1, 166, 1, 167, 1, 167, 1, 167, 1, 167, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 169, 1, 169, 1, 169, 1, 169, 1, 170, 1, 170, 1, 170, 1, 170, 1, 171, 1, 171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 172, 3, 172, 2091, 8, 172, 1, 173, 1, 173, 1, 173, 1, 173, 1, 174, 1, 174, 1, 174, 1, 174, 1, 175, 1, 175, 1, 175, 1, 175, 1, 175, 1, 175, 1, 176, 1, 176, 1, 176, 3, 176, 2110, 8, 176, 1, 176, 1, 176, 1, 177, 1, 177, 1, 178, 1, 178, 1, 178, 1, 178, 5, 178, 2120, 8, 178, 10, 178, 12, 178, 2123, 9, 178, 1, 179, 1, 179, 1, 179, 3, 179, 2128, 8, 179, 1, 180, 1, 180, 1, 180, 1, 180, 1, 180, 1, 180, 1, 180, 3, 180, 2137, 8, 180, 1, 181, 1, 181, 1, 181, 1, 181, 1, 181, 1, 181, 1, 181, 1, 181, 1, 181, 3, 181, 2148, 8, 181, 1, 182, 1, 182, 1, 183, 1, 183, 1, 184, 1, 184, 1, 185, 1, 185, 1, 186, 1, 186, 1, 187, 1, 187, 1, 187, 1, 187, 3, 187, 2164, 8, 187, 1, 188, 1, 188, 1, 188, 1, 188, 1, 188, 1, 188, 1, 188, 3, 188, 2173, 8, 188, 1, 189, 1, 189, 1, 189, 1, 189, 1, 189, 1, 189, 3, 189, 2181, 8, 189, 1, 190, 1, 190, 3, 190, 2185, 8, 190, 1, 191, 1, 191, 1, 192, 1, 192, 1, 192, 1, 192, 1, 192, 5, 192, 2194, 8, 192, 10, 192, 12, 192, 2197, 9, 192, 1, 192, 1, 192, 1, 193, 1, 193, 3, 193, 2203, 8, 193, 1, 194, 1, 194, 1, 195, 1, 195, 1, 196, 1, 196, 1, 197, 1, 197, 1, 198, 1, 198, 1, 199, 1, 199, 1, 200, 1, 200, 1, 201, 1, 201, 1, 202, 1, 202, 1, 203, 1, 203, 1, 204, 1, 204, 1, 205, 1, 205, 1, 205, 1, 206, 1, 206, 1, 207, 1, 207, 1, 208, 1, 208, 1, 209, 1, 209, 1, 210, 1, 210, 1, 210, 1, 211, 1, 211, 1, 212, 1, 212, 1, 213, 1, 213, 1, 214, 1, 214, 1, 215, 1, 215, 1, 216, 1, 216, 1, 217, 1, 217, 1, 218, 1, 218, 1, 219, 1, 219, 1, 220, 1, 220, 1, 221, 1, 221, 1, 222, 1, 222, 1, 223, 1, 223, 1, 224, 1, 224, 1, 225, 1, 225, 1, 226, 1, 226, 1, 227, 1, 227, 1, 228, 1, 228, 1, 229, 1, 229, 1, 230, 1, 230, 1, 231, 1, 231, 1, 232, 1, 232, 1, 233, 1, 233, 1, 234, 1, 234, 1, 235, 1, 235, 1, 236, 1, 236, 1, 237, 1, 237, 1, 238, 1, 238, 1, 239, 1, 239, 1, 240, 1, 240, 1, 241, 1, 241, 1, 242, 1, 242, 1, 243, 1, 243, 1, 244, 1, 244, 1, 245, 1, 245, 1, 246, 1, 246, 1, 247, 1, 247, 1, 248, 1, 248, 1, 249, 1, 249, 1, 250, 1, 250, 1, 251, 1, 251, 1, 252, 1, 252, 1, 253, 1, 253, 1, 254, 1, 254, 1, 255, 1, 255, 1, 256, 1, 256, 1, 257, 1, 257, 1, 258, 1, 258, 1, 259, 1, 259, 1, 260, 1, 260, 1, 261, 1, 261, 1, 262, 1, 262, 1, 263, 1, 263, 1, 264, 1, 264, 1, 265, 1, 265, 1, 266, 1, 266, 1, 267, 1, 267, 1, 268, 1, 268, 1, 269, 1, 269, 1, 270, 1, 270, 1, 271, 1, 271, 1, 272, 1, 272, 1, 273, 1, 273, 1, 274, 1, 274, 1, 275, 1, 275, 1, 276, 1, 276, 1, 277, 1, 277, 1, 278, 1, 278, 1, 279, 1, 279, 1, 280, 1, 280, 1, 281, 1, 281, 1, 282, 1, 282, 1, 283, 1, 283, 1, 284, 1, 284, 1, 285, 1, 285, 1, 286, 1, 286, 1, 287, 1, 287, 1, 288, 1, 288, 1, 289, 1, 289, 1, 290, 1, 290, 1, 291, 1, 291, 1, 292, 1, 292, 1, 293, 1, 293, 1, 294, 1, 294, 1, 295, 1, 295, 1, 296, 1, 296, 1, 297, 1, 297, 1, 298, 1, 298, 1, 299, 1, 299, 1, 300, 1, 300, 1, 301, 1, 301, 1, 302, 1, 302, 1, 303, 1, 303, 1, 304, 1, 304, 1, 305, 1, 305, 1, 306, 1, 306, 1, 307, 1, 307, 1, 308, 1, 308, 1, 309, 1, 309, 1, 310, 1, 310, 1, 311, 1, 311, 1, 312, 1, 312, 1, 313, 1, 313, 1, 314, 1, 314, 1, 315, 1, 315, 1, 315, 1, 315, 1, 315, 1, 315, 5, 315, 2455, 8, 315, 10, 315, 12, 315, 2458, 9, 315, 1, 316, 1, 316, 1, 316, 0, 0, 317, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 254, 256, 258, 260, 262, 264, 266, 268, 270, 272, 274, 276, 278, 280, 282, 284, 286, 288, 290, 292, 294, 296, 298, 300, 302, 304, 306, 308, 310, 312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 332, 334, 336, 338, 340, 342, 344, 346, 348, 350, 352, 354, 356, 358, 360, 362, 364, 366, 368, 370, 372, 374, 376, 378, 380, 382, 384, 386, 388, 390, 392, 394, 396, 398, 400, 402, 404, 406, 408, 410, 412, 414, 416, 418, 420, 422, 424, 426, 428, 430, 432, 434, 436, 438, 440, 442, 444, 446, 448, 450, 452, 454, 456, 458, 460, 462, 464, 466, 468, 470, 472, 474, 476, 478, 480, 482, 484, 486, 488, 490, 492, 494, 496, 498, 500, 502, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, 532, 534, 536, 538, 540, 542, 544, 546, 548, 550, 552, 554, 556, 558, 560, 562, 564, 566, 568, 570, 572, 574, 576, 578, 580, 582, 584, 586, 588, 590, 592, 594, 596, 598, 600, 602, 604, 606, 608, 610, 612, 614, 616, 618, 620, 622, 624, 626, 628, 630, 632, 0, 9, 1, 0, 168, 169, 2, 0, 14, 14, 16, 16, 1, 0, 19, 23, 1, 0, 176, 177, 3, 0, 141, 141, 146, 146, 174, 174, 1, 0, 170, 171, 2, 0, 57, 57, 131, 131, 6, 0, 84, 84, 118, 118, 127, 127, 141, 141, 147, 167, 174, 174, 2, 0, 71, 71, 174, 174, 2431, 0, 635, 1, 0, 0, 0, 2, 653, 1, 0, 0, 0, 4, 666, 1, 0, 0, 0, 6, 668, 1, 0, 0, 0, 8, 708, 1, 0, 0, 0, 10, 712, 1, 0, 0, 0, 12, 720, 1, 0, 0, 0, 14, 722, 1, 0, 0, 0, 16, 724, 1, 0, 0, 0, 18, 727, 1, 0, 0, 0, 20, 732, 1, 0, 0, 0, 22, 736, 1, 0, 0, 0, 24, 743, 1, 0, 0, 0, 26, 753, 1, 0, 0, 0, 28, 765, 1, 0, 0, 0, 30, 784, 1, 0, 0, 0, 32, 819, 1, 0, 0, 0, 34, 821, 1, 0, 0, 0, 36, 834, 1, 0, 0, 0, 38, 843, 1, 0, 0, 0, 40, 858, 1, 0, 0, 0, 42, 869, 1, 0, 0, 0, 44, 883, 1, 0, 0, 0, 46, 911, 1, 0, 0, 0, 48, 918, 1, 0, 0, 0, 50, 927, 1, 0, 0, 0, 52, 938, 1, 0, 0, 0, 54, 940, 1, 0, 0, 0, 56, 957, 1, 0, 0, 0, 58, 984, 1, 0, 0, 0, 60, 986, 1, 0, 0, 0, 62, 999, 1, 0, 0, 0, 64, 1005, 1, 0, 0, 0, 66, 1035, 1, 0, 0, 0, 68, 1037, 1, 0, 0, 0, 70, 1049, 1, 0, 0, 0, 72, 1053, 1, 0, 0, 0, 74, 1066, 1, 0, 0, 0, 76, 1078, 1, 0, 0, 0, 78, 1081, 1, 0, 0, 0, 80, 1089, 1, 0, 0, 0, 82, 1094, 1, 0, 0, 0, 84, 1096, 1, 0, 0, 0, 86, 1109, 1, 0, 0, 0, 88, 1111, 1, 0, 0, 0, 90, 1114, 1, 0, 0, 0, 92, 1123, 1, 0, 0, 0, 94, 1127, 1, 0, 0, 0, 96, 1139, 1, 0, 0, 0, 98, 1144, 1, 0, 0, 0, 100, 1155, 1, 0, 0, 0, 102, 1157, 1, 0, 0, 0, 104, 1160, 1, 0, 0, 0, 106, 1165, 1, 0, 0, 0, 108, 1169, 1, 0, 0, 0, 110, 1172, 1, 0, 0, 0, 112, 1181, 1, 0, 0, 0, 114, 1184, 1, 0, 0, 0, 116, 1193, 1, 0, 0, 0, 118, 1197, 1, 0, 0, 0, 120, 1200, 1, 0, 0, 0, 122, 1209, 1, 0, 0, 0, 124, 1212, 1, 0, 0, 0, 126, 1218, 1, 0, 0, 0, 128, 1244, 1, 0, 0, 0, 130, 1246, 1, 0, 0, 0, 132, 1260, 1, 0, 0, 0, 134, 1267, 1, 0, 0, 0, 136, 1279, 1, 0, 0, 0, 138, 1292, 1, 0, 0, 0, 140, 1304, 1, 0, 0, 0, 142, 1316, 1, 0, 0, 0, 144, 1325, 1, 0, 0, 0, 146, 1332, 1, 0, 0, 0, 148, 1339, 1, 0, 0, 0, 150, 1346, 1, 0, 0, 0, 152, 1358, 1, 0, 0, 0, 154, 1370, 1, 0, 0, 0, 156, 1377, 1, 0, 0, 0, 158, 1387, 1, 0, 0, 0, 160, 1404, 1, 0, 0, 0, 162, 1406, 1, 0, 0, 0, 164, 1410, 1, 0, 0, 0, 166, 1412, 1, 0, 0, 0, 168, 1424, 1, 0, 0, 0, 170, 1428, 1, 0, 0, 0, 172, 1432, 1, 0, 0, 0, 174, 1434, 1, 0, 0, 0, 176, 1448, 1, 0, 0, 0, 178, 1453, 1, 0, 0, 0, 180, 1456, 1, 0, 0, 0, 182, 1465, 1, 0, 0, 0, 184, 1467, 1, 0, 0, 0, 186, 1469, 1, 0, 0, 0, 188, 1473, 1, 0, 0, 0, 190, 1479, 1, 0, 0, 0, 192, 1488, 1, 0, 0, 0, 194, 1497, 1, 0, 0, 0, 196, 1499, 1, 0, 0, 0, 198, 1501, 1, 0, 0, 0, 200, 1504, 1, 0, 0, 0, 202, 1514, 1, 0, 0, 0, 204, 1516, 1, 0, 0, 0, 206, 1530, 1, 0, 0, 0, 208, 1545, 1, 0, 0, 0, 210, 1547, 1, 0, 0, 0, 212, 1551, 1, 0, 0, 0, 214, 1554, 1, 0, 0, 0, 216, 1560, 1, 0, 0, 0, 218, 1576, 1, 0, 0, 0, 220, 1582, 1, 0, 0, 0, 222, 1584, 1, 0, 0, 0, 224, 1589, 1, 0, 0, 0, 226, 1594, 1, 0, 0, 0, 228, 1600, 1, 0, 0, 0, 230, 1618, 1, 0, 0, 0, 232, 1635, 1, 0, 0, 0, 234, 1638, 1, 0, 0, 0, 236, 1655, 1, 0, 0, 0, 238, 1658, 1, 0, 0, 0, 240, 1667, 1, 0, 0, 0, 242, 1671, 1, 0, 0, 0, 244, 1684, 1, 0, 0, 0, 246, 1686, 1, 0, 0, 0, 248, 1690, 1, 0, 0, 0, 250, 1696, 1, 0, 0, 0, 252, 1702, 1, 0, 0, 0, 254, 1706, 1, 0, 0, 0, 256, 1711, 1, 0, 0, 0, 258, 1725, 1, 0, 0, 0, 260, 1742, 1, 0, 0, 0, 262, 1756, 1, 0, 0, 0, 264, 1758, 1, 0, 0, 0, 266, 1771, 1, 0, 0, 0, 268, 1805, 1, 0, 0, 0, 270, 1807, 1, 0, 0, 0, 272, 1812, 1, 0, 0, 0, 274, 1815, 1, 0, 0, 0, 276, 1818, 1, 0, 0, 0, 278, 1822, 1, 0, 0, 0, 280, 1833, 1, 0, 0, 0, 282, 1835, 1, 0, 0, 0, 284, 1839, 1, 0, 0, 0, 286, 1848, 1, 0, 0, 0, 288, 1863, 1, 0, 0, 0, 290, 1865, 1, 0, 0, 0, 292, 1892, 1, 0, 0, 0, 294, 1895, 1, 0, 0, 0, 296, 1900, 1, 0, 0, 0, 298, 1905, 1, 0, 0, 0, 300, 1909, 1, 0, 0, 0, 302, 1912, 1, 0, 0, 0, 304, 1923, 1, 0, 0, 0, 306, 1928, 1, 0, 0, 0, 308, 1931, 1, 0, 0, 0, 310, 1935, 1, 0, 0, 0, 312, 1957, 1, 0, 0, 0, 314, 1959, 1, 0, 0, 0, 316, 1961, 1, 0, 0, 0, 318, 1963, 1, 0, 0, 0, 320, 1968, 1, 0, 0, 0, 322, 1971, 1, 0, 0, 0, 324, 2049, 1, 0, 0, 0, 326, 2051, 1, 0, 0, 0, 328, 2053, 1, 0, 0, 0, 330, 2057, 1, 0, 0, 0, 332, 2061, 1, 0, 0, 0, 334, 2065, 1, 0, 0, 0, 336, 2069, 1, 0, 0, 0, 338, 2075, 1, 0, 0, 0, 340, 2079, 1, 0, 0, 0, 342, 2083, 1, 0, 0, 0, 344, 2090, 1, 0, 0, 0, 346, 2092, 1, 0, 0, 0, 348, 2096, 1, 0, 0, 0, 350, 2100, 1, 0, 0, 0, 352, 2106, 1, 0, 0, 0, 354, 2113, 1, 0, 0, 0, 356, 2115, 1, 0, 0, 0, 358, 2127, 1, 0, 0, 0, 360, 2136, 1, 0, 0, 0, 362, 2147, 1, 0, 0, 0, 364, 2149, 1, 0, 0, 0, 366, 2151, 1, 0, 0, 0, 368, 2153, 1, 0, 0, 0, 370, 2155, 1, 0, 0, 0, 372, 2157, 1, 0, 0, 0, 374, 2163, 1, 0, 0, 0, 376, 2172, 1, 0, 0, 0, 378, 2180, 1, 0, 0, 0, 380, 2182, 1, 0, 0, 0, 382, 2186, 1, 0, 0, 0, 384, 2188, 1, 0, 0, 0, 386, 2202, 1, 0, 0, 0, 388, 2204, 1, 0, 0, 0, 390, 2206, 1, 0, 0, 0, 392, 2208, 1, 0, 0, 0, 394, 2210, 1, 0, 0, 0, 396, 2212, 1, 0, 0, 0, 398, 2214, 1, 0, 0, 0, 400, 2216, 1, 0, 0, 0, 402, 2218, 1, 0, 0, 0, 404, 2220, 1, 0, 0, 0, 406, 2222, 1, 0, 0, 0, 408, 2224, 1, 0, 0, 0, 410, 2226, 1, 0, 0, 0, 412, 2229, 1, 0, 0, 0, 414, 2231, 1, 0, 0, 0, 416, 2233, 1, 0, 0, 0, 418, 2235, 1, 0, 0, 0, 420, 2237, 1, 0, 0, 0, 422, 2240, 1, 0, 0, 0, 424, 2242, 1, 0, 0, 0, 426, 2244, 1, 0, 0, 0, 428, 2246, 1, 0, 0, 0, 430, 2248, 1, 0, 0, 0, 432, 2250, 1, 0, 0, 0, 434, 2252, 1, 0, 0, 0, 436, 2254, 1, 0, 0, 0, 438, 2256, 1, 0, 0, 0, 440, 2258, 1, 0, 0, 0, 442, 2260, 1, 0, 0, 0, 444, 2262, 1, 0, 0, 0, 446, 2264, 1, 0, 0, 0, 448, 2266, 1, 0, 0, 0, 450, 2268, 1, 0, 0, 0, 452, 2270, 1, 0, 0, 0, 454, 2272, 1, 0, 0, 0, 456, 2274, 1, 0, 0, 0, 458, 2276, 1, 0, 0, 0, 460, 2278, 1, 0, 0, 0, 462, 2280, 1, 0, 0, 0, 464, 2282, 1, 0, 0, 0, 466, 2284, 1, 0, 0, 0, 468, 2286, 1, 0, 0, 0, 470, 2288, 1, 0, 0, 0, 472, 2290, 1, 0, 0, 0, 474, 2292, 1, 0, 0, 0, 476, 2294, 1, 0, 0, 0, 478, 2296, 1, 0, 0, 0, 480, 2298, 1, 0, 0, 0, 482, 2300, 1, 0, 0, 0, 484, 2302, 1, 0, 0, 0, 486, 2304, 1, 0, 0, 0, 488, 2306, 1, 0, 0, 0, 490, 2308, 1, 0, 0, 0, 492, 2310, 1, 0, 0, 0, 494, 2312, 1, 0, 0, 0, 496, 2314, 1, 0, 0, 0, 498, 2316, 1, 0, 0, 0, 500, 2318, 1, 0, 0, 0, 502, 2320, 1, 0, 0, 0, 504, 2322, 1, 0, 0, 0, 506, 2324, 1, 0, 0, 0, 508, 2326, 1, 0, 0, 0, 510, 2328, 1, 0, 0, 0, 512, 2330, 1, 0, 0, 0, 514, 2332, 1, 0, 0, 0, 516, 2334, 1, 0, 0, 0, 518, 2336, 1, 0, 0, 0, 520, 2338, 1, 0, 0, 0, 522, 2340, 1, 0, 0, 0, 524, 2342, 1, 0, 0, 0, 526, 2344, 1, 0, 0, 0, 528, 2346, 1, 0, 0, 0, 530, 2348, 1, 0, 0, 0, 532, 2350, 1, 0, 0, 0, 534, 2352, 1, 0, 0, 0, 536, 2354, 1, 0, 0, 0, 538, 2356, 1, 0, 0, 0, 540, 2358, 1, 0, 0, 0, 542, 2360, 1, 0, 0, 0, 544, 2362, 1, 0, 0, 0, 546, 2364, 1, 0, 0, 0, 548, 2366, 1, 0, 0, 0, 550, 2368, 1, 0, 0, 0, 552, 2370, 1, 0, 0, 0, 554, 2372, 1, 0, 0, 0, 556, 2374, 1, 0, 0, 0, 558, 2376, 1, 0, 0, 0, 560, 2378, 1, 0, 0, 0, 562, 2380, 1, 0, 0, 0, 564, 2382, 1, 0, 0, 0, 566, 2384, 1, 0, 0, 0, 568, 2386, 1, 0, 0, 0, 570, 2388, 1, 0, 0, 0, 572, 2390, 1, 0, 0, 0, 574, 2392, 1, 0, 0, 0, 576, 2394, 1, 0, 0, 0, 578, 2396, 1, 0, 0, 0, 580, 2398, 1, 0, 0, 0, 582, 2400, 1, 0, 0, 0, 584, 2402, 1, 0, 0, 0, 586, 2404, 1, 0, 0, 0, 588, 2406, 1, 0, 0, 0, 590, 2408, 1, 0, 0, 0, 592, 2410, 1, 0, 0, 0, 594, 2412, 1, 0, 0, 0, 596, 2414, 1, 0, 0, 0, 598, 2416, 1, 0, 0, 0, 600, 2418, 1, 0, 0, 0, 602, 2420, 1, 0, 0, 0, 604, 2422, 1, 0, 0, 0, 606, 2424, 1, 0, 0, 0, 608, 2426, 1, 0, 0, 0, 610, 2428, 1, 0, 0, 0, 612, 2430, 1, 0, 0, 0, 614, 2432, 1, 0, 0, 0, 616, 2434, 1, 0, 0, 0, 618, 2436, 1, 0, 0, 0, 620, 2438, 1, 0, 0, 0, 622, 2440, 1, 0, 0, 0, 624, 2442, 1, 0, 0, 0, 626, 2444, 1, 0, 0, 0, 628, 2446, 1, 0, 0, 0, 630, 2448, 1, 0, 0, 0, 632, 2459, 1, 0, 0, 0, 634, 636, 3, 2, 1, 0, 635, 634, 1, 0, 0, 0, 636, 637, 1, 0, 0, 0, 637, 635, 1, 0, 0, 0, 637, 638, 1, 0, 0, 0, 638, 640, 1, 0, 0, 0, 639, 641, 5, 15, 0, 0, 640, 639, 1, 0, 0, 0, 640, 641, 1, 0, 0, 0, 641, 642, 1, 0, 0, 0, 642, 643, 5, 0, 0, 1, 643, 1, 1, 0, 0, 0, 644, 646, 3, 8, 4, 0, 645, 647, 5, 15, 0, 0, 646, 645, 1, 0, 0, 0, 646, 647, 1, 0, 0, 0, 647, 648, 1, 0, 0, 0, 648, 649, 3, 4, 2, 0, 649, 652, 1, 0, 0, 0, 650, 652, 3, 6, 3, 0, 651, 644, 1, 0, 0, 0, 651, 650, 1, 0, 0, 0, 652, 655, 1, 0, 0, 0, 653, 651, 1, 0, 0, 0, 653, 654, 1, 0, 0, 0, 654, 664, 1, 0, 0, 0, 655, 653, 1, 0, 0, 0, 656, 661, 3, 8, 4, 0, 657, 659, 5, 15, 0, 0, 658, 657, 1, 0, 0, 0, 658, 659, 1, 0, 0, 0, 659, 660, 1, 0, 0, 0, 660, 662, 3, 4, 2, 0, 661, 658, 1, 0, 0, 0, 661, 662, 1, 0, 0, 0, 662, 665, 1, 0, 0, 0, 663, 665, 3, 6, 3, 0, 664, 656, 1, 0, 0, 0, 664, 663, 1, 0, 0, 0, 665, 3, 1, 0, 0, 0, 666, 667, 5, 8, 0, 0, 667, 5, 1, 0, 0, 0, 668, 669, 3, 4, 2, 0, 669, 7, 1, 0, 0, 0, 670, 709, 3, 204, 102, 0, 671, 709, 3, 130, 65, 0, 672, 709, 3, 124, 62, 0, 673, 709, 3, 98, 49, 0, 674, 709, 3, 84, 42, 0, 675, 709, 3, 78, 39, 0, 676, 709, 3, 198, 99, 0, 677, 709, 3, 64, 32, 0, 678, 709, 3, 56, 28, 0, 679, 709, 3, 216, 108, 0, 680, 709, 3, 54, 27, 0, 681, 709, 3, 44, 22, 0, 682, 709, 3, 36, 18, 0, 683, 709, 3, 152, 76, 0, 684, 709, 3, 42, 21, 0, 685, 709, 3, 38, 19, 0, 686, 709, 3, 34, 17, 0, 687, 709, 3, 228, 114, 0, 688, 709, 3, 138, 69, 0, 689, 709, 3, 140, 70, 0, 690, 709, 3, 150, 75, 0, 691, 709, 3, 148, 74, 0, 692, 709, 3, 136, 68, 0, 693, 709, 3, 144, 72, 0, 694, 709, 3, 146, 73, 0, 695, 709, 3, 142, 71, 0, 696, 709, 3, 134, 67, 0, 697, 709, 3, 132, 66, 0, 698, 709, 3, 28, 14, 0, 699, 709, 3, 266, 133, 0, 700, 709, 3, 26, 13, 0, 701, 709, 3, 24, 12, 0, 702, 709, 3, 22, 11, 0, 703, 709, 3, 290, 145, 0, 704, 709, 3, 214, 107, 0, 705, 709, 3, 234, 117, 0, 706, 709, 3, 212, 106, 0, 707, 709, 3, 10, 5, 0, 708, 670, 1, 0, 0, 0, 708, 671, 1, 0, 0, 0, 708, 672, 1, 0, 0, 0, 708, 673, 1, 0, 0, 0, 708, 674, 1, 0, 0, 0, 708, 675, 1, 0, 0, 0, 708, 676, 1, 0, 0, 0, 708, 677, 1, 0, 0, 0, 708, 678, 1, 0, 0, 0, 708, 679, 1, 0, 0, 0, 708, 680, 1, 0, 0, 0, 708, 681, 1, 0, 0, 0, 708, 682, 1, 0, 0, 0, 708, 683, 1, 0, 0, 0, 708, 684, 1, 0, 0, 0, 708, 685, 1, 0, 0, 0, 708, 686, 1, 0, 0, 0, 708, 687, 1, 0, 0, 0, 708, 688, 1, 0, 0, 0, 708, 689, 1, 0, 0, 0, 708, 690, 1, 0, 0, 0, 708, 691, 1, 0, 0, 0, 708, 692, 1, 0, 0, 0, 708, 693, 1, 0, 0, 0, 708, 694, 1, 0, 0, 0, 708, 695, 1, 0, 0, 0, 708, 696, 1, 0, 0, 0, 708, 697, 1, 0, 0, 0, 708, 698, 1, 0, 0, 0, 708, 699, 1, 0, 0, 0, 708, 700, 1, 0, 0, 0, 708, 701, 1, 0, 0, 0, 708, 702, 1, 0, 0, 0, 708, 703, 1, 0, 0, 0, 708, 704, 1, 0, 0, 0, 708, 705, 1, 0, 0, 0, 708, 706, 1, 0, 0, 0, 708, 707, 1, 0, 0, 0, 709, 9, 1, 0, 0, 0, 710, 713, 3, 456, 228, 0, 711, 713, 3, 458, 229, 0, 712, 710, 1, 0, 0, 0, 712, 711, 1, 0, 0, 0, 713, 714, 1, 0, 0, 0, 714, 715, 3, 12, 6, 0, 715, 11, 1, 0, 0, 0, 716, 721, 3, 14, 7, 0, 717, 721, 3, 16, 8, 0, 718, 721, 3, 18, 9, 0, 719, 721, 3, 20, 10, 0, 720, 716, 1, 0, 0, 0, 720, 717, 1, 0, 0, 0, 720, 718, 1, 0, 0, 0, 720, 719, 1, 0, 0, 0, 721, 13, 1, 0, 0, 0, 722, 723, 3, 510, 255, 0, 723, 15, 1, 0, 0, 0, 724, 725, 3, 574, 287, 0, 725, 17, 1, 0, 0, 0, 726, 728, 3, 572, 286, 0, 727, 726, 1, 0, 0, 0, 727, 728, 1, 0, 0, 0, 728, 729, 1, 0, 0, 0, 729, 730, 3, 298, 149, 0, 730, 19, 1, 0, 0, 0, 731, 733, 3, 508, 254, 0, 732, 731, 1, 0, 0, 0, 732, 733, 1, 0, 0, 0, 733, 734, 1, 0, 0, 0, 734, 735, 3, 374, 187, 0, 735, 21, 1, 0, 0, 0, 736, 737, 3, 606, 303, 0, 737, 738, 3, 30, 15, 0, 738, 739, 3, 536, 268, 0, 739, 740, 3, 32, 16, 0, 740, 741, 3, 476, 238, 0, 741, 742, 3, 388, 194, 0, 742, 23, 1, 0, 0, 0, 743, 744, 3, 516, 258, 0, 744, 748, 3, 558, 279, 0, 745, 746, 3, 534, 267, 0, 746, 747, 3, 388, 194, 0, 747, 749, 1, 0, 0, 0, 748, 745, 1, 0, 0, 0, 748, 749, 1, 0, 0, 0, 749, 751, 1, 0, 0, 0, 750, 752, 3, 528, 264, 0, 751, 750, 1, 0, 0, 0, 751, 752, 1, 0, 0, 0, 752, 25, 1, 0, 0, 0, 753, 754, 3, 516, 258, 0, 754, 758, 3, 30, 15, 0, 755, 756, 3, 536, 268, 0, 756, 757, 3, 32, 16, 0, 757, 759, 1, 0, 0, 0, 758, 755, 1, 0, 0, 0, 758, 759, 1, 0, 0, 0, 759, 763, 1, 0, 0, 0, 760, 761, 3, 534, 267, 0, 761, 762, 3, 388, 194, 0, 762, 764, 1, 0, 0, 0, 763, 760, 1, 0, 0, 0, 763, 764, 1, 0, 0, 0, 764, 27, 1, 0, 0, 0, 765, 766, 3, 484, 242, 0, 766, 767, 3, 30, 15, 0, 767, 768, 3, 536, 268, 0, 768, 769, 3, 32, 16, 0, 769, 770, 3, 578, 289, 0, 770, 771, 3, 388, 194, 0, 771, 29, 1, 0, 0, 0, 772, 775, 3, 418, 209, 0, 773, 775, 3, 420, 210, 0, 774, 772, 1, 0, 0, 0, 774, 773, 1, 0, 0, 0, 775, 785, 1, 0, 0, 0, 776, 785, 3, 424, 212, 0, 777, 785, 3, 434, 217, 0, 778, 785, 3, 458, 229, 0, 779, 785, 3, 468, 234, 0, 780, 785, 3, 452, 226, 0, 781, 785, 3, 462, 231, 0, 782, 785, 3, 524, 262, 0, 783, 785, 3, 560, 280, 0, 784, 774, 1, 0, 0, 0, 784, 776, 1, 0, 0, 0, 784, 777, 1, 0, 0, 0, 784, 778, 1, 0, 0, 0, 784, 779, 1, 0, 0, 0, 784, 780, 1, 0, 0, 0, 784, 781, 1, 0, 0, 0, 784, 782, 1, 0, 0, 0, 784, 783, 1, 0, 0, 0, 785, 31, 1, 0, 0, 0, 786, 787, 3, 418, 209, 0, 787, 788, 3, 482, 241, 0, 788, 820, 1, 0, 0, 0, 789, 790, 3, 418, 209, 0, 790, 791, 3, 482, 241, 0, 791, 792, 3, 488, 244, 0, 792, 793, 3, 508, 254, 0, 793, 794, 3, 374, 187, 0, 794, 820, 1, 0, 0, 0, 795, 799, 3, 480, 240, 0, 796, 797, 3, 374, 187, 0, 797, 798, 5, 10, 0, 0, 798, 800, 1, 0, 0, 0, 799, 796, 1, 0, 0, 0, 799, 800, 1, 0, 0, 0, 800, 801, 1, 0, 0, 0, 801, 802, 3, 400, 200, 0, 802, 820, 1, 0, 0, 0, 803, 804, 3, 418, 209, 0, 804, 805, 3, 510, 255, 0, 805, 820, 1, 0, 0, 0, 806, 807, 3, 508, 254, 0, 807, 808, 3, 374, 187, 0, 808, 820, 1, 0, 0, 0, 809, 811, 3, 572, 286, 0, 810, 809, 1, 0, 0, 0, 810, 811, 1, 0, 0, 0, 811, 812, 1, 0, 0, 0, 812, 820, 3, 298, 149, 0, 813, 814, 3, 418, 209, 0, 814, 815, 3, 558, 279, 0, 815, 820, 1, 0, 0, 0, 816, 817, 3, 556, 278, 0, 817, 818, 3, 388, 194, 0, 818, 820, 1, 0, 0, 0, 819, 786, 1, 0, 0, 0, 819, 789, 1, 0, 0, 0, 819, 795, 1, 0, 0, 0, 819, 803, 1, 0, 0, 0, 819, 806, 1, 0, 0, 0, 819, 810, 1, 0, 0, 0, 819, 813, 1, 0, 0, 0, 819, 816, 1, 0, 0, 0, 820, 33, 1, 0, 0, 0, 821, 822, 3, 452, 226, 0, 822, 824, 3, 594, 297, 0, 823, 825, 3, 276, 138, 0, 824, 823, 1, 0, 0, 0, 824, 825, 1, 0, 0, 0, 825, 826, 1, 0, 0, 0, 826, 827, 3, 404, 202, 0, 827, 828, 3, 604, 302, 0, 828, 829, 3, 544, 272, 0, 829, 832, 3, 368, 184, 0, 830, 833, 3, 570, 285, 0, 831, 833, 3, 526, 263, 0, 832, 830, 1, 0, 0, 0, 832, 831, 1, 0, 0, 0, 832, 833, 1, 0, 0, 0, 833, 35, 1, 0, 0, 0, 834, 835, 3, 452, 226, 0, 835, 837, 3, 556, 278, 0, 836, 838, 3, 276, 138, 0, 837, 836, 1, 0, 0, 0, 837, 838, 1, 0, 0, 0, 838, 839, 1, 0, 0, 0, 839, 841, 3, 388, 194, 0, 840, 842, 3, 126, 63, 0, 841, 840, 1, 0, 0, 0, 841, 842, 1, 0, 0, 0, 842, 37, 1, 0, 0, 0, 843, 844, 3, 452, 226, 0, 844, 846, 3, 586, 293, 0, 845, 847, 3, 276, 138, 0, 846, 845, 1, 0, 0, 0, 846, 847, 1, 0, 0, 0, 847, 851, 1, 0, 0, 0, 848, 849, 3, 374, 187, 0, 849, 850, 5, 10, 0, 0, 850, 852, 1, 0, 0, 0, 851, 848, 1, 0, 0, 0, 851, 852, 1, 0, 0, 0, 852, 853, 1, 0, 0, 0, 853, 854, 3, 396, 198, 0, 854, 855, 3, 610, 305, 0, 855, 856, 3, 40, 20, 0, 856, 857, 3, 612, 306, 0, 857, 39, 1, 0, 0, 0, 858, 859, 3, 378, 189, 0, 859, 866, 3, 380, 190, 0, 860, 861, 3, 626, 313, 0, 861, 862, 3, 378, 189, 0, 862, 863, 3, 380, 190, 0, 863, 865, 1, 0, 0, 0, 864, 860, 1, 0, 0, 0, 865, 868, 1, 0, 0, 0, 866, 864, 1, 0, 0, 0, 866, 867, 1, 0, 0, 0, 867, 41, 1, 0, 0, 0, 868, 866, 1, 0, 0, 0, 869, 870, 3, 452, 226, 0, 870, 872, 3, 580, 290, 0, 871, 873, 3, 276, 138, 0, 872, 871, 1, 0, 0, 0, 872, 873, 1, 0, 0, 0, 873, 877, 1, 0, 0, 0, 874, 875, 3, 374, 187, 0, 875, 876, 5, 10, 0, 0, 876, 878, 1, 0, 0, 0, 877, 874, 1, 0, 0, 0, 877, 878, 1, 0, 0, 0, 878, 879, 1, 0, 0, 0, 879, 880, 3, 390, 195, 0, 880, 881, 3, 596, 298, 0, 881, 882, 3, 392, 196, 0, 882, 43, 1, 0, 0, 0, 883, 884, 3, 452, 226, 0, 884, 885, 3, 522, 261, 0, 885, 887, 3, 600, 300, 0, 886, 888, 3, 276, 138, 0, 887, 886, 1, 0, 0, 0, 887, 888, 1, 0, 0, 0, 888, 892, 1, 0, 0, 0, 889, 890, 3, 374, 187, 0, 890, 891, 5, 10, 0, 0, 891, 893, 1, 0, 0, 0, 892, 889, 1, 0, 0, 0, 892, 893, 1, 0, 0, 0, 893, 894, 1, 0, 0, 0, 894, 895, 3, 394, 197, 0, 895, 896, 3, 430, 215, 0, 896, 897, 3, 560, 280, 0, 897, 898, 3, 284, 142, 0, 898, 899, 3, 476, 238, 0, 899, 900, 3, 298, 149, 0, 900, 901, 3, 46, 23, 0, 901, 902, 3, 546, 273, 0, 902, 903, 3, 504, 252, 0, 903, 904, 3, 610, 305, 0, 904, 905, 3, 284, 142, 0, 905, 909, 3, 612, 306, 0, 906, 907, 3, 604, 302, 0, 907, 908, 3, 52, 26, 0, 908, 910, 1, 0, 0, 0, 909, 906, 1, 0, 0, 0, 909, 910, 1, 0, 0, 0, 910, 45, 1, 0, 0, 0, 911, 912, 3, 602, 301, 0, 912, 916, 3, 48, 24, 0, 913, 914, 3, 426, 213, 0, 914, 915, 3, 322, 161, 0, 915, 917, 1, 0, 0, 0, 916, 913, 1, 0, 0, 0, 916, 917, 1, 0, 0, 0, 917, 47, 1, 0, 0, 0, 918, 924, 3, 50, 25, 0, 919, 920, 3, 426, 213, 0, 920, 921, 3, 50, 25, 0, 921, 923, 1, 0, 0, 0, 922, 919, 1, 0, 0, 0, 923, 926, 1, 0, 0, 0, 924, 922, 1, 0, 0, 0, 924, 925, 1, 0, 0, 0, 925, 49, 1, 0, 0, 0, 926, 924, 1, 0, 0, 0, 927, 928, 3, 378, 189, 0, 928, 929, 3, 500, 250, 0, 929, 930, 3, 530, 265, 0, 930, 931, 3, 532, 266, 0, 931, 51, 1, 0, 0, 0, 932, 939, 3, 158, 79, 0, 933, 934, 3, 158, 79, 0, 934, 935, 3, 426, 213, 0, 935, 936, 3, 156, 78, 0, 936, 939, 1, 0, 0, 0, 937, 939, 3, 156, 78, 0, 938, 932, 1, 0, 0, 0, 938, 933, 1, 0, 0, 0, 938, 937, 1, 0, 0, 0, 939, 53, 1, 0, 0, 0, 940, 941, 3, 452, 226, 0, 941, 943, 3, 508, 254, 0, 942, 944, 3, 276, 138, 0, 943, 942, 1, 0, 0, 0, 943, 944, 1, 0, 0, 0, 944, 945, 1, 0, 0, 0, 945, 946, 3, 374, 187, 0, 946, 947, 3, 604, 302, 0, 947, 948, 3, 552, 276, 0, 948, 949, 5, 19, 0, 0, 949, 950, 3, 614, 307, 0, 950, 951, 3, 206, 103, 0, 951, 955, 3, 616, 308, 0, 952, 953, 3, 426, 213, 0, 953, 954, 3, 210, 105, 0, 954, 956, 1, 0, 0, 0, 955, 952, 1, 0, 0, 0, 955, 956, 1, 0, 0, 0, 956, 55, 1, 0, 0, 0, 957, 959, 3, 452, 226, 0, 958, 960, 3, 76, 38, 0, 959, 958, 1, 0, 0, 0, 959, 960, 1, 0, 0, 0, 960, 961, 1, 0, 0, 0, 961, 963, 3, 480, 240, 0, 962, 964, 3, 276, 138, 0, 963, 962, 1, 0, 0, 0, 963, 964, 1, 0, 0, 0, 964, 968, 1, 0, 0, 0, 965, 966, 3, 374, 187, 0, 966, 967, 5, 10, 0, 0, 967, 969, 1, 0, 0, 0, 968, 965, 1, 0, 0, 0, 968, 969, 1, 0, 0, 0, 969, 970, 1, 0, 0, 0, 970, 971, 3, 400, 200, 0, 971, 973, 3, 610, 305, 0, 972, 974, 3, 60, 30, 0, 973, 972, 1, 0, 0, 0, 973, 974, 1, 0, 0, 0, 974, 975, 1, 0, 0, 0, 975, 976, 3, 612, 306, 0, 976, 977, 3, 62, 31, 0, 977, 978, 3, 554, 277, 0, 978, 979, 3, 380, 190, 0, 979, 980, 3, 512, 256, 0, 980, 981, 3, 402, 201, 0, 981, 982, 3, 430, 215, 0, 982, 983, 3, 58, 29, 0, 983, 57, 1, 0, 0, 0, 984, 985, 7, 0, 0, 0, 985, 59, 1, 0, 0, 0, 986, 992, 3, 410, 205, 0, 987, 988, 3, 626, 313, 0, 988, 989, 3, 410, 205, 0, 989, 991, 1, 0, 0, 0, 990, 987, 1, 0, 0, 0, 991, 994, 1, 0, 0, 0, 992, 990, 1, 0, 0, 0, 992, 993, 1, 0, 0, 0, 993, 61, 1, 0, 0, 0, 994, 992, 1, 0, 0, 0, 995, 1000, 3, 444, 222, 0, 996, 997, 3, 554, 277, 0, 997, 998, 3, 532, 266, 0, 998, 1000, 1, 0, 0, 0, 999, 995, 1, 0, 0, 0, 999, 996, 1, 0, 0, 0, 1000, 1001, 1, 0, 0, 0, 1001, 1002, 3, 536, 268, 0, 1002, 1003, 3, 532, 266, 0, 1003, 1004, 3, 494, 247, 0, 1004, 63, 1, 0, 0, 0, 1005, 1007, 3, 452, 226, 0, 1006, 1008, 3, 76, 38, 0, 1007, 1006, 1, 0, 0, 0, 1007, 1008, 1, 0, 0, 0, 1008, 1009, 1, 0, 0, 0, 1009, 1011, 3, 416, 208, 0, 1010, 1012, 3, 276, 138, 0, 1011, 1010, 1, 0, 0, 0, 1011, 1012, 1, 0, 0, 0, 1012, 1016, 1, 0, 0, 0, 1013, 1014, 3, 374, 187, 0, 1014, 1015, 5, 10, 0, 0, 1015, 1017, 1, 0, 0, 0, 1016, 1013, 1, 0, 0, 0, 1016, 1017, 1, 0, 0, 0, 1017, 1018, 1, 0, 0, 0, 1018, 1019, 3, 398, 199, 0, 1019, 1020, 3, 610, 305, 0, 1020, 1021, 3, 380, 190, 0, 1021, 1022, 3, 612, 306, 0, 1022, 1023, 3, 564, 282, 0, 1023, 1024, 3, 400, 200, 0, 1024, 1025, 3, 568, 284, 0, 1025, 1026, 3, 380, 190, 0, 1026, 1027, 3, 474, 237, 0, 1027, 1028, 3, 400, 200, 0, 1028, 1029, 3, 492, 246, 0, 1029, 1030, 3, 66, 33, 0, 1030, 65, 1, 0, 0, 0, 1031, 1036, 3, 362, 181, 0, 1032, 1036, 3, 74, 37, 0, 1033, 1036, 3, 72, 36, 0, 1034, 1036, 3, 68, 34, 0, 1035, 1031, 1, 0, 0, 0, 1035, 1032, 1, 0, 0, 0, 1035, 1033, 1, 0, 0, 0, 1035, 1034, 1, 0, 0, 0, 1036, 67, 1, 0, 0, 0, 1037, 1038, 3, 614, 307, 0, 1038, 1044, 3, 70, 35, 0, 1039, 1040, 3, 626, 313, 0, 1040, 1041, 3, 70, 35, 0, 1041, 1043, 1, 0, 0, 0, 1042, 1039, 1, 0, 0, 0, 1043, 1046, 1, 0, 0, 0, 1044, 1042, 1, 0, 0, 0, 1044, 1045, 1, 0, 0, 0, 1045, 1047, 1, 0, 0, 0, 1046, 1044, 1, 0, 0, 0, 1047, 1048, 3, 616, 308, 0, 1048, 69, 1, 0, 0, 0, 1049, 1050, 3, 408, 204, 0, 1050, 1051, 5, 9, 0, 0, 1051, 1052, 3, 66, 33, 0, 1052, 71, 1, 0, 0, 0, 1053, 1054, 3, 610, 305, 0, 1054, 1061, 3, 74, 37, 0, 1055, 1056, 3, 626, 313, 0, 1056, 1057, 3, 362, 181, 0, 1057, 1060, 1, 0, 0, 0, 1058, 1060, 3, 74, 37, 0, 1059, 1055, 1, 0, 0, 0, 1059, 1058, 1, 0, 0, 0, 1060, 1063, 1, 0, 0, 0, 1061, 1059, 1, 0, 0, 0, 1061, 1062, 1, 0, 0, 0, 1062, 1064, 1, 0, 0, 0, 1063, 1061, 1, 0, 0, 0, 1064, 1065, 3, 612, 306, 0, 1065, 73, 1, 0, 0, 0, 1066, 1067, 3, 610, 305, 0, 1067, 1073, 3, 362, 181, 0, 1068, 1069, 3, 626, 313, 0, 1069, 1070, 3, 362, 181, 0, 1070, 1072, 1, 0, 0, 0, 1071, 1068, 1, 0, 0, 0, 1072, 1075, 1, 0, 0, 0, 1073, 1071, 1, 0, 0, 0, 1073, 1074, 1, 0, 0, 0, 1074, 1076, 1, 0, 0, 0, 1075, 1073, 1, 0, 0, 0, 1076, 1077, 3, 612, 306, 0, 1077, 75, 1, 0, 0, 0, 1078, 1079, 3, 540, 270, 0, 1079, 1080, 3, 550, 275, 0, 1080, 77, 1, 0, 0, 0, 1081, 1082, 3, 424, 212, 0, 1082, 1083, 3, 594, 297, 0, 1083, 1084, 3, 404, 202, 0, 1084, 1085, 3, 604, 302, 0, 1085, 1087, 3, 80, 40, 0, 1086, 1088, 3, 82, 41, 0, 1087, 1086, 1, 0, 0, 0, 1087, 1088, 1, 0, 0, 0, 1088, 79, 1, 0, 0, 0, 1089, 1090, 3, 544, 272, 0, 1090, 1091, 3, 368, 184, 0, 1091, 81, 1, 0, 0, 0, 1092, 1095, 3, 570, 285, 0, 1093, 1095, 3, 526, 263, 0, 1094, 1092, 1, 0, 0, 0, 1094, 1093, 1, 0, 0, 0, 1095, 83, 1, 0, 0, 0, 1096, 1097, 3, 424, 212, 0, 1097, 1101, 3, 586, 293, 0, 1098, 1099, 3, 374, 187, 0, 1099, 1100, 5, 10, 0, 0, 1100, 1102, 1, 0, 0, 0, 1101, 1098, 1, 0, 0, 0, 1101, 1102, 1, 0, 0, 0, 1102, 1103, 1, 0, 0, 0, 1103, 1104, 3, 396, 198, 0, 1104, 1105, 3, 86, 43, 0, 1105, 85, 1, 0, 0, 0, 1106, 1110, 3, 96, 48, 0, 1107, 1110, 3, 94, 47, 0, 1108, 1110, 3, 88, 44, 0, 1109, 1106, 1, 0, 0, 0, 1109, 1107, 1, 0, 0, 0, 1109, 1108, 1, 0, 0, 0, 1110, 87, 1, 0, 0, 0, 1111, 1112, 3, 548, 274, 0, 1112, 1113, 3, 90, 45, 0, 1113, 89, 1, 0, 0, 0, 1114, 1120, 3, 92, 46, 0, 1115, 1116, 3, 426, 213, 0, 1116, 1117, 3, 92, 46, 0, 1117, 1119, 1, 0, 0, 0, 1118, 1115, 1, 0, 0, 0, 1119, 1122, 1, 0, 0, 0, 1120, 1118, 1, 0, 0, 0, 1120, 1121, 1, 0, 0, 0, 1121, 91, 1, 0, 0, 0, 1122, 1120, 1, 0, 0, 0, 1123, 1124, 3, 378, 189, 0, 1124, 1125, 3, 578, 289, 0, 1125, 1126, 3, 378, 189, 0, 1126, 93, 1, 0, 0, 0, 1127, 1128, 3, 414, 207, 0, 1128, 1129, 3, 378, 189, 0, 1129, 1136, 3, 380, 190, 0, 1130, 1131, 3, 626, 313, 0, 1131, 1132, 3, 378, 189, 0, 1132, 1133, 3, 380, 190, 0, 1133, 1135, 1, 0, 0, 0, 1134, 1130, 1, 0, 0, 0, 1135, 1138, 1, 0, 0, 0, 1136, 1134, 1, 0, 0, 0, 1136, 1137, 1, 0, 0, 0, 1137, 95, 1, 0, 0, 0, 1138, 1136, 1, 0, 0, 0, 1139, 1140, 3, 424, 212, 0, 1140, 1141, 3, 378, 189, 0, 1141, 1142, 3, 586, 293, 0, 1142, 1143, 3, 380, 190, 0, 1143, 97, 1, 0, 0, 0, 1144, 1145, 3, 424, 212, 0, 1145, 1146, 3, 572, 286, 0, 1146, 1147, 3, 298, 149, 0, 1147, 1148, 3, 100, 50, 0, 1148, 99, 1, 0, 0, 0, 1149, 1156, 3, 118, 59, 0, 1150, 1156, 3, 108, 54, 0, 1151, 1156, 3, 106, 53, 0, 1152, 1156, 3, 112, 56, 0, 1153, 1156, 3, 104, 52, 0, 1154, 1156, 3, 102, 51, 0, 1155, 1149, 1, 0, 0, 0, 1155, 1150, 1, 0, 0, 0, 1155, 1151, 1, 0, 0, 0, 1155, 1152, 1, 0, 0, 0, 1155, 1153, 1, 0, 0, 0, 1155, 1154, 1, 0, 0, 0, 1156, 101, 1, 0, 0, 0, 1157, 1158, 3, 604, 302, 0, 1158, 1159, 3, 158, 79, 0, 1159, 103, 1, 0, 0, 0, 1160, 1161, 3, 548, 274, 0, 1161, 1162, 3, 378, 189, 0, 1162, 1163, 3, 578, 289, 0, 1163, 1164, 3, 378, 189, 0, 1164, 105, 1, 0, 0, 0, 1165, 1166, 3, 462, 231, 0, 1166, 1167, 3, 448, 224, 0, 1167, 1168, 3, 566, 283, 0, 1168, 107, 1, 0, 0, 0, 1169, 1170, 3, 462, 231, 0, 1170, 1171, 3, 110, 55, 0, 1171, 109, 1, 0, 0, 0, 1172, 1178, 3, 378, 189, 0, 1173, 1174, 3, 626, 313, 0, 1174, 1175, 3, 378, 189, 0, 1175, 1177, 1, 0, 0, 0, 1176, 1173, 1, 0, 0, 0, 1177, 1180, 1, 0, 0, 0, 1178, 1176, 1, 0, 0, 0, 1178, 1179, 1, 0, 0, 0, 1179, 111, 1, 0, 0, 0, 1180, 1178, 1, 0, 0, 0, 1181, 1182, 3, 424, 212, 0, 1182, 1183, 3, 114, 57, 0, 1183, 113, 1, 0, 0, 0, 1184, 1190, 3, 116, 58, 0, 1185, 1186, 3, 626, 313, 0, 1186, 1187, 3, 116, 58, 0, 1187, 1189, 1, 0, 0, 0, 1188, 1185, 1, 0, 0, 0, 1189, 1192, 1, 0, 0, 0, 1190, 1188, 1, 0, 0, 0, 1190, 1191, 1, 0, 0, 0, 1191, 115, 1, 0, 0, 0, 1192, 1190, 1, 0, 0, 0, 1193, 1194, 3, 378, 189, 0, 1194, 1195, 3, 586, 293, 0, 1195, 1196, 3, 380, 190, 0, 1196, 117, 1, 0, 0, 0, 1197, 1198, 3, 414, 207, 0, 1198, 1199, 3, 120, 60, 0, 1199, 119, 1, 0, 0, 0, 1200, 1206, 3, 122, 61, 0, 1201, 1202, 3, 626, 313, 0, 1202, 1203, 3, 122, 61, 0, 1203, 1205, 1, 0, 0, 0, 1204, 1201, 1, 0, 0, 0, 1205, 1208, 1, 0, 0, 0, 1206, 1204, 1, 0, 0, 0, 1206, 1207, 1, 0, 0, 0, 1207, 121, 1, 0, 0, 0, 1208, 1206, 1, 0, 0, 0, 1209, 1210, 3, 378, 189, 0, 1210, 1211, 3, 380, 190, 0, 1211, 123, 1, 0, 0, 0, 1212, 1213, 3, 424, 212, 0, 1213, 1214, 3, 556, 278, 0, 1214, 1216, 3, 388, 194, 0, 1215, 1217, 3, 126, 63, 0, 1216, 1215, 1, 0, 0, 0, 1216, 1217, 1, 0, 0, 0, 1217, 125, 1, 0, 0, 0, 1218, 1219, 3, 604, 302, 0, 1219, 1225, 3, 128, 64, 0, 1220, 1221, 3, 426, 213, 0, 1221, 1222, 3, 128, 64, 0, 1222, 1224, 1, 0, 0, 0, 1223, 1220, 1, 0, 0, 0, 1224, 1227, 1, 0, 0, 0, 1225, 1223, 1, 0, 0, 0, 1225, 1226, 1, 0, 0, 0, 1226, 127, 1, 0, 0, 0, 1227, 1225, 1, 0, 0, 0, 1228, 1229, 3, 544, 272, 0, 1229, 1230, 5, 19, 0, 0, 1230, 1231, 3, 368, 184, 0, 1231, 1245, 1, 0, 0, 0, 1232, 1233, 3, 520, 260, 0, 1233, 1234, 5, 19, 0, 0, 1234, 1235, 3, 370, 185, 0, 1235, 1245, 1, 0, 0, 0, 1236, 1237, 3, 570, 285, 0, 1237, 1238, 5, 19, 0, 0, 1238, 1239, 3, 370, 185, 0, 1239, 1245, 1, 0, 0, 0, 1240, 1241, 3, 538, 269, 0, 1241, 1242, 5, 19, 0, 0, 1242, 1243, 3, 166, 83, 0, 1243, 1245, 1, 0, 0, 0, 1244, 1228, 1, 0, 0, 0, 1244, 1232, 1, 0, 0, 0, 1244, 1236, 1, 0, 0, 0, 1244, 1240, 1, 0, 0, 0, 1245, 129, 1, 0, 0, 0, 1246, 1247, 3, 424, 212, 0, 1247, 1248, 3, 522, 261, 0, 1248, 1252, 3, 600, 300, 0, 1249, 1250, 3, 374, 187, 0, 1250, 1251, 5, 10, 0, 0, 1251, 1253, 1, 0, 0, 0, 1252, 1249, 1, 0, 0, 0, 1252, 1253, 1, 0, 0, 0, 1253, 1254, 1, 0, 0, 0, 1254, 1258, 3, 394, 197, 0, 1255, 1256, 3, 604, 302, 0, 1256, 1257, 3, 158, 79, 0, 1257, 1259, 1, 0, 0, 0, 1258, 1255, 1, 0, 0, 0, 1258, 1259, 1, 0, 0, 0, 1259, 131, 1, 0, 0, 0, 1260, 1261, 3, 462, 231, 0, 1261, 1263, 3, 594, 297, 0, 1262, 1264, 3, 278, 139, 0, 1263, 1262, 1, 0, 0, 0, 1263, 1264, 1, 0, 0, 0, 1264, 1265, 1, 0, 0, 0, 1265, 1266, 3, 404, 202, 0, 1266, 133, 1, 0, 0, 0, 1267, 1268, 3, 462, 231, 0, 1268, 1270, 3, 586, 293, 0, 1269, 1271, 3, 278, 139, 0, 1270, 1269, 1, 0, 0, 0, 1270, 1271, 1, 0, 0, 0, 1271, 1275, 1, 0, 0, 0, 1272, 1273, 3, 374, 187, 0, 1273, 1274, 5, 10, 0, 0, 1274, 1276, 1, 0, 0, 0, 1275, 1272, 1, 0, 0, 0, 1275, 1276, 1, 0, 0, 0, 1276, 1277, 1, 0, 0, 0, 1277, 1278, 3, 396, 198, 0, 1278, 135, 1, 0, 0, 0, 1279, 1280, 3, 462, 231, 0, 1280, 1281, 3, 522, 261, 0, 1281, 1283, 3, 600, 300, 0, 1282, 1284, 3, 278, 139, 0, 1283, 1282, 1, 0, 0, 0, 1283, 1284, 1, 0, 0, 0, 1284, 1288, 1, 0, 0, 0, 1285, 1286, 3, 374, 187, 0, 1286, 1287, 5, 10, 0, 0, 1287, 1289, 1, 0, 0, 0, 1288, 1285, 1, 0, 0, 0, 1288, 1289, 1, 0, 0, 0, 1289, 1290, 1, 0, 0, 0, 1290, 1291, 3, 394, 197, 0, 1291, 137, 1, 0, 0, 0, 1292, 1293, 3, 462, 231, 0, 1293, 1295, 3, 416, 208, 0, 1294, 1296, 3, 278, 139, 0, 1295, 1294, 1, 0, 0, 0, 1295, 1296, 1, 0, 0, 0, 1296, 1300, 1, 0, 0, 0, 1297, 1298, 3, 374, 187, 0, 1298, 1299, 5, 10, 0, 0, 1299, 1301, 1, 0, 0, 0, 1300, 1297, 1, 0, 0, 0, 1300, 1301, 1, 0, 0, 0, 1301, 1302, 1, 0, 0, 0, 1302, 1303, 3, 398, 199, 0, 1303, 139, 1, 0, 0, 0, 1304, 1305, 3, 462, 231, 0, 1305, 1307, 3, 480, 240, 0, 1306, 1308, 3, 278, 139, 0, 1307, 1306, 1, 0, 0, 0, 1307, 1308, 1, 0, 0, 0, 1308, 1312, 1, 0, 0, 0, 1309, 1310, 3, 374, 187, 0, 1310, 1311, 5, 10, 0, 0, 1311, 1313, 1, 0, 0, 0, 1312, 1309, 1, 0, 0, 0, 1312, 1313, 1, 0, 0, 0, 1313, 1314, 1, 0, 0, 0, 1314, 1315, 3, 400, 200, 0, 1315, 141, 1, 0, 0, 0, 1316, 1317, 3, 462, 231, 0, 1317, 1319, 3, 580, 290, 0, 1318, 1320, 3, 278, 139, 0, 1319, 1318, 1, 0, 0, 0, 1319, 1320, 1, 0, 0, 0, 1320, 1321, 1, 0, 0, 0, 1321, 1322, 3, 390, 195, 0, 1322, 1323, 3, 536, 268, 0, 1323, 1324, 3, 298, 149, 0, 1324, 143, 1, 0, 0, 0, 1325, 1326, 3, 462, 231, 0, 1326, 1328, 3, 556, 278, 0, 1327, 1329, 3, 278, 139, 0, 1328, 1327, 1, 0, 0, 0, 1328, 1329, 1, 0, 0, 0, 1329, 1330, 1, 0, 0, 0, 1330, 1331, 3, 388, 194, 0, 1331, 145, 1, 0, 0, 0, 1332, 1333, 3, 462, 231, 0, 1333, 1335, 3, 572, 286, 0, 1334, 1336, 3, 278, 139, 0, 1335, 1334, 1, 0, 0, 0, 1335, 1336, 1, 0, 0, 0, 1336, 1337, 1, 0, 0, 0, 1337, 1338, 3, 298, 149, 0, 1338, 147, 1, 0, 0, 0, 1339, 1340, 3, 462, 231, 0, 1340, 1342, 3, 508, 254, 0, 1341, 1343, 3, 278, 139, 0, 1342, 1341, 1, 0, 0, 0, 1342, 1343, 1, 0, 0, 0, 1343, 1344, 1, 0, 0, 0, 1344, 1345, 3, 374, 187, 0, 1345, 149, 1, 0, 0, 0, 1346, 1347, 3, 462, 231, 0, 1347, 1349, 3, 490, 245, 0, 1348, 1350, 3, 278, 139, 0, 1349, 1348, 1, 0, 0, 0, 1349, 1350, 1, 0, 0, 0, 1350, 1354, 1, 0, 0, 0, 1351, 1352, 3, 374, 187, 0, 1352, 1353, 5, 10, 0, 0, 1353, 1355, 1, 0, 0, 0, 1354, 1351, 1, 0, 0, 0, 1354, 1355, 1, 0, 0, 0, 1355, 1356, 1, 0, 0, 0, 1356, 1357, 3, 218, 109, 0, 1357, 151, 1, 0, 0, 0, 1358, 1359, 3, 452, 226, 0, 1359, 1361, 3, 572, 286, 0, 1360, 1362, 3, 276, 138, 0, 1361, 1360, 1, 0, 0, 0, 1361, 1362, 1, 0, 0, 0, 1362, 1363, 1, 0, 0, 0, 1363, 1364, 3, 298, 149, 0, 1364, 1365, 3, 610, 305, 0, 1365, 1366, 3, 174, 87, 0, 1366, 1368, 3, 612, 306, 0, 1367, 1369, 3, 154, 77, 0, 1368, 1367, 1, 0, 0, 0, 1368, 1369, 1, 0, 0, 0, 1369, 153, 1, 0, 0, 0, 1370, 1372, 3, 604, 302, 0, 1371, 1373, 3, 158, 79, 0, 1372, 1371, 1, 0, 0, 0, 1372, 1373, 1, 0, 0, 0, 1373, 1375, 1, 0, 0, 0, 1374, 1376, 3, 156, 78, 0, 1375, 1374, 1, 0, 0, 0, 1375, 1376, 1, 0, 0, 0, 1376, 155, 1, 0, 0, 0, 1377, 1378, 3, 446, 223, 0, 1378, 1379, 3, 542, 271, 0, 1379, 1380, 3, 442, 221, 0, 1380, 1381, 3, 610, 305, 0, 1381, 1383, 3, 378, 189, 0, 1382, 1384, 3, 386, 193, 0, 1383, 1382, 1, 0, 0, 0, 1383, 1384, 1, 0, 0, 0, 1384, 1385, 1, 0, 0, 0, 1385, 1386, 3, 612, 306, 0, 1386, 157, 1, 0, 0, 0, 1387, 1393, 3, 160, 80, 0, 1388, 1389, 3, 426, 213, 0, 1389, 1390, 3, 160, 80, 0, 1390, 1392, 1, 0, 0, 0, 1391, 1388, 1, 0, 0, 0, 1392, 1395, 1, 0, 0, 0, 1393, 1391, 1, 0, 0, 0, 1393, 1394, 1, 0, 0, 0, 1394, 159, 1, 0, 0, 0, 1395, 1393, 1, 0, 0, 0, 1396, 1397, 3, 162, 81, 0, 1397, 1398, 5, 19, 0, 0, 1398, 1399, 3, 164, 82, 0, 1399, 1405, 1, 0, 0, 0, 1400, 1401, 3, 162, 81, 0, 1401, 1402, 5, 19, 0, 0, 1402, 1403, 3, 166, 83, 0, 1403, 1405, 1, 0, 0, 0, 1404, 1396, 1, 0, 0, 0, 1404, 1400, 1, 0, 0, 0, 1405, 161, 1, 0, 0, 0, 1406, 1407, 5, 174, 0, 0, 1407, 163, 1, 0, 0, 0, 1408, 1411, 3, 368, 184, 0, 1409, 1411, 3, 366, 183, 0, 1410, 1408, 1, 0, 0, 0, 1410, 1409, 1, 0, 0, 0, 1411, 165, 1, 0, 0, 0, 1412, 1413, 3, 614, 307, 0, 1413, 1419, 3, 168, 84, 0, 1414, 1415, 3, 626, 313, 0, 1415, 1416, 3, 168, 84, 0, 1416, 1418, 1, 0, 0, 0, 1417, 1414, 1, 0, 0, 0, 1418, 1421, 1, 0, 0, 0, 1419, 1417, 1, 0, 0, 0, 1419, 1420, 1, 0, 0, 0, 1420, 1422, 1, 0, 0, 0, 1421, 1419, 1, 0, 0, 0, 1422, 1423, 3, 616, 308, 0, 1423, 167, 1, 0, 0, 0, 1424, 1425, 3, 170, 85, 0, 1425, 1426, 5, 9, 0, 0, 1426, 1427, 3, 172, 86, 0, 1427, 169, 1, 0, 0, 0, 1428, 1429, 3, 368, 184, 0, 1429, 171, 1, 0, 0, 0, 1430, 1433, 3, 368, 184, 0, 1431, 1433, 3, 366, 183, 0, 1432, 1430, 1, 0, 0, 0, 1432, 1431, 1, 0, 0, 0, 1433, 173, 1, 0, 0, 0, 1434, 1440, 3, 176, 88, 0, 1435, 1436, 3, 626, 313, 0, 1436, 1437, 3, 176, 88, 0, 1437, 1439, 1, 0, 0, 0, 1438, 1435, 1, 0, 0, 0, 1439, 1442, 1, 0, 0, 0, 1440, 1438, 1, 0, 0, 0, 1440, 1441, 1, 0, 0, 0, 1441, 1446, 1, 0, 0, 0, 1442, 1440, 1, 0, 0, 0, 1443, 1444, 3, 626, 313, 0, 1444, 1445, 3, 180, 90, 0, 1445, 1447, 1, 0, 0, 0, 1446, 1443, 1, 0, 0, 0, 1446, 1447, 1, 0, 0, 0, 1447, 175, 1, 0, 0, 0, 1448, 1449, 3, 378, 189, 0, 1449, 1451, 3, 380, 190, 0, 1450, 1452, 3, 178, 89, 0, 1451, 1450, 1, 0, 0, 0, 1451, 1452, 1, 0, 0, 0, 1452, 177, 1, 0, 0, 0, 1453, 1454, 3, 546, 273, 0, 1454, 1455, 3, 504, 252, 0, 1455, 179, 1, 0, 0, 0, 1456, 1457, 3, 546, 273, 0, 1457, 1458, 3, 504, 252, 0, 1458, 1459, 3, 610, 305, 0, 1459, 1460, 3, 182, 91, 0, 1460, 1461, 3, 612, 306, 0, 1461, 181, 1, 0, 0, 0, 1462, 1466, 3, 184, 92, 0, 1463, 1466, 3, 186, 93, 0, 1464, 1466, 3, 188, 94, 0, 1465, 1462, 1, 0, 0, 0, 1465, 1463, 1, 0, 0, 0, 1465, 1464, 1, 0, 0, 0, 1466, 183, 1, 0, 0, 0, 1467, 1468, 3, 378, 189, 0, 1468, 185, 1, 0, 0, 0, 1469, 1470, 3, 194, 97, 0, 1470, 1471, 3, 626, 313, 0, 1471, 1472, 3, 192, 96, 0, 1472, 187, 1, 0, 0, 0, 1473, 1474, 3, 610, 305, 0, 1474, 1475, 3, 190, 95, 0, 1475, 1476, 3, 612, 306, 0, 1476, 1477, 3, 626, 313, 0, 1477, 1478, 3, 192, 96, 0, 1478, 189, 1, 0, 0, 0, 1479, 1485, 3, 194, 97, 0, 1480, 1481, 3, 626, 313, 0, 1481, 1482, 3, 194, 97, 0, 1482, 1484, 1, 0, 0, 0, 1483, 1480, 1, 0, 0, 0, 1484, 1487, 1, 0, 0, 0, 1485, 1483, 1, 0, 0, 0, 1485, 1486, 1, 0, 0, 0, 1486, 191, 1, 0, 0, 0, 1487, 1485, 1, 0, 0, 0, 1488, 1494, 3, 196, 98, 0, 1489, 1490, 3, 626, 313, 0, 1490, 1491, 3, 196, 98, 0, 1491, 1493, 1, 0, 0, 0, 1492, 1489, 1, 0, 0, 0, 1493, 1496, 1, 0, 0, 0, 1494, 1492, 1, 0, 0, 0, 1494, 1495, 1, 0, 0, 0, 1495, 193, 1, 0, 0, 0, 1496, 1494, 1, 0, 0, 0, 1497, 1498, 3, 378, 189, 0, 1498, 195, 1, 0, 0, 0, 1499, 1500, 3, 378, 189, 0, 1500, 197, 1, 0, 0, 0, 1501, 1502, 3, 428, 214, 0, 1502, 1503, 3, 436, 218, 0, 1503, 199, 1, 0, 0, 0, 1504, 1506, 3, 440, 220, 0, 1505, 1507, 3, 202, 101, 0, 1506, 1505, 1, 0, 0, 0, 1506, 1507, 1, 0, 0, 0, 1507, 1508, 1, 0, 0, 0, 1508, 1510, 3, 436, 218, 0, 1509, 1511, 3, 274, 137, 0, 1510, 1509, 1, 0, 0, 0, 1510, 1511, 1, 0, 0, 0, 1511, 201, 1, 0, 0, 0, 1512, 1515, 3, 518, 259, 0, 1513, 1515, 3, 588, 294, 0, 1514, 1512, 1, 0, 0, 0, 1514, 1513, 1, 0, 0, 0, 1515, 203, 1, 0, 0, 0, 1516, 1517, 3, 424, 212, 0, 1517, 1518, 3, 508, 254, 0, 1518, 1519, 3, 374, 187, 0, 1519, 1520, 3, 604, 302, 0, 1520, 1521, 3, 552, 276, 0, 1521, 1522, 5, 19, 0, 0, 1522, 1523, 3, 614, 307, 0, 1523, 1524, 3, 206, 103, 0, 1524, 1528, 3, 616, 308, 0, 1525, 1526, 3, 426, 213, 0, 1526, 1527, 3, 210, 105, 0, 1527, 1529, 1, 0, 0, 0, 1528, 1525, 1, 0, 0, 0, 1528, 1529, 1, 0, 0, 0, 1529, 205, 1, 0, 0, 0, 1530, 1536, 3, 208, 104, 0, 1531, 1532, 3, 626, 313, 0, 1532, 1533, 3, 208, 104, 0, 1533, 1535, 1, 0, 0, 0, 1534, 1531, 1, 0, 0, 0, 1535, 1538, 1, 0, 0, 0, 1536, 1534, 1, 0, 0, 0, 1536, 1537, 1, 0, 0, 0, 1537, 207, 1, 0, 0, 0, 1538, 1536, 1, 0, 0, 0, 1539, 1540, 5, 169, 0, 0, 1540, 1541, 5, 9, 0, 0, 1541, 1546, 5, 169, 0, 0, 1542, 1543, 5, 169, 0, 0, 1543, 1544, 5, 9, 0, 0, 1544, 1546, 5, 170, 0, 0, 1545, 1539, 1, 0, 0, 0, 1545, 1542, 1, 0, 0, 0, 1546, 209, 1, 0, 0, 0, 1547, 1548, 3, 464, 232, 0, 1548, 1549, 5, 19, 0, 0, 1549, 1550, 3, 370, 185, 0, 1550, 211, 1, 0, 0, 0, 1551, 1552, 3, 592, 296, 0, 1552, 1553, 3, 374, 187, 0, 1553, 213, 1, 0, 0, 0, 1554, 1556, 3, 582, 291, 0, 1555, 1557, 3, 572, 286, 0, 1556, 1555, 1, 0, 0, 0, 1556, 1557, 1, 0, 0, 0, 1557, 1558, 1, 0, 0, 0, 1558, 1559, 3, 298, 149, 0, 1559, 215, 1, 0, 0, 0, 1560, 1561, 3, 452, 226, 0, 1561, 1563, 3, 490, 245, 0, 1562, 1564, 3, 276, 138, 0, 1563, 1562, 1, 0, 0, 0, 1563, 1564, 1, 0, 0, 0, 1564, 1566, 1, 0, 0, 0, 1565, 1567, 3, 218, 109, 0, 1566, 1565, 1, 0, 0, 0, 1566, 1567, 1, 0, 0, 0, 1567, 1568, 1, 0, 0, 0, 1568, 1569, 3, 536, 268, 0, 1569, 1570, 3, 298, 149, 0, 1570, 1571, 3, 610, 305, 0, 1571, 1572, 3, 220, 110, 0, 1572, 1573, 3, 612, 306, 0, 1573, 217, 1, 0, 0, 0, 1574, 1577, 5, 174, 0, 0, 1575, 1577, 3, 368, 184, 0, 1576, 1574, 1, 0, 0, 0, 1576, 1575, 1, 0, 0, 0, 1577, 219, 1, 0, 0, 0, 1578, 1583, 3, 378, 189, 0, 1579, 1583, 3, 222, 111, 0, 1580, 1583, 3, 224, 112, 0, 1581, 1583, 3, 226, 113, 0, 1582, 1578, 1, 0, 0, 0, 1582, 1579, 1, 0, 0, 0, 1582, 1580, 1, 0, 0, 0, 1582, 1581, 1, 0, 0, 0, 1583, 221, 1, 0, 0, 0, 1584, 1585, 3, 506, 253, 0, 1585, 1586, 3, 610, 305, 0, 1586, 1587, 5, 174, 0, 0, 1587, 1588, 3, 612, 306, 0, 1588, 223, 1, 0, 0, 0, 1589, 1590, 3, 466, 233, 0, 1590, 1591, 3, 610, 305, 0, 1591, 1592, 5, 174, 0, 0, 1592, 1593, 3, 612, 306, 0, 1593, 225, 1, 0, 0, 0, 1594, 1595, 3, 478, 239, 0, 1595, 1596, 3, 610, 305, 0, 1596, 1597, 5, 174, 0, 0, 1597, 1598, 3, 612, 306, 0, 1598, 227, 1, 0, 0, 0, 1599, 1601, 3, 200, 100, 0, 1600, 1599, 1, 0, 0, 0, 1600, 1601, 1, 0, 0, 0, 1601, 1602, 1, 0, 0, 0, 1602, 1604, 3, 454, 227, 0, 1603, 1605, 3, 230, 115, 0, 1604, 1603, 1, 0, 0, 0, 1604, 1605, 1, 0, 0, 0, 1605, 1606, 1, 0, 0, 0, 1606, 1608, 3, 300, 150, 0, 1607, 1609, 3, 274, 137, 0, 1608, 1607, 1, 0, 0, 0, 1608, 1609, 1, 0, 0, 0, 1609, 1610, 1, 0, 0, 0, 1610, 1613, 3, 306, 153, 0, 1611, 1614, 3, 278, 139, 0, 1612, 1614, 3, 236, 118, 0, 1613, 1611, 1, 0, 0, 0, 1613, 1612, 1, 0, 0, 0, 1613, 1614, 1, 0, 0, 0, 1614, 1616, 1, 0, 0, 0, 1615, 1617, 3, 4, 2, 0, 1616, 1615, 1, 0, 0, 0, 1616, 1617, 1, 0, 0, 0, 1617, 229, 1, 0, 0, 0, 1618, 1624, 3, 232, 116, 0, 1619, 1620, 3, 626, 313, 0, 1620, 1621, 3, 232, 116, 0, 1621, 1623, 1, 0, 0, 0, 1622, 1619, 1, 0, 0, 0, 1623, 1626, 1, 0, 0, 0, 1624, 1622, 1, 0, 0, 0, 1624, 1625, 1, 0, 0, 0, 1625, 231, 1, 0, 0, 0, 1626, 1624, 1, 0, 0, 0, 1627, 1629, 3, 314, 157, 0, 1628, 1630, 3, 320, 160, 0, 1629, 1628, 1, 0, 0, 0, 1629, 1630, 1, 0, 0, 0, 1630, 1636, 1, 0, 0, 0, 1631, 1633, 3, 318, 159, 0, 1632, 1634, 3, 320, 160, 0, 1633, 1632, 1, 0, 0, 0, 1633, 1634, 1, 0, 0, 0, 1634, 1636, 1, 0, 0, 0, 1635, 1627, 1, 0, 0, 0, 1635, 1631, 1, 0, 0, 0, 1636, 233, 1, 0, 0, 0, 1637, 1639, 3, 200, 100, 0, 1638, 1637, 1, 0, 0, 0, 1638, 1639, 1, 0, 0, 0, 1639, 1640, 1, 0, 0, 0, 1640, 1641, 3, 590, 295, 0, 1641, 1643, 3, 298, 149, 0, 1642, 1644, 3, 268, 134, 0, 1643, 1642, 1, 0, 0, 0, 1643, 1644, 1, 0, 0, 0, 1644, 1645, 1, 0, 0, 0, 1645, 1646, 3, 562, 281, 0, 1646, 1647, 3, 242, 121, 0, 1647, 1650, 3, 306, 153, 0, 1648, 1651, 3, 278, 139, 0, 1649, 1651, 3, 236, 118, 0, 1650, 1648, 1, 0, 0, 0, 1650, 1649, 1, 0, 0, 0, 1650, 1651, 1, 0, 0, 0, 1651, 1653, 1, 0, 0, 0, 1652, 1654, 3, 4, 2, 0, 1653, 1652, 1, 0, 0, 0, 1653, 1654, 1, 0, 0, 0, 1654, 235, 1, 0, 0, 0, 1655, 1656, 3, 486, 243, 0, 1656, 1657, 3, 238, 119, 0, 1657, 237, 1, 0, 0, 0, 1658, 1664, 3, 240, 120, 0, 1659, 1660, 3, 426, 213, 0, 1660, 1661, 3, 240, 120, 0, 1661, 1663, 1, 0, 0, 0, 1662, 1659, 1, 0, 0, 0, 1663, 1666, 1, 0, 0, 0, 1664, 1662, 1, 0, 0, 0, 1664, 1665, 1, 0, 0, 0, 1665, 239, 1, 0, 0, 0, 1666, 1664, 1, 0, 0, 0, 1667, 1668, 5, 174, 0, 0, 1668, 1669, 5, 19, 0, 0, 1669, 1670, 3, 362, 181, 0, 1670, 241, 1, 0, 0, 0, 1671, 1677, 3, 244, 122, 0, 1672, 1673, 3, 626, 313, 0, 1673, 1674, 3, 244, 122, 0, 1674, 1676, 1, 0, 0, 0, 1675, 1672, 1, 0, 0, 0, 1676, 1679, 1, 0, 0, 0, 1677, 1675, 1, 0, 0, 0, 1677, 1678, 1, 0, 0, 0, 1678, 243, 1, 0, 0, 0, 1679, 1677, 1, 0, 0, 0, 1680, 1685, 3, 250, 125, 0, 1681, 1685, 3, 248, 124, 0, 1682, 1685, 3, 246, 123, 0, 1683, 1685, 3, 254, 127, 0, 1684, 1680, 1, 0, 0, 0, 1684, 1681, 1, 0, 0, 0, 1684, 1682, 1, 0, 0, 0, 1684, 1683, 1, 0, 0, 0, 1685, 245, 1, 0, 0, 0, 1686, 1687, 3, 378, 189, 0, 1687, 1688, 5, 19, 0, 0, 1688, 1689, 3, 360, 180, 0, 1689, 247, 1, 0, 0, 0, 1690, 1691, 3, 378, 189, 0, 1691, 1692, 5, 19, 0, 0, 1692, 1693, 3, 360, 180, 0, 1693, 1694, 3, 262, 131, 0, 1694, 1695, 5, 174, 0, 0, 1695, 249, 1, 0, 0, 0, 1696, 1697, 3, 378, 189, 0, 1697, 1698, 5, 19, 0, 0, 1698, 1699, 5, 174, 0, 0, 1699, 1700, 3, 262, 131, 0, 1700, 1701, 3, 360, 180, 0, 1701, 251, 1, 0, 0, 0, 1702, 1703, 3, 622, 311, 0, 1703, 1704, 3, 362, 181, 0, 1704, 1705, 3, 624, 312, 0, 1705, 253, 1, 0, 0, 0, 1706, 1707, 3, 378, 189, 0, 1707, 1708, 3, 252, 126, 0, 1708, 1709, 5, 19, 0, 0, 1709, 1710, 3, 362, 181, 0, 1710, 255, 1, 0, 0, 0, 1711, 1721, 3, 614, 307, 0, 1712, 1718, 3, 362, 181, 0, 1713, 1714, 3, 626, 313, 0, 1714, 1715, 3, 362, 181, 0, 1715, 1717, 1, 0, 0, 0, 1716, 1713, 1, 0, 0, 0, 1717, 1720, 1, 0, 0, 0, 1718, 1716, 1, 0, 0, 0, 1718, 1719, 1, 0, 0, 0, 1719, 1722, 1, 0, 0, 0, 1720, 1718, 1, 0, 0, 0, 1721, 1712, 1, 0, 0, 0, 1721, 1722, 1, 0, 0, 0, 1722, 1723, 1, 0, 0, 0, 1723, 1724, 3, 616, 308, 0, 1724, 257, 1, 0, 0, 0, 1725, 1726, 3, 614, 307, 0, 1726, 1727, 3, 362, 181, 0, 1727, 1728, 3, 628, 314, 0, 1728, 1729, 3, 362, 181, 0, 1729, 1737, 1, 0, 0, 0, 1730, 1731, 3, 626, 313, 0, 1731, 1732, 3, 362, 181, 0, 1732, 1733, 3, 628, 314, 0, 1733, 1734, 3, 362, 181, 0, 1734, 1736, 1, 0, 0, 0, 1735, 1730, 1, 0, 0, 0, 1736, 1739, 1, 0, 0, 0, 1737, 1735, 1, 0, 0, 0, 1737, 1738, 1, 0, 0, 0, 1738, 1740, 1, 0, 0, 0, 1739, 1737, 1, 0, 0, 0, 1740, 1741, 3, 616, 308, 0, 1741, 259, 1, 0, 0, 0, 1742, 1752, 3, 622, 311, 0, 1743, 1749, 3, 362, 181, 0, 1744, 1745, 3, 626, 313, 0, 1745, 1746, 3, 362, 181, 0, 1746, 1748, 1, 0, 0, 0, 1747, 1744, 1, 0, 0, 0, 1748, 1751, 1, 0, 0, 0, 1749, 1747, 1, 0, 0, 0, 1749, 1750, 1, 0, 0, 0, 1750, 1753, 1, 0, 0, 0, 1751, 1749, 1, 0, 0, 0, 1752, 1743, 1, 0, 0, 0, 1752, 1753, 1, 0, 0, 0, 1753, 1754, 1, 0, 0, 0, 1754, 1755, 3, 624, 312, 0, 1755, 261, 1, 0, 0, 0, 1756, 1757, 7, 1, 0, 0, 1757, 263, 1, 0, 0, 0, 1758, 1759, 3, 610, 305, 0, 1759, 1765, 3, 288, 144, 0, 1760, 1761, 3, 626, 313, 0, 1761, 1762, 3, 288, 144, 0, 1762, 1764, 1, 0, 0, 0, 1763, 1760, 1, 0, 0, 0, 1764, 1767, 1, 0, 0, 0, 1765, 1763, 1, 0, 0, 0, 1765, 1766, 1, 0, 0, 0, 1766, 1768, 1, 0, 0, 0, 1767, 1765, 1, 0, 0, 0, 1768, 1769, 3, 612, 306, 0, 1769, 265, 1, 0, 0, 0, 1770, 1772, 3, 200, 100, 0, 1771, 1770, 1, 0, 0, 0, 1771, 1772, 1, 0, 0, 0, 1772, 1773, 1, 0, 0, 0, 1773, 1774, 3, 496, 248, 0, 1774, 1775, 3, 498, 249, 0, 1775, 1777, 3, 298, 149, 0, 1776, 1778, 3, 282, 141, 0, 1777, 1776, 1, 0, 0, 0, 1777, 1778, 1, 0, 0, 0, 1778, 1779, 1, 0, 0, 0, 1779, 1781, 3, 280, 140, 0, 1780, 1782, 3, 276, 138, 0, 1781, 1780, 1, 0, 0, 0, 1781, 1782, 1, 0, 0, 0, 1782, 1784, 1, 0, 0, 0, 1783, 1785, 3, 268, 134, 0, 1784, 1783, 1, 0, 0, 0, 1784, 1785, 1, 0, 0, 0, 1785, 1787, 1, 0, 0, 0, 1786, 1788, 3, 4, 2, 0, 1787, 1786, 1, 0, 0, 0, 1787, 1788, 1, 0, 0, 0, 1788, 267, 1, 0, 0, 0, 1789, 1790, 3, 596, 298, 0, 1790, 1791, 3, 272, 136, 0, 1791, 1806, 1, 0, 0, 0, 1792, 1793, 3, 596, 298, 0, 1793, 1794, 3, 272, 136, 0, 1794, 1795, 3, 426, 213, 0, 1795, 1796, 3, 270, 135, 0, 1796, 1806, 1, 0, 0, 0, 1797, 1798, 3, 596, 298, 0, 1798, 1799, 3, 270, 135, 0, 1799, 1806, 1, 0, 0, 0, 1800, 1801, 3, 596, 298, 0, 1801, 1802, 3, 270, 135, 0, 1802, 1803, 3, 426, 213, 0, 1803, 1804, 3, 272, 136, 0, 1804, 1806, 1, 0, 0, 0, 1805, 1789, 1, 0, 0, 0, 1805, 1792, 1, 0, 0, 0, 1805, 1797, 1, 0, 0, 0, 1805, 1800, 1, 0, 0, 0, 1806, 269, 1, 0, 0, 0, 1807, 1810, 3, 576, 288, 0, 1808, 1811, 3, 342, 171, 0, 1809, 1811, 3, 364, 182, 0, 1810, 1808, 1, 0, 0, 0, 1810, 1809, 1, 0, 0, 0, 1811, 271, 1, 0, 0, 0, 1812, 1813, 3, 584, 292, 0, 1813, 1814, 3, 364, 182, 0, 1814, 273, 1, 0, 0, 0, 1815, 1816, 3, 596, 298, 0, 1816, 1817, 3, 270, 135, 0, 1817, 275, 1, 0, 0, 0, 1818, 1819, 3, 486, 243, 0, 1819, 1820, 3, 530, 265, 0, 1820, 1821, 3, 470, 235, 0, 1821, 277, 1, 0, 0, 0, 1822, 1823, 3, 486, 243, 0, 1823, 1824, 3, 470, 235, 0, 1824, 279, 1, 0, 0, 0, 1825, 1826, 3, 598, 299, 0, 1826, 1827, 5, 1, 0, 0, 1827, 1828, 3, 286, 143, 0, 1828, 1829, 5, 2, 0, 0, 1829, 1834, 1, 0, 0, 0, 1830, 1831, 3, 502, 251, 0, 1831, 1832, 3, 362, 181, 0, 1832, 1834, 1, 0, 0, 0, 1833, 1825, 1, 0, 0, 0, 1833, 1830, 1, 0, 0, 0, 1834, 281, 1, 0, 0, 0, 1835, 1836, 5, 1, 0, 0, 1836, 1837, 3, 284, 142, 0, 1837, 1838, 5, 2, 0, 0, 1838, 283, 1, 0, 0, 0, 1839, 1845, 3, 378, 189, 0, 1840, 1841, 3, 626, 313, 0, 1841, 1842, 3, 378, 189, 0, 1842, 1844, 1, 0, 0, 0, 1843, 1840, 1, 0, 0, 0, 1844, 1847, 1, 0, 0, 0, 1845, 1843, 1, 0, 0, 0, 1845, 1846, 1, 0, 0, 0, 1846, 285, 1, 0, 0, 0, 1847, 1845, 1, 0, 0, 0, 1848, 1854, 3, 360, 180, 0, 1849, 1850, 3, 626, 313, 0, 1850, 1851, 3, 360, 180, 0, 1851, 1853, 1, 0, 0, 0, 1852, 1849, 1, 0, 0, 0, 1853, 1856, 1, 0, 0, 0, 1854, 1852, 1, 0, 0, 0, 1854, 1855, 1, 0, 0, 0, 1855, 287, 1, 0, 0, 0, 1856, 1854, 1, 0, 0, 0, 1857, 1864, 3, 362, 181, 0, 1858, 1864, 3, 352, 176, 0, 1859, 1864, 3, 258, 129, 0, 1860, 1864, 3, 256, 128, 0, 1861, 1864, 3, 260, 130, 0, 1862, 1864, 3, 264, 132, 0, 1863, 1857, 1, 0, 0, 0, 1863, 1858, 1, 0, 0, 0, 1863, 1859, 1, 0, 0, 0, 1863, 1860, 1, 0, 0, 0, 1863, 1861, 1, 0, 0, 0, 1863, 1862, 1, 0, 0, 0, 1864, 289, 1, 0, 0, 0, 1865, 1867, 3, 560, 280, 0, 1866, 1868, 3, 308, 154, 0, 1867, 1866, 1, 0, 0, 0, 1867, 1868, 1, 0, 0, 0, 1868, 1870, 1, 0, 0, 0, 1869, 1871, 3, 502, 251, 0, 1870, 1869, 1, 0, 0, 0, 1870, 1871, 1, 0, 0, 0, 1871, 1872, 1, 0, 0, 0, 1872, 1873, 3, 310, 155, 0, 1873, 1875, 3, 300, 150, 0, 1874, 1876, 3, 306, 153, 0, 1875, 1874, 1, 0, 0, 0, 1875, 1876, 1, 0, 0, 0, 1876, 1878, 1, 0, 0, 0, 1877, 1879, 3, 630, 315, 0, 1878, 1877, 1, 0, 0, 0, 1878, 1879, 1, 0, 0, 0, 1879, 1881, 1, 0, 0, 0, 1880, 1882, 3, 302, 151, 0, 1881, 1880, 1, 0, 0, 0, 1881, 1882, 1, 0, 0, 0, 1882, 1884, 1, 0, 0, 0, 1883, 1885, 3, 294, 147, 0, 1884, 1883, 1, 0, 0, 0, 1884, 1885, 1, 0, 0, 0, 1885, 1887, 1, 0, 0, 0, 1886, 1888, 3, 292, 146, 0, 1887, 1886, 1, 0, 0, 0, 1887, 1888, 1, 0, 0, 0, 1888, 1890, 1, 0, 0, 0, 1889, 1891, 3, 4, 2, 0, 1890, 1889, 1, 0, 0, 0, 1890, 1891, 1, 0, 0, 0, 1891, 291, 1, 0, 0, 0, 1892, 1893, 3, 422, 211, 0, 1893, 1894, 3, 472, 236, 0, 1894, 293, 1, 0, 0, 0, 1895, 1898, 3, 514, 257, 0, 1896, 1899, 3, 342, 171, 0, 1897, 1899, 3, 364, 182, 0, 1898, 1896, 1, 0, 0, 0, 1898, 1897, 1, 0, 0, 0, 1899, 295, 1, 0, 0, 0, 1900, 1901, 5, 83, 0, 0, 1901, 297, 1, 0, 0, 0, 1902, 1903, 3, 374, 187, 0, 1903, 1904, 5, 10, 0, 0, 1904, 1906, 1, 0, 0, 0, 1905, 1902, 1, 0, 0, 0, 1905, 1906, 1, 0, 0, 0, 1906, 1907, 1, 0, 0, 0, 1907, 1908, 3, 376, 188, 0, 1908, 299, 1, 0, 0, 0, 1909, 1910, 3, 476, 238, 0, 1910, 1911, 3, 298, 149, 0, 1911, 301, 1, 0, 0, 0, 1912, 1913, 3, 542, 271, 0, 1913, 1914, 3, 442, 221, 0, 1914, 1920, 3, 304, 152, 0, 1915, 1916, 3, 626, 313, 0, 1916, 1917, 3, 304, 152, 0, 1917, 1919, 1, 0, 0, 0, 1918, 1915, 1, 0, 0, 0, 1919, 1922, 1, 0, 0, 0, 1920, 1918, 1, 0, 0, 0, 1920, 1921, 1, 0, 0, 0, 1921, 303, 1, 0, 0, 0, 1922, 1920, 1, 0, 0, 0, 1923, 1926, 5, 174, 0, 0, 1924, 1927, 3, 432, 216, 0, 1925, 1927, 3, 456, 228, 0, 1926, 1924, 1, 0, 0, 0, 1926, 1925, 1, 0, 0, 0, 1926, 1927, 1, 0, 0, 0, 1927, 305, 1, 0, 0, 0, 1928, 1929, 3, 602, 301, 0, 1929, 1930, 3, 322, 161, 0, 1930, 307, 1, 0, 0, 0, 1931, 1932, 3, 460, 230, 0, 1932, 309, 1, 0, 0, 0, 1933, 1936, 5, 11, 0, 0, 1934, 1936, 3, 312, 156, 0, 1935, 1933, 1, 0, 0, 0, 1935, 1934, 1, 0, 0, 0, 1936, 1942, 1, 0, 0, 0, 1937, 1938, 3, 626, 313, 0, 1938, 1939, 3, 312, 156, 0, 1939, 1941, 1, 0, 0, 0, 1940, 1937, 1, 0, 0, 0, 1941, 1944, 1, 0, 0, 0, 1942, 1940, 1, 0, 0, 0, 1942, 1943, 1, 0, 0, 0, 1943, 311, 1, 0, 0, 0, 1944, 1942, 1, 0, 0, 0, 1945, 1947, 3, 314, 157, 0, 1946, 1948, 3, 320, 160, 0, 1947, 1946, 1, 0, 0, 0, 1947, 1948, 1, 0, 0, 0, 1948, 1958, 1, 0, 0, 0, 1949, 1951, 3, 316, 158, 0, 1950, 1952, 3, 320, 160, 0, 1951, 1950, 1, 0, 0, 0, 1951, 1952, 1, 0, 0, 0, 1952, 1958, 1, 0, 0, 0, 1953, 1955, 3, 318, 159, 0, 1954, 1956, 3, 320, 160, 0, 1955, 1954, 1, 0, 0, 0, 1955, 1956, 1, 0, 0, 0, 1956, 1958, 1, 0, 0, 0, 1957, 1945, 1, 0, 0, 0, 1957, 1949, 1, 0, 0, 0, 1957, 1953, 1, 0, 0, 0, 1958, 313, 1, 0, 0, 0, 1959, 1960, 3, 378, 189, 0, 1960, 315, 1, 0, 0, 0, 1961, 1962, 3, 352, 176, 0, 1962, 317, 1, 0, 0, 0, 1963, 1964, 3, 378, 189, 0, 1964, 1965, 3, 622, 311, 0, 1965, 1966, 3, 362, 181, 0, 1966, 1967, 3, 624, 312, 0, 1967, 319, 1, 0, 0, 0, 1968, 1969, 3, 430, 215, 0, 1969, 1970, 5, 174, 0, 0, 1970, 321, 1, 0, 0, 0, 1971, 1977, 3, 324, 162, 0, 1972, 1973, 3, 426, 213, 0, 1973, 1974, 3, 324, 162, 0, 1974, 1976, 1, 0, 0, 0, 1975, 1972, 1, 0, 0, 0, 1976, 1979, 1, 0, 0, 0, 1977, 1975, 1, 0, 0, 0, 1977, 1978, 1, 0, 0, 0, 1978, 323, 1, 0, 0, 0, 1979, 1977, 1, 0, 0, 0, 1980, 2050, 3, 338, 169, 0, 1981, 2050, 3, 340, 170, 0, 1982, 2050, 3, 336, 168, 0, 1983, 2050, 3, 328, 164, 0, 1984, 2050, 3, 330, 165, 0, 1985, 2050, 3, 332, 166, 0, 1986, 2050, 3, 334, 167, 0, 1987, 2050, 3, 350, 175, 0, 1988, 2050, 3, 348, 174, 0, 1989, 2050, 3, 346, 173, 0, 1990, 1991, 5, 174, 0, 0, 1991, 1992, 5, 10, 0, 0, 1992, 1993, 5, 174, 0, 0, 1993, 1994, 3, 296, 148, 0, 1994, 1995, 3, 362, 181, 0, 1995, 2050, 1, 0, 0, 0, 1996, 1997, 5, 174, 0, 0, 1997, 1998, 5, 10, 0, 0, 1998, 1999, 5, 174, 0, 0, 1999, 2000, 3, 438, 219, 0, 2000, 2001, 3, 362, 181, 0, 2001, 2002, 3, 426, 213, 0, 2002, 2003, 3, 362, 181, 0, 2003, 2050, 1, 0, 0, 0, 2004, 2005, 5, 1, 0, 0, 2005, 2011, 5, 174, 0, 0, 2006, 2007, 3, 626, 313, 0, 2007, 2008, 5, 174, 0, 0, 2008, 2010, 1, 0, 0, 0, 2009, 2006, 1, 0, 0, 0, 2010, 2013, 1, 0, 0, 0, 2011, 2009, 1, 0, 0, 0, 2011, 2012, 1, 0, 0, 0, 2012, 2014, 1, 0, 0, 0, 2013, 2011, 1, 0, 0, 0, 2014, 2015, 5, 2, 0, 0, 2015, 2016, 3, 488, 244, 0, 2016, 2017, 5, 1, 0, 0, 2017, 2023, 3, 264, 132, 0, 2018, 2019, 3, 626, 313, 0, 2019, 2020, 3, 264, 132, 0, 2020, 2022, 1, 0, 0, 0, 2021, 2018, 1, 0, 0, 0, 2022, 2025, 1, 0, 0, 0, 2023, 2021, 1, 0, 0, 0, 2023, 2024, 1, 0, 0, 0, 2024, 2026, 1, 0, 0, 0, 2025, 2023, 1, 0, 0, 0, 2026, 2027, 5, 2, 0, 0, 2027, 2050, 1, 0, 0, 0, 2028, 2029, 5, 1, 0, 0, 2029, 2035, 5, 174, 0, 0, 2030, 2031, 3, 626, 313, 0, 2031, 2032, 5, 174, 0, 0, 2032, 2034, 1, 0, 0, 0, 2033, 2030, 1, 0, 0, 0, 2034, 2037, 1, 0, 0, 0, 2035, 2033, 1, 0, 0, 0, 2035, 2036, 1, 0, 0, 0, 2036, 2038, 1, 0, 0, 0, 2037, 2035, 1, 0, 0, 0, 2038, 2039, 5, 2, 0, 0, 2039, 2040, 3, 326, 163, 0, 2040, 2046, 3, 264, 132, 0, 2041, 2042, 3, 626, 313, 0, 2042, 2043, 3, 264, 132, 0, 2043, 2045, 1, 0, 0, 0, 2044, 2041, 1, 0, 0, 0, 2045, 2048, 1, 0, 0, 0, 2046, 2044, 1, 0, 0, 0, 2046, 2047, 1, 0, 0, 0, 2047, 2050, 1, 0, 0, 0, 2048, 2046, 1, 0, 0, 0, 2049, 1980, 1, 0, 0, 0, 2049, 1981, 1, 0, 0, 0, 2049, 1982, 1, 0, 0, 0, 2049, 1983, 1, 0, 0, 0, 2049, 1984, 1, 0, 0, 0, 2049, 1985, 1, 0, 0, 0, 2049, 1986, 1, 0, 0, 0, 2049, 1987, 1, 0, 0, 0, 2049, 1988, 1, 0, 0, 0, 2049, 1989, 1, 0, 0, 0, 2049, 1990, 1, 0, 0, 0, 2049, 1996, 1, 0, 0, 0, 2049, 2004, 1, 0, 0, 0, 2049, 2028, 1, 0, 0, 0, 2050, 325, 1, 0, 0, 0, 2051, 2052, 7, 2, 0, 0, 2052, 327, 1, 0, 0, 0, 2053, 2054, 3, 352, 176, 0, 2054, 2055, 3, 326, 163, 0, 2055, 2056, 3, 362, 181, 0, 2056, 329, 1, 0, 0, 0, 2057, 2058, 3, 352, 176, 0, 2058, 2059, 3, 326, 163, 0, 2059, 2060, 3, 352, 176, 0, 2060, 331, 1, 0, 0, 0, 2061, 2062, 3, 378, 189, 0, 2062, 2063, 3, 326, 163, 0, 2063, 2064, 3, 352, 176, 0, 2064, 333, 1, 0, 0, 0, 2065, 2066, 3, 352, 176, 0, 2066, 2067, 3, 326, 163, 0, 2067, 2068, 3, 378, 189, 0, 2068, 335, 1, 0, 0, 0, 2069, 2070, 3, 378, 189, 0, 2070, 2071, 3, 438, 219, 0, 2071, 2072, 3, 360, 180, 0, 2072, 2073, 3, 426, 213, 0, 2073, 2074, 3, 360, 180, 0, 2074, 337, 1, 0, 0, 0, 2075, 2076, 3, 378, 189, 0, 2076, 2077, 3, 326, 163, 0, 2077, 2078, 3, 362, 181, 0, 2078, 339, 1, 0, 0, 0, 2079, 2080, 3, 378, 189, 0, 2080, 2081, 3, 296, 148, 0, 2081, 2082, 3, 362, 181, 0, 2082, 341, 1, 0, 0, 0, 2083, 2084, 7, 3, 0, 0, 2084, 343, 1, 0, 0, 0, 2085, 2091, 3, 342, 171, 0, 2086, 2087, 5, 1, 0, 0, 2087, 2088, 3, 356, 178, 0, 2088, 2089, 5, 2, 0, 0, 2089, 2091, 1, 0, 0, 0, 2090, 2085, 1, 0, 0, 0, 2090, 2086, 1, 0, 0, 0, 2091, 345, 1, 0, 0, 0, 2092, 2093, 3, 378, 189, 0, 2093, 2094, 3, 488, 244, 0, 2094, 2095, 3, 344, 172, 0, 2095, 347, 1, 0, 0, 0, 2096, 2097, 3, 378, 189, 0, 2097, 2098, 3, 450, 225, 0, 2098, 2099, 3, 362, 181, 0, 2099, 349, 1, 0, 0, 0, 2100, 2101, 3, 378, 189, 0, 2101, 2102, 3, 450, 225, 0, 2102, 2103, 3, 504, 252, 0, 2103, 2104, 1, 0, 0, 0, 2104, 2105, 3, 362, 181, 0, 2105, 351, 1, 0, 0, 0, 2106, 2107, 3, 354, 177, 0, 2107, 2109, 5, 1, 0, 0, 2108, 2110, 3, 356, 178, 0, 2109, 2108, 1, 0, 0, 0, 2109, 2110, 1, 0, 0, 0, 2110, 2111, 1, 0, 0, 0, 2111, 2112, 5, 2, 0, 0, 2112, 353, 1, 0, 0, 0, 2113, 2114, 7, 4, 0, 0, 2114, 355, 1, 0, 0, 0, 2115, 2121, 3, 358, 179, 0, 2116, 2117, 3, 626, 313, 0, 2117, 2118, 3, 358, 179, 0, 2118, 2120, 1, 0, 0, 0, 2119, 2116, 1, 0, 0, 0, 2120, 2123, 1, 0, 0, 0, 2121, 2119, 1, 0, 0, 0, 2121, 2122, 1, 0, 0, 0, 2122, 357, 1, 0, 0, 0, 2123, 2121, 1, 0, 0, 0, 2124, 2128, 3, 360, 180, 0, 2125, 2128, 3, 378, 189, 0, 2126, 2128, 5, 11, 0, 0, 2127, 2124, 1, 0, 0, 0, 2127, 2125, 1, 0, 0, 0, 2127, 2126, 1, 0, 0, 0, 2128, 359, 1, 0, 0, 0, 2129, 2137, 3, 342, 171, 0, 2130, 2137, 3, 362, 181, 0, 2131, 2137, 3, 352, 176, 0, 2132, 2137, 3, 258, 129, 0, 2133, 2137, 3, 256, 128, 0, 2134, 2137, 3, 260, 130, 0, 2135, 2137, 3, 264, 132, 0, 2136, 2129, 1, 0, 0, 0, 2136, 2130, 1, 0, 0, 0, 2136, 2131, 1, 0, 0, 0, 2136, 2132, 1, 0, 0, 0, 2136, 2133, 1, 0, 0, 0, 2136, 2134, 1, 0, 0, 0, 2136, 2135, 1, 0, 0, 0, 2137, 361, 1, 0, 0, 0, 2138, 2148, 3, 342, 171, 0, 2139, 2148, 3, 532, 266, 0, 2140, 2148, 5, 175, 0, 0, 2141, 2148, 3, 368, 184, 0, 2142, 2148, 3, 364, 182, 0, 2143, 2148, 3, 366, 183, 0, 2144, 2148, 3, 372, 186, 0, 2145, 2148, 3, 370, 185, 0, 2146, 2148, 3, 58, 29, 0, 2147, 2138, 1, 0, 0, 0, 2147, 2139, 1, 0, 0, 0, 2147, 2140, 1, 0, 0, 0, 2147, 2141, 1, 0, 0, 0, 2147, 2142, 1, 0, 0, 0, 2147, 2143, 1, 0, 0, 0, 2147, 2144, 1, 0, 0, 0, 2147, 2145, 1, 0, 0, 0, 2147, 2146, 1, 0, 0, 0, 2148, 363, 1, 0, 0, 0, 2149, 2150, 5, 170, 0, 0, 2150, 365, 1, 0, 0, 0, 2151, 2152, 7, 5, 0, 0, 2152, 367, 1, 0, 0, 0, 2153, 2154, 5, 169, 0, 0, 2154, 369, 1, 0, 0, 0, 2155, 2156, 7, 6, 0, 0, 2156, 371, 1, 0, 0, 0, 2157, 2158, 5, 172, 0, 0, 2158, 373, 1, 0, 0, 0, 2159, 2164, 5, 174, 0, 0, 2160, 2161, 5, 17, 0, 0, 2161, 2162, 5, 174, 0, 0, 2162, 2164, 5, 17, 0, 0, 2163, 2159, 1, 0, 0, 0, 2163, 2160, 1, 0, 0, 0, 2164, 375, 1, 0, 0, 0, 2165, 2173, 5, 174, 0, 0, 2166, 2173, 5, 79, 0, 0, 2167, 2173, 5, 125, 0, 0, 2168, 2173, 5, 63, 0, 0, 2169, 2170, 5, 17, 0, 0, 2170, 2171, 5, 174, 0, 0, 2171, 2173, 5, 17, 0, 0, 2172, 2165, 1, 0, 0, 0, 2172, 2166, 1, 0, 0, 0, 2172, 2167, 1, 0, 0, 0, 2172, 2168, 1, 0, 0, 0, 2172, 2169, 1, 0, 0, 0, 2173, 377, 1, 0, 0, 0, 2174, 2181, 5, 174, 0, 0, 2175, 2181, 3, 586, 293, 0, 2176, 2181, 5, 76, 0, 0, 2177, 2178, 5, 17, 0, 0, 2178, 2179, 5, 174, 0, 0, 2179, 2181, 5, 17, 0, 0, 2180, 2174, 1, 0, 0, 0, 2180, 2175, 1, 0, 0, 0, 2180, 2176, 1, 0, 0, 0, 2180, 2177, 1, 0, 0, 0, 2181, 379, 1, 0, 0, 0, 2182, 2184, 3, 382, 191, 0, 2183, 2185, 3, 384, 192, 0, 2184, 2183, 1, 0, 0, 0, 2184, 2185, 1, 0, 0, 0, 2185, 381, 1, 0, 0, 0, 2186, 2187, 7, 7, 0, 0, 2187, 383, 1, 0, 0, 0, 2188, 2189, 3, 618, 309, 0, 2189, 2195, 3, 380, 190, 0, 2190, 2191, 3, 626, 313, 0, 2191, 2192, 3, 380, 190, 0, 2192, 2194, 1, 0, 0, 0, 2193, 2190, 1, 0, 0, 0, 2194, 2197, 1, 0, 0, 0, 2195, 2193, 1, 0, 0, 0, 2195, 2196, 1, 0, 0, 0, 2196, 2198, 1, 0, 0, 0, 2197, 2195, 1, 0, 0, 0, 2198, 2199, 3, 620, 310, 0, 2199, 385, 1, 0, 0, 0, 2200, 2203, 3, 432, 216, 0, 2201, 2203, 3, 456, 228, 0, 2202, 2200, 1, 0, 0, 0, 2202, 2201, 1, 0, 0, 0, 2203, 387, 1, 0, 0, 0, 2204, 2205, 5, 174, 0, 0, 2205, 389, 1, 0, 0, 0, 2206, 2207, 5, 174, 0, 0, 2207, 391, 1, 0, 0, 0, 2208, 2209, 3, 368, 184, 0, 2209, 393, 1, 0, 0, 0, 2210, 2211, 5, 174, 0, 0, 2211, 395, 1, 0, 0, 0, 2212, 2213, 5, 174, 0, 0, 2213, 397, 1, 0, 0, 0, 2214, 2215, 5, 174, 0, 0, 2215, 399, 1, 0, 0, 0, 2216, 2217, 5, 174, 0, 0, 2217, 401, 1, 0, 0, 0, 2218, 2219, 5, 174, 0, 0, 2219, 403, 1, 0, 0, 0, 2220, 2221, 5, 174, 0, 0, 2221, 405, 1, 0, 0, 0, 2222, 2223, 3, 368, 184, 0, 2223, 407, 1, 0, 0, 0, 2224, 2225, 5, 174, 0, 0, 2225, 409, 1, 0, 0, 0, 2226, 2227, 3, 412, 206, 0, 2227, 2228, 3, 380, 190, 0, 2228, 411, 1, 0, 0, 0, 2229, 2230, 7, 8, 0, 0, 2230, 413, 1, 0, 0, 0, 2231, 2232, 5, 24, 0, 0, 2232, 415, 1, 0, 0, 0, 2233, 2234, 5, 25, 0, 0, 2234, 417, 1, 0, 0, 0, 2235, 2236, 5, 26, 0, 0, 2236, 419, 1, 0, 0, 0, 2237, 2238, 5, 26, 0, 0, 2238, 2239, 5, 106, 0, 0, 2239, 421, 1, 0, 0, 0, 2240, 2241, 5, 27, 0, 0, 2241, 423, 1, 0, 0, 0, 2242, 2243, 5, 28, 0, 0, 2243, 425, 1, 0, 0, 0, 2244, 2245, 5, 29, 0, 0, 2245, 427, 1, 0, 0, 0, 2246, 2247, 5, 31, 0, 0, 2247, 429, 1, 0, 0, 0, 2248, 2249, 5, 32, 0, 0, 2249, 431, 1, 0, 0, 0, 2250, 2251, 5, 33, 0, 0, 2251, 433, 1, 0, 0, 0, 2252, 2253, 5, 34, 0, 0, 2253, 435, 1, 0, 0, 0, 2254, 2255, 5, 35, 0, 0, 2255, 437, 1, 0, 0, 0, 2256, 2257, 5, 37, 0, 0, 2257, 439, 1, 0, 0, 0, 2258, 2259, 5, 36, 0, 0, 2259, 441, 1, 0, 0, 0, 2260, 2261, 5, 38, 0, 0, 2261, 443, 1, 0, 0, 0, 2262, 2263, 5, 39, 0, 0, 2263, 445, 1, 0, 0, 0, 2264, 2265, 5, 40, 0, 0, 2265, 447, 1, 0, 0, 0, 2266, 2267, 5, 42, 0, 0, 2267, 449, 1, 0, 0, 0, 2268, 2269, 5, 44, 0, 0, 2269, 451, 1, 0, 0, 0, 2270, 2271, 5, 45, 0, 0, 2271, 453, 1, 0, 0, 0, 2272, 2273, 5, 47, 0, 0, 2273, 455, 1, 0, 0, 0, 2274, 2275, 5, 48, 0, 0, 2275, 457, 1, 0, 0, 0, 2276, 2277, 5, 49, 0, 0, 2277, 459, 1, 0, 0, 0, 2278, 2279, 5, 50, 0, 0, 2279, 461, 1, 0, 0, 0, 2280, 2281, 5, 51, 0, 0, 2281, 463, 1, 0, 0, 0, 2282, 2283, 5, 52, 0, 0, 2283, 465, 1, 0, 0, 0, 2284, 2285, 5, 54, 0, 0, 2285, 467, 1, 0, 0, 0, 2286, 2287, 5, 55, 0, 0, 2287, 469, 1, 0, 0, 0, 2288, 2289, 5, 56, 0, 0, 2289, 471, 1, 0, 0, 0, 2290, 2291, 5, 58, 0, 0, 2291, 473, 1, 0, 0, 0, 2292, 2293, 5, 59, 0, 0, 2293, 475, 1, 0, 0, 0, 2294, 2295, 5, 60, 0, 0, 2295, 477, 1, 0, 0, 0, 2296, 2297, 5, 61, 0, 0, 2297, 479, 1, 0, 0, 0, 2298, 2299, 5, 62, 0, 0, 2299, 481, 1, 0, 0, 0, 2300, 2301, 5, 63, 0, 0, 2301, 483, 1, 0, 0, 0, 2302, 2303, 5, 64, 0, 0, 2303, 485, 1, 0, 0, 0, 2304, 2305, 5, 66, 0, 0, 2305, 487, 1, 0, 0, 0, 2306, 2307, 5, 67, 0, 0, 2307, 489, 1, 0, 0, 0, 2308, 2309, 5, 68, 0, 0, 2309, 491, 1, 0, 0, 0, 2310, 2311, 5, 70, 0, 0, 2311, 493, 1, 0, 0, 0, 2312, 2313, 5, 71, 0, 0, 2313, 495, 1, 0, 0, 0, 2314, 2315, 5, 72, 0, 0, 2315, 497, 1, 0, 0, 0, 2316, 2317, 5, 73, 0, 0, 2317, 499, 1, 0, 0, 0, 2318, 2319, 5, 74, 0, 0, 2319, 501, 1, 0, 0, 0, 2320, 2321, 5, 75, 0, 0, 2321, 503, 1, 0, 0, 0, 2322, 2323, 5, 76, 0, 0, 2323, 505, 1, 0, 0, 0, 2324, 2325, 5, 77, 0, 0, 2325, 507, 1, 0, 0, 0, 2326, 2327, 5, 78, 0, 0, 2327, 509, 1, 0, 0, 0, 2328, 2329, 5, 79, 0, 0, 2329, 511, 1, 0, 0, 0, 2330, 2331, 5, 80, 0, 0, 2331, 513, 1, 0, 0, 0, 2332, 2333, 5, 82, 0, 0, 2333, 515, 1, 0, 0, 0, 2334, 2335, 5, 84, 0, 0, 2335, 517, 1, 0, 0, 0, 2336, 2337, 5, 87, 0, 0, 2337, 519, 1, 0, 0, 0, 2338, 2339, 5, 88, 0, 0, 2339, 521, 1, 0, 0, 0, 2340, 2341, 5, 89, 0, 0, 2341, 523, 1, 0, 0, 0, 2342, 2343, 5, 90, 0, 0, 2343, 525, 1, 0, 0, 0, 2344, 2345, 5, 93, 0, 0, 2345, 527, 1, 0, 0, 0, 2346, 2347, 5, 92, 0, 0, 2347, 529, 1, 0, 0, 0, 2348, 2349, 5, 94, 0, 0, 2349, 531, 1, 0, 0, 0, 2350, 2351, 5, 95, 0, 0, 2351, 533, 1, 0, 0, 0, 2352, 2353, 5, 96, 0, 0, 2353, 535, 1, 0, 0, 0, 2354, 2355, 5, 97, 0, 0, 2355, 537, 1, 0, 0, 0, 2356, 2357, 5, 99, 0, 0, 2357, 539, 1, 0, 0, 0, 2358, 2359, 5, 100, 0, 0, 2359, 541, 1, 0, 0, 0, 2360, 2361, 5, 101, 0, 0, 2361, 543, 1, 0, 0, 0, 2362, 2363, 5, 103, 0, 0, 2363, 545, 1, 0, 0, 0, 2364, 2365, 5, 107, 0, 0, 2365, 547, 1, 0, 0, 0, 2366, 2367, 5, 109, 0, 0, 2367, 549, 1, 0, 0, 0, 2368, 2369, 5, 110, 0, 0, 2369, 551, 1, 0, 0, 0, 2370, 2371, 5, 111, 0, 0, 2371, 553, 1, 0, 0, 0, 2372, 2373, 5, 112, 0, 0, 2373, 555, 1, 0, 0, 0, 2374, 2375, 5, 114, 0, 0, 2375, 557, 1, 0, 0, 0, 2376, 2377, 5, 115, 0, 0, 2377, 559, 1, 0, 0, 0, 2378, 2379, 5, 117, 0, 0, 2379, 561, 1, 0, 0, 0, 2380, 2381, 5, 118, 0, 0, 2381, 563, 1, 0, 0, 0, 2382, 2383, 5, 119, 0, 0, 2383, 565, 1, 0, 0, 0, 2384, 2385, 5, 121, 0, 0, 2385, 567, 1, 0, 0, 0, 2386, 2387, 5, 122, 0, 0, 2387, 569, 1, 0, 0, 0, 2388, 2389, 5, 123, 0, 0, 2389, 571, 1, 0, 0, 0, 2390, 2391, 5, 124, 0, 0, 2391, 573, 1, 0, 0, 0, 2392, 2393, 5, 125, 0, 0, 2393, 575, 1, 0, 0, 0, 2394, 2395, 5, 127, 0, 0, 2395, 577, 1, 0, 0, 0, 2396, 2397, 5, 128, 0, 0, 2397, 579, 1, 0, 0, 0, 2398, 2399, 5, 130, 0, 0, 2399, 581, 1, 0, 0, 0, 2400, 2401, 5, 132, 0, 0, 2401, 583, 1, 0, 0, 0, 2402, 2403, 5, 133, 0, 0, 2403, 585, 1, 0, 0, 0, 2404, 2405, 5, 135, 0, 0, 2405, 587, 1, 0, 0, 0, 2406, 2407, 5, 136, 0, 0, 2407, 589, 1, 0, 0, 0, 2408, 2409, 5, 137, 0, 0, 2409, 591, 1, 0, 0, 0, 2410, 2411, 5, 138, 0, 0, 2411, 593, 1, 0, 0, 0, 2412, 2413, 5, 139, 0, 0, 2413, 595, 1, 0, 0, 0, 2414, 2415, 5, 140, 0, 0, 2415, 597, 1, 0, 0, 0, 2416, 2417, 5, 142, 0, 0, 2417, 599, 1, 0, 0, 0, 2418, 2419, 5, 143, 0, 0, 2419, 601, 1, 0, 0, 0, 2420, 2421, 5, 144, 0, 0, 2421, 603, 1, 0, 0, 0, 2422, 2423, 5, 145, 0, 0, 2423, 605, 1, 0, 0, 0, 2424, 2425, 5, 113, 0, 0, 2425, 607, 1, 0, 0, 0, 2426, 2427, 5, 65, 0, 0, 2427, 609, 1, 0, 0, 0, 2428, 2429, 5, 1, 0, 0, 2429, 611, 1, 0, 0, 0, 2430, 2431, 5, 2, 0, 0, 2431, 613, 1, 0, 0, 0, 2432, 2433, 5, 3, 0, 0, 2433, 615, 1, 0, 0, 0, 2434, 2435, 5, 4, 0, 0, 2435, 617, 1, 0, 0, 0, 2436, 2437, 5, 20, 0, 0, 2437, 619, 1, 0, 0, 0, 2438, 2439, 5, 21, 0, 0, 2439, 621, 1, 0, 0, 0, 2440, 2441, 5, 5, 0, 0, 2441, 623, 1, 0, 0, 0, 2442, 2443, 5, 6, 0, 0, 2443, 625, 1, 0, 0, 0, 2444, 2445, 5, 7, 0, 0, 2445, 627, 1, 0, 0, 0, 2446, 2447, 5, 9, 0, 0, 2447, 629, 1, 0, 0, 0, 2448, 2449, 3, 608, 304, 0, 2449, 2450, 3, 442, 221, 0, 2450, 2456, 3, 632, 316, 0, 2451, 2452, 3, 626, 313, 0, 2452, 2453, 3, 632, 316, 0, 2453, 2455, 1, 0, 0, 0, 2454, 2451, 1, 0, 0, 0, 2455, 2458, 1, 0, 0, 0, 2456, 2454, 1, 0, 0, 0, 2456, 2457, 1, 0, 0, 0, 2457, 631, 1, 0, 0, 0, 2458, 2456, 1, 0, 0, 0, 2459, 2460, 5, 174, 0, 0, 2460, 633, 1, 0, 0, 0, 180, 637, 640, 646, 651, 653, 658, 661, 664, 708, 712, 720, 727, 732, 748, 751, 758, 763, 774, 784, 799, 810, 819, 824, 832, 837, 841, 846, 851, 866, 872, 877, 887, 892, 909, 916, 924, 938, 943, 955, 959, 963, 968, 973, 992, 999, 1007, 1011, 1016, 1035, 1044, 1059, 1061, 1073, 1087, 1094, 1101, 1109, 1120, 1136, 1155, 1178, 1190, 1206, 1216, 1225, 1244, 1252, 1258, 1263, 1270, 1275, 1283, 1288, 1295, 1300, 1307, 1312, 1319, 1328, 1335, 1342, 1349, 1354, 1361, 1368, 1372, 1375, 1383, 1393, 1404, 1410, 1419, 1432, 1440, 1446, 1451, 1465, 1485, 1494, 1506, 1510, 1514, 1528, 1536, 1545, 1556, 1563, 1566, 1576, 1582, 1600, 1604, 1608, 1613, 1616, 1624, 1629, 1633, 1635, 1638, 1643, 1650, 1653, 1664, 1677, 1684, 1718, 1721, 1737, 1749, 1752, 1765, 1771, 1777, 1781, 1784, 1787, 1805, 1810, 1833, 1845, 1854, 1863, 1867, 1870, 1875, 1878, 1881, 1884, 1887, 1890, 1898, 1905, 1920, 1926, 1935, 1942, 1947, 1951, 1955, 1957, 1977, 2011, 2023, 2035, 2046, 2049, 2090, 2109, 2121, 2127, 2136, 2147, 2163, 2172, 2180, 2184, 2195, 2202, 2456] \ No newline at end of file diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/cql_parser.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/cql_parser.go index 969b3dfa..f5c0340d 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/cql_parser.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/cql_parser.go @@ -131,11 +131,12 @@ func cqlparserParserInit() { "distinctSpec", "selectElements", "selectElement", "selectColumn", "selectFunction", "selectIndex", "asSpec", "relationElements", "relationElement", "compareOperator", "relationFunctionCompareConstant", "relationFunctionCompareFunction", - "relationBetween", "relationCompare", "relationLike", "marker", "tupleValue", - "relationIn", "relationContains", "relationContainsKey", "functionCall", - "functionArgs", "valueAny", "constant", "decimalLiteral", "floatLiteral", - "stringLiteral", "booleanLiteral", "hexadecimalLiteral", "keyspace", - "table", "column", "dataType", "dataTypeName", "dataTypeDefinition", + "relationColumnCompareFunction", "relationFunctionCompareColumn", "relationBetween", + "relationCompare", "relationLike", "marker", "tupleValue", "relationIn", + "relationContains", "relationContainsKey", "functionCall", "functionName", + "functionArgs", "functionArg", "valueAny", "constant", "decimalLiteral", + "floatLiteral", "stringLiteral", "booleanLiteral", "hexadecimalLiteral", + "keyspace", "table", "column", "dataType", "dataTypeName", "dataTypeDefinition", "orderDirection", "role", "trigger", "triggerClass", "materializedView", "type_", "aggregate", "function_", "language", "user", "password", "hashKey", "param", "paramName", "kwAdd", "kwAggregate", "kwAll", "kwAllPermissions", @@ -160,7 +161,7 @@ func cqlparserParserInit() { } staticData.PredictionContextCache = antlr.NewPredictionContextCache() staticData.serializedATN = []int32{ - 4, 1, 181, 2458, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, + 4, 1, 181, 2462, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, @@ -226,1076 +227,1076 @@ func cqlparserParserInit() { 297, 2, 298, 7, 298, 2, 299, 7, 299, 2, 300, 7, 300, 2, 301, 7, 301, 2, 302, 7, 302, 2, 303, 7, 303, 2, 304, 7, 304, 2, 305, 7, 305, 2, 306, 7, 306, 2, 307, 7, 307, 2, 308, 7, 308, 2, 309, 7, 309, 2, 310, 7, 310, 2, - 311, 7, 311, 2, 312, 7, 312, 1, 0, 4, 0, 628, 8, 0, 11, 0, 12, 0, 629, - 1, 0, 3, 0, 633, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 639, 8, 1, 1, 1, 1, - 1, 1, 1, 5, 1, 644, 8, 1, 10, 1, 12, 1, 647, 9, 1, 1, 1, 1, 1, 3, 1, 651, - 8, 1, 1, 1, 3, 1, 654, 8, 1, 1, 1, 3, 1, 657, 8, 1, 1, 2, 1, 2, 1, 3, 1, - 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, + 311, 7, 311, 2, 312, 7, 312, 2, 313, 7, 313, 2, 314, 7, 314, 2, 315, 7, + 315, 2, 316, 7, 316, 1, 0, 4, 0, 636, 8, 0, 11, 0, 12, 0, 637, 1, 0, 3, + 0, 641, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 647, 8, 1, 1, 1, 1, 1, 1, 1, + 5, 1, 652, 8, 1, 10, 1, 12, 1, 655, 9, 1, 1, 1, 1, 1, 3, 1, 659, 8, 1, + 1, 1, 3, 1, 662, 8, 1, 1, 1, 3, 1, 665, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, - 4, 1, 4, 1, 4, 3, 4, 701, 8, 4, 1, 5, 1, 5, 3, 5, 705, 8, 5, 1, 5, 1, 5, - 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 713, 8, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, - 3, 9, 720, 8, 9, 1, 9, 1, 9, 1, 10, 3, 10, 725, 8, 10, 1, 10, 1, 10, 1, - 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, - 1, 12, 3, 12, 741, 8, 12, 1, 12, 3, 12, 744, 8, 12, 1, 13, 1, 13, 1, 13, - 1, 13, 1, 13, 3, 13, 751, 8, 13, 1, 13, 1, 13, 1, 13, 3, 13, 756, 8, 13, - 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 3, 15, 767, - 8, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 777, + 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, + 4, 1, 4, 3, 4, 709, 8, 4, 1, 5, 1, 5, 3, 5, 713, 8, 5, 1, 5, 1, 5, 1, 6, + 1, 6, 1, 6, 1, 6, 3, 6, 721, 8, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 3, 9, + 728, 8, 9, 1, 9, 1, 9, 1, 10, 3, 10, 733, 8, 10, 1, 10, 1, 10, 1, 11, 1, + 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, + 3, 12, 749, 8, 12, 1, 12, 3, 12, 752, 8, 12, 1, 13, 1, 13, 1, 13, 1, 13, + 1, 13, 3, 13, 759, 8, 13, 1, 13, 1, 13, 1, 13, 3, 13, 764, 8, 13, 1, 14, + 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 3, 15, 775, 8, + 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 785, 8, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, - 16, 1, 16, 1, 16, 1, 16, 3, 16, 792, 8, 16, 1, 16, 1, 16, 1, 16, 1, 16, - 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 803, 8, 16, 1, 16, 1, 16, 1, - 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 812, 8, 16, 1, 17, 1, 17, 1, 17, - 3, 17, 817, 8, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 3, 17, 825, - 8, 17, 1, 18, 1, 18, 1, 18, 3, 18, 830, 8, 18, 1, 18, 1, 18, 3, 18, 834, - 8, 18, 1, 19, 1, 19, 1, 19, 3, 19, 839, 8, 19, 1, 19, 1, 19, 1, 19, 3, - 19, 844, 8, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, - 1, 20, 1, 20, 1, 20, 5, 20, 857, 8, 20, 10, 20, 12, 20, 860, 9, 20, 1, - 21, 1, 21, 1, 21, 3, 21, 865, 8, 21, 1, 21, 1, 21, 1, 21, 3, 21, 870, 8, - 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 880, - 8, 22, 1, 22, 1, 22, 1, 22, 3, 22, 885, 8, 22, 1, 22, 1, 22, 1, 22, 1, + 16, 1, 16, 1, 16, 1, 16, 3, 16, 800, 8, 16, 1, 16, 1, 16, 1, 16, 1, 16, + 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 811, 8, 16, 1, 16, 1, 16, 1, + 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 820, 8, 16, 1, 17, 1, 17, 1, 17, + 3, 17, 825, 8, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 3, 17, 833, + 8, 17, 1, 18, 1, 18, 1, 18, 3, 18, 838, 8, 18, 1, 18, 1, 18, 3, 18, 842, + 8, 18, 1, 19, 1, 19, 1, 19, 3, 19, 847, 8, 19, 1, 19, 1, 19, 1, 19, 3, + 19, 852, 8, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, + 1, 20, 1, 20, 1, 20, 5, 20, 865, 8, 20, 10, 20, 12, 20, 868, 9, 20, 1, + 21, 1, 21, 1, 21, 3, 21, 873, 8, 21, 1, 21, 1, 21, 1, 21, 3, 21, 878, 8, + 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 888, + 8, 22, 1, 22, 1, 22, 1, 22, 3, 22, 893, 8, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, - 1, 22, 3, 22, 902, 8, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 909, - 8, 23, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 915, 8, 24, 10, 24, 12, 24, 918, + 1, 22, 3, 22, 910, 8, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 917, + 8, 23, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 923, 8, 24, 10, 24, 12, 24, 926, 9, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, - 26, 1, 26, 3, 26, 931, 8, 26, 1, 27, 1, 27, 1, 27, 3, 27, 936, 8, 27, 1, + 26, 1, 26, 3, 26, 939, 8, 26, 1, 27, 1, 27, 1, 27, 3, 27, 944, 8, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 3, 27, - 948, 8, 27, 1, 28, 1, 28, 3, 28, 952, 8, 28, 1, 28, 1, 28, 3, 28, 956, - 8, 28, 1, 28, 1, 28, 1, 28, 3, 28, 961, 8, 28, 1, 28, 1, 28, 1, 28, 3, - 28, 966, 8, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, - 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 5, 30, 983, 8, 30, 10, - 30, 12, 30, 986, 9, 30, 1, 31, 1, 31, 1, 31, 1, 31, 3, 31, 992, 8, 31, - 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 3, 32, 1000, 8, 32, 1, 32, 1, - 32, 3, 32, 1004, 8, 32, 1, 32, 1, 32, 1, 32, 3, 32, 1009, 8, 32, 1, 32, + 956, 8, 27, 1, 28, 1, 28, 3, 28, 960, 8, 28, 1, 28, 1, 28, 3, 28, 964, + 8, 28, 1, 28, 1, 28, 1, 28, 3, 28, 969, 8, 28, 1, 28, 1, 28, 1, 28, 3, + 28, 974, 8, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, + 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 5, 30, 991, 8, 30, 10, + 30, 12, 30, 994, 9, 30, 1, 31, 1, 31, 1, 31, 1, 31, 3, 31, 1000, 8, 31, + 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 3, 32, 1008, 8, 32, 1, 32, 1, + 32, 3, 32, 1012, 8, 32, 1, 32, 1, 32, 1, 32, 3, 32, 1017, 8, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, - 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 3, 33, 1028, 8, 33, 1, 34, 1, 34, - 1, 34, 1, 34, 1, 34, 5, 34, 1035, 8, 34, 10, 34, 12, 34, 1038, 9, 34, 1, + 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 3, 33, 1036, 8, 33, 1, 34, 1, 34, + 1, 34, 1, 34, 1, 34, 5, 34, 1043, 8, 34, 10, 34, 12, 34, 1046, 9, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, - 1, 36, 5, 36, 1052, 8, 36, 10, 36, 12, 36, 1055, 9, 36, 1, 36, 1, 36, 1, - 37, 1, 37, 1, 37, 1, 37, 1, 37, 5, 37, 1064, 8, 37, 10, 37, 12, 37, 1067, + 1, 36, 5, 36, 1060, 8, 36, 10, 36, 12, 36, 1063, 9, 36, 1, 36, 1, 36, 1, + 37, 1, 37, 1, 37, 1, 37, 1, 37, 5, 37, 1072, 8, 37, 10, 37, 12, 37, 1075, 9, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, - 39, 1, 39, 3, 39, 1080, 8, 39, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 3, 41, - 1087, 8, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 3, 42, 1094, 8, 42, 1, - 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 3, 43, 1102, 8, 43, 1, 44, 1, 44, - 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 5, 45, 1111, 8, 45, 10, 45, 12, 45, - 1114, 9, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, - 47, 1, 47, 1, 47, 5, 47, 1127, 8, 47, 10, 47, 12, 47, 1130, 9, 47, 1, 48, + 39, 1, 39, 3, 39, 1088, 8, 39, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 3, 41, + 1095, 8, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 3, 42, 1102, 8, 42, 1, + 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 3, 43, 1110, 8, 43, 1, 44, 1, 44, + 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 5, 45, 1119, 8, 45, 10, 45, 12, 45, + 1122, 9, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, + 47, 1, 47, 1, 47, 5, 47, 1135, 8, 47, 10, 47, 12, 47, 1138, 9, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, - 50, 1, 50, 1, 50, 1, 50, 1, 50, 3, 50, 1148, 8, 50, 1, 51, 1, 51, 1, 51, + 50, 1, 50, 1, 50, 1, 50, 1, 50, 3, 50, 1156, 8, 50, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, - 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 5, 55, 1169, 8, 55, 10, 55, 12, - 55, 1172, 9, 55, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 5, 57, - 1181, 8, 57, 10, 57, 12, 57, 1184, 9, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, - 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 5, 60, 1197, 8, 60, 10, 60, - 12, 60, 1200, 9, 60, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 3, - 62, 1209, 8, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 5, 63, 1216, 8, 63, - 10, 63, 12, 63, 1219, 9, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, + 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 5, 55, 1177, 8, 55, 10, 55, 12, + 55, 1180, 9, 55, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 5, 57, + 1189, 8, 57, 10, 57, 12, 57, 1192, 9, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, + 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 5, 60, 1205, 8, 60, 10, 60, + 12, 60, 1208, 9, 60, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 3, + 62, 1217, 8, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 5, 63, 1224, 8, 63, + 10, 63, 12, 63, 1227, 9, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 3, - 64, 1237, 8, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 1245, - 8, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 1251, 8, 65, 1, 66, 1, 66, 1, - 66, 3, 66, 1256, 8, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 3, 67, 1263, - 8, 67, 1, 67, 1, 67, 1, 67, 3, 67, 1268, 8, 67, 1, 67, 1, 67, 1, 68, 1, - 68, 1, 68, 1, 68, 3, 68, 1276, 8, 68, 1, 68, 1, 68, 1, 68, 3, 68, 1281, - 8, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 3, 69, 1288, 8, 69, 1, 69, 1, - 69, 1, 69, 3, 69, 1293, 8, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 3, 70, - 1300, 8, 70, 1, 70, 1, 70, 1, 70, 3, 70, 1305, 8, 70, 1, 70, 1, 70, 1, - 71, 1, 71, 1, 71, 3, 71, 1312, 8, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, - 1, 72, 1, 72, 3, 72, 1321, 8, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 3, - 73, 1328, 8, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 3, 74, 1335, 8, 74, - 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 3, 75, 1342, 8, 75, 1, 75, 1, 75, 1, - 75, 3, 75, 1347, 8, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 3, 76, 1354, - 8, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 3, 76, 1361, 8, 76, 1, 77, 1, - 77, 3, 77, 1365, 8, 77, 1, 77, 3, 77, 1368, 8, 77, 1, 78, 1, 78, 1, 78, - 1, 78, 1, 78, 1, 78, 3, 78, 1376, 8, 78, 1, 78, 1, 78, 1, 79, 1, 79, 1, - 79, 1, 79, 5, 79, 1384, 8, 79, 10, 79, 12, 79, 1387, 9, 79, 1, 80, 1, 80, - 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 3, 80, 1397, 8, 80, 1, 81, 1, - 81, 1, 82, 1, 82, 3, 82, 1403, 8, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, - 5, 83, 1410, 8, 83, 10, 83, 12, 83, 1413, 9, 83, 1, 83, 1, 83, 1, 84, 1, - 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 86, 1, 86, 3, 86, 1425, 8, 86, 1, 87, - 1, 87, 1, 87, 1, 87, 5, 87, 1431, 8, 87, 10, 87, 12, 87, 1434, 9, 87, 1, - 87, 1, 87, 1, 87, 3, 87, 1439, 8, 87, 1, 88, 1, 88, 1, 88, 3, 88, 1444, + 64, 1245, 8, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 1253, + 8, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 1259, 8, 65, 1, 66, 1, 66, 1, + 66, 3, 66, 1264, 8, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 3, 67, 1271, + 8, 67, 1, 67, 1, 67, 1, 67, 3, 67, 1276, 8, 67, 1, 67, 1, 67, 1, 68, 1, + 68, 1, 68, 1, 68, 3, 68, 1284, 8, 68, 1, 68, 1, 68, 1, 68, 3, 68, 1289, + 8, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 3, 69, 1296, 8, 69, 1, 69, 1, + 69, 1, 69, 3, 69, 1301, 8, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 3, 70, + 1308, 8, 70, 1, 70, 1, 70, 1, 70, 3, 70, 1313, 8, 70, 1, 70, 1, 70, 1, + 71, 1, 71, 1, 71, 3, 71, 1320, 8, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, + 1, 72, 1, 72, 3, 72, 1329, 8, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 3, + 73, 1336, 8, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 3, 74, 1343, 8, 74, + 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 3, 75, 1350, 8, 75, 1, 75, 1, 75, 1, + 75, 3, 75, 1355, 8, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 3, 76, 1362, + 8, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 3, 76, 1369, 8, 76, 1, 77, 1, + 77, 3, 77, 1373, 8, 77, 1, 77, 3, 77, 1376, 8, 77, 1, 78, 1, 78, 1, 78, + 1, 78, 1, 78, 1, 78, 3, 78, 1384, 8, 78, 1, 78, 1, 78, 1, 79, 1, 79, 1, + 79, 1, 79, 5, 79, 1392, 8, 79, 10, 79, 12, 79, 1395, 9, 79, 1, 80, 1, 80, + 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 3, 80, 1405, 8, 80, 1, 81, 1, + 81, 1, 82, 1, 82, 3, 82, 1411, 8, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, + 5, 83, 1418, 8, 83, 10, 83, 12, 83, 1421, 9, 83, 1, 83, 1, 83, 1, 84, 1, + 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 86, 1, 86, 3, 86, 1433, 8, 86, 1, 87, + 1, 87, 1, 87, 1, 87, 5, 87, 1439, 8, 87, 10, 87, 12, 87, 1442, 9, 87, 1, + 87, 1, 87, 1, 87, 3, 87, 1447, 8, 87, 1, 88, 1, 88, 1, 88, 3, 88, 1452, 8, 88, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, - 91, 1, 91, 1, 91, 3, 91, 1458, 8, 91, 1, 92, 1, 92, 1, 93, 1, 93, 1, 93, + 91, 1, 91, 1, 91, 3, 91, 1466, 8, 91, 1, 92, 1, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 95, 1, 95, 1, 95, 1, - 95, 5, 95, 1476, 8, 95, 10, 95, 12, 95, 1479, 9, 95, 1, 96, 1, 96, 1, 96, - 1, 96, 5, 96, 1485, 8, 96, 10, 96, 12, 96, 1488, 9, 96, 1, 97, 1, 97, 1, - 98, 1, 98, 1, 99, 1, 99, 1, 99, 1, 100, 1, 100, 3, 100, 1499, 8, 100, 1, - 100, 1, 100, 3, 100, 1503, 8, 100, 1, 101, 1, 101, 3, 101, 1507, 8, 101, + 95, 5, 95, 1484, 8, 95, 10, 95, 12, 95, 1487, 9, 95, 1, 96, 1, 96, 1, 96, + 1, 96, 5, 96, 1493, 8, 96, 10, 96, 12, 96, 1496, 9, 96, 1, 97, 1, 97, 1, + 98, 1, 98, 1, 99, 1, 99, 1, 99, 1, 100, 1, 100, 3, 100, 1507, 8, 100, 1, + 100, 1, 100, 3, 100, 1511, 8, 100, 1, 101, 1, 101, 3, 101, 1515, 8, 101, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, - 1, 102, 1, 102, 1, 102, 3, 102, 1521, 8, 102, 1, 103, 1, 103, 1, 103, 1, - 103, 5, 103, 1527, 8, 103, 10, 103, 12, 103, 1530, 9, 103, 1, 104, 1, 104, - 1, 104, 1, 104, 1, 104, 1, 104, 3, 104, 1538, 8, 104, 1, 105, 1, 105, 1, - 105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 3, 107, 1549, 8, 107, - 1, 107, 1, 107, 1, 108, 1, 108, 1, 108, 3, 108, 1556, 8, 108, 1, 108, 3, - 108, 1559, 8, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 109, - 1, 109, 3, 109, 1569, 8, 109, 1, 110, 1, 110, 1, 110, 1, 110, 3, 110, 1575, + 1, 102, 1, 102, 1, 102, 3, 102, 1529, 8, 102, 1, 103, 1, 103, 1, 103, 1, + 103, 5, 103, 1535, 8, 103, 10, 103, 12, 103, 1538, 9, 103, 1, 104, 1, 104, + 1, 104, 1, 104, 1, 104, 1, 104, 3, 104, 1546, 8, 104, 1, 105, 1, 105, 1, + 105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 3, 107, 1557, 8, 107, + 1, 107, 1, 107, 1, 108, 1, 108, 1, 108, 3, 108, 1564, 8, 108, 1, 108, 3, + 108, 1567, 8, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 109, + 1, 109, 3, 109, 1577, 8, 109, 1, 110, 1, 110, 1, 110, 1, 110, 3, 110, 1583, 8, 110, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 114, 3, 114, - 1593, 8, 114, 1, 114, 1, 114, 3, 114, 1597, 8, 114, 1, 114, 1, 114, 3, - 114, 1601, 8, 114, 1, 114, 1, 114, 1, 114, 3, 114, 1606, 8, 114, 1, 114, - 3, 114, 1609, 8, 114, 1, 115, 1, 115, 1, 115, 1, 115, 5, 115, 1615, 8, - 115, 10, 115, 12, 115, 1618, 9, 115, 1, 116, 1, 116, 3, 116, 1622, 8, 116, - 1, 116, 1, 116, 3, 116, 1626, 8, 116, 3, 116, 1628, 8, 116, 1, 117, 3, - 117, 1631, 8, 117, 1, 117, 1, 117, 1, 117, 3, 117, 1636, 8, 117, 1, 117, - 1, 117, 1, 117, 1, 117, 1, 117, 3, 117, 1643, 8, 117, 1, 117, 3, 117, 1646, + 1601, 8, 114, 1, 114, 1, 114, 3, 114, 1605, 8, 114, 1, 114, 1, 114, 3, + 114, 1609, 8, 114, 1, 114, 1, 114, 1, 114, 3, 114, 1614, 8, 114, 1, 114, + 3, 114, 1617, 8, 114, 1, 115, 1, 115, 1, 115, 1, 115, 5, 115, 1623, 8, + 115, 10, 115, 12, 115, 1626, 9, 115, 1, 116, 1, 116, 3, 116, 1630, 8, 116, + 1, 116, 1, 116, 3, 116, 1634, 8, 116, 3, 116, 1636, 8, 116, 1, 117, 3, + 117, 1639, 8, 117, 1, 117, 1, 117, 1, 117, 3, 117, 1644, 8, 117, 1, 117, + 1, 117, 1, 117, 1, 117, 1, 117, 3, 117, 1651, 8, 117, 1, 117, 3, 117, 1654, 8, 117, 1, 118, 1, 118, 1, 118, 1, 119, 1, 119, 1, 119, 1, 119, 5, 119, - 1655, 8, 119, 10, 119, 12, 119, 1658, 9, 119, 1, 120, 1, 120, 1, 120, 1, - 120, 1, 121, 1, 121, 1, 121, 1, 121, 5, 121, 1668, 8, 121, 10, 121, 12, - 121, 1671, 9, 121, 1, 122, 1, 122, 1, 122, 1, 122, 3, 122, 1677, 8, 122, + 1663, 8, 119, 10, 119, 12, 119, 1666, 9, 119, 1, 120, 1, 120, 1, 120, 1, + 120, 1, 121, 1, 121, 1, 121, 1, 121, 5, 121, 1676, 8, 121, 10, 121, 12, + 121, 1679, 9, 121, 1, 122, 1, 122, 1, 122, 1, 122, 3, 122, 1685, 8, 122, 1, 123, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 126, 1, 126, 1, 126, 1, 126, 1, 127, 1, 127, 1, 127, 1, 127, 1, 127, 1, 128, 1, 128, - 1, 128, 1, 128, 1, 128, 5, 128, 1709, 8, 128, 10, 128, 12, 128, 1712, 9, - 128, 3, 128, 1714, 8, 128, 1, 128, 1, 128, 1, 129, 1, 129, 1, 129, 1, 129, - 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 5, 129, 1728, 8, 129, 10, - 129, 12, 129, 1731, 9, 129, 1, 129, 1, 129, 1, 130, 1, 130, 1, 130, 1, - 130, 1, 130, 5, 130, 1740, 8, 130, 10, 130, 12, 130, 1743, 9, 130, 3, 130, - 1745, 8, 130, 1, 130, 1, 130, 1, 131, 1, 131, 1, 132, 1, 132, 1, 132, 1, - 132, 1, 132, 5, 132, 1756, 8, 132, 10, 132, 12, 132, 1759, 9, 132, 1, 132, - 1, 132, 1, 133, 3, 133, 1764, 8, 133, 1, 133, 1, 133, 1, 133, 1, 133, 3, - 133, 1770, 8, 133, 1, 133, 1, 133, 3, 133, 1774, 8, 133, 1, 133, 3, 133, - 1777, 8, 133, 1, 133, 3, 133, 1780, 8, 133, 1, 134, 1, 134, 1, 134, 1, + 1, 128, 1, 128, 1, 128, 5, 128, 1717, 8, 128, 10, 128, 12, 128, 1720, 9, + 128, 3, 128, 1722, 8, 128, 1, 128, 1, 128, 1, 129, 1, 129, 1, 129, 1, 129, + 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 5, 129, 1736, 8, 129, 10, + 129, 12, 129, 1739, 9, 129, 1, 129, 1, 129, 1, 130, 1, 130, 1, 130, 1, + 130, 1, 130, 5, 130, 1748, 8, 130, 10, 130, 12, 130, 1751, 9, 130, 3, 130, + 1753, 8, 130, 1, 130, 1, 130, 1, 131, 1, 131, 1, 132, 1, 132, 1, 132, 1, + 132, 1, 132, 5, 132, 1764, 8, 132, 10, 132, 12, 132, 1767, 9, 132, 1, 132, + 1, 132, 1, 133, 3, 133, 1772, 8, 133, 1, 133, 1, 133, 1, 133, 1, 133, 3, + 133, 1778, 8, 133, 1, 133, 1, 133, 3, 133, 1782, 8, 133, 1, 133, 3, 133, + 1785, 8, 133, 1, 133, 3, 133, 1788, 8, 133, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, - 134, 1, 134, 1, 134, 1, 134, 3, 134, 1798, 8, 134, 1, 135, 1, 135, 1, 135, - 3, 135, 1803, 8, 135, 1, 136, 1, 136, 1, 136, 1, 137, 1, 137, 1, 137, 1, + 134, 1, 134, 1, 134, 1, 134, 3, 134, 1806, 8, 134, 1, 135, 1, 135, 1, 135, + 3, 135, 1811, 8, 135, 1, 136, 1, 136, 1, 136, 1, 137, 1, 137, 1, 137, 1, 138, 1, 138, 1, 138, 1, 138, 1, 139, 1, 139, 1, 139, 1, 140, 1, 140, 1, - 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 3, 140, 1826, 8, 140, 1, 141, - 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1, 142, 1, 142, 5, 142, 1836, 8, - 142, 10, 142, 12, 142, 1839, 9, 142, 1, 143, 1, 143, 1, 143, 1, 143, 5, - 143, 1845, 8, 143, 10, 143, 12, 143, 1848, 9, 143, 1, 144, 1, 144, 1, 144, - 1, 144, 1, 144, 1, 144, 3, 144, 1856, 8, 144, 1, 145, 1, 145, 3, 145, 1860, - 8, 145, 1, 145, 3, 145, 1863, 8, 145, 1, 145, 1, 145, 1, 145, 3, 145, 1868, - 8, 145, 1, 145, 3, 145, 1871, 8, 145, 1, 145, 3, 145, 1874, 8, 145, 1, - 145, 3, 145, 1877, 8, 145, 1, 145, 3, 145, 1880, 8, 145, 1, 145, 3, 145, - 1883, 8, 145, 1, 146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 3, 147, 1891, - 8, 147, 1, 148, 1, 148, 1, 149, 1, 149, 1, 149, 3, 149, 1898, 8, 149, 1, + 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 3, 140, 1834, 8, 140, 1, 141, + 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1, 142, 1, 142, 5, 142, 1844, 8, + 142, 10, 142, 12, 142, 1847, 9, 142, 1, 143, 1, 143, 1, 143, 1, 143, 5, + 143, 1853, 8, 143, 10, 143, 12, 143, 1856, 9, 143, 1, 144, 1, 144, 1, 144, + 1, 144, 1, 144, 1, 144, 3, 144, 1864, 8, 144, 1, 145, 1, 145, 3, 145, 1868, + 8, 145, 1, 145, 3, 145, 1871, 8, 145, 1, 145, 1, 145, 1, 145, 3, 145, 1876, + 8, 145, 1, 145, 3, 145, 1879, 8, 145, 1, 145, 3, 145, 1882, 8, 145, 1, + 145, 3, 145, 1885, 8, 145, 1, 145, 3, 145, 1888, 8, 145, 1, 145, 3, 145, + 1891, 8, 145, 1, 146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 3, 147, 1899, + 8, 147, 1, 148, 1, 148, 1, 149, 1, 149, 1, 149, 3, 149, 1906, 8, 149, 1, 149, 1, 149, 1, 150, 1, 150, 1, 150, 1, 151, 1, 151, 1, 151, 1, 151, 1, - 151, 1, 151, 5, 151, 1911, 8, 151, 10, 151, 12, 151, 1914, 9, 151, 1, 152, - 1, 152, 1, 152, 3, 152, 1919, 8, 152, 1, 153, 1, 153, 1, 153, 1, 154, 1, - 154, 1, 155, 1, 155, 3, 155, 1928, 8, 155, 1, 155, 1, 155, 1, 155, 5, 155, - 1933, 8, 155, 10, 155, 12, 155, 1936, 9, 155, 1, 156, 1, 156, 3, 156, 1940, - 8, 156, 1, 156, 1, 156, 3, 156, 1944, 8, 156, 1, 156, 1, 156, 3, 156, 1948, - 8, 156, 3, 156, 1950, 8, 156, 1, 157, 1, 157, 1, 158, 1, 158, 1, 159, 1, + 151, 1, 151, 5, 151, 1919, 8, 151, 10, 151, 12, 151, 1922, 9, 151, 1, 152, + 1, 152, 1, 152, 3, 152, 1927, 8, 152, 1, 153, 1, 153, 1, 153, 1, 154, 1, + 154, 1, 155, 1, 155, 3, 155, 1936, 8, 155, 1, 155, 1, 155, 1, 155, 5, 155, + 1941, 8, 155, 10, 155, 12, 155, 1944, 9, 155, 1, 156, 1, 156, 3, 156, 1948, + 8, 156, 1, 156, 1, 156, 3, 156, 1952, 8, 156, 1, 156, 1, 156, 3, 156, 1956, + 8, 156, 3, 156, 1958, 8, 156, 1, 157, 1, 157, 1, 158, 1, 158, 1, 159, 1, 159, 1, 159, 1, 159, 1, 159, 1, 160, 1, 160, 1, 160, 1, 161, 1, 161, 1, - 161, 1, 161, 5, 161, 1968, 8, 161, 10, 161, 12, 161, 1971, 9, 161, 1, 162, + 161, 1, 161, 5, 161, 1976, 8, 161, 10, 161, 12, 161, 1979, 9, 161, 1, 162, + 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, - 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 5, 162, - 2000, 8, 162, 10, 162, 12, 162, 2003, 9, 162, 1, 162, 1, 162, 1, 162, 1, - 162, 1, 162, 1, 162, 1, 162, 5, 162, 2012, 8, 162, 10, 162, 12, 162, 2015, - 9, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 5, 162, - 2024, 8, 162, 10, 162, 12, 162, 2027, 9, 162, 1, 162, 1, 162, 1, 162, 1, - 162, 1, 162, 1, 162, 5, 162, 2035, 8, 162, 10, 162, 12, 162, 2038, 9, 162, - 3, 162, 2040, 8, 162, 1, 163, 1, 163, 1, 164, 1, 164, 1, 164, 1, 164, 1, - 165, 1, 165, 1, 165, 1, 165, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, - 166, 1, 167, 1, 167, 1, 167, 1, 167, 1, 168, 1, 168, 1, 168, 1, 168, 1, - 169, 1, 169, 1, 170, 1, 170, 1, 170, 1, 170, 1, 170, 3, 170, 2073, 8, 170, - 1, 171, 1, 171, 1, 171, 1, 171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 173, - 1, 173, 1, 173, 1, 173, 1, 173, 1, 173, 1, 174, 1, 174, 1, 174, 1, 174, - 1, 174, 1, 174, 1, 174, 3, 174, 2096, 8, 174, 1, 174, 1, 174, 1, 174, 1, - 174, 1, 174, 1, 174, 1, 174, 3, 174, 2105, 8, 174, 1, 174, 3, 174, 2108, - 8, 174, 1, 175, 1, 175, 1, 175, 3, 175, 2113, 8, 175, 1, 175, 1, 175, 1, - 175, 1, 175, 3, 175, 2119, 8, 175, 5, 175, 2121, 8, 175, 10, 175, 12, 175, - 2124, 9, 175, 1, 176, 1, 176, 1, 176, 1, 176, 1, 176, 1, 176, 1, 176, 3, - 176, 2133, 8, 176, 1, 177, 1, 177, 1, 177, 1, 177, 1, 177, 1, 177, 1, 177, - 1, 177, 1, 177, 3, 177, 2144, 8, 177, 1, 178, 1, 178, 1, 179, 1, 179, 1, - 180, 1, 180, 1, 181, 1, 181, 1, 182, 1, 182, 1, 183, 1, 183, 1, 183, 1, - 183, 3, 183, 2160, 8, 183, 1, 184, 1, 184, 1, 184, 1, 184, 1, 184, 1, 184, - 1, 184, 3, 184, 2169, 8, 184, 1, 185, 1, 185, 1, 185, 1, 185, 1, 185, 1, - 185, 3, 185, 2177, 8, 185, 1, 186, 1, 186, 3, 186, 2181, 8, 186, 1, 187, - 1, 187, 1, 188, 1, 188, 1, 188, 1, 188, 1, 188, 5, 188, 2190, 8, 188, 10, - 188, 12, 188, 2193, 9, 188, 1, 188, 1, 188, 1, 189, 1, 189, 3, 189, 2199, - 8, 189, 1, 190, 1, 190, 1, 191, 1, 191, 1, 192, 1, 192, 1, 193, 1, 193, - 1, 194, 1, 194, 1, 195, 1, 195, 1, 196, 1, 196, 1, 197, 1, 197, 1, 198, - 1, 198, 1, 199, 1, 199, 1, 200, 1, 200, 1, 201, 1, 201, 1, 201, 1, 202, - 1, 202, 1, 203, 1, 203, 1, 204, 1, 204, 1, 205, 1, 205, 1, 206, 1, 206, - 1, 206, 1, 207, 1, 207, 1, 208, 1, 208, 1, 209, 1, 209, 1, 210, 1, 210, - 1, 211, 1, 211, 1, 212, 1, 212, 1, 213, 1, 213, 1, 214, 1, 214, 1, 215, - 1, 215, 1, 216, 1, 216, 1, 217, 1, 217, 1, 218, 1, 218, 1, 219, 1, 219, - 1, 220, 1, 220, 1, 221, 1, 221, 1, 222, 1, 222, 1, 223, 1, 223, 1, 224, - 1, 224, 1, 225, 1, 225, 1, 226, 1, 226, 1, 227, 1, 227, 1, 228, 1, 228, - 1, 229, 1, 229, 1, 230, 1, 230, 1, 231, 1, 231, 1, 232, 1, 232, 1, 233, - 1, 233, 1, 234, 1, 234, 1, 235, 1, 235, 1, 236, 1, 236, 1, 237, 1, 237, - 1, 238, 1, 238, 1, 239, 1, 239, 1, 240, 1, 240, 1, 241, 1, 241, 1, 242, - 1, 242, 1, 243, 1, 243, 1, 244, 1, 244, 1, 245, 1, 245, 1, 246, 1, 246, - 1, 247, 1, 247, 1, 248, 1, 248, 1, 249, 1, 249, 1, 250, 1, 250, 1, 251, - 1, 251, 1, 252, 1, 252, 1, 253, 1, 253, 1, 254, 1, 254, 1, 255, 1, 255, - 1, 256, 1, 256, 1, 257, 1, 257, 1, 258, 1, 258, 1, 259, 1, 259, 1, 260, - 1, 260, 1, 261, 1, 261, 1, 262, 1, 262, 1, 263, 1, 263, 1, 264, 1, 264, - 1, 265, 1, 265, 1, 266, 1, 266, 1, 267, 1, 267, 1, 268, 1, 268, 1, 269, - 1, 269, 1, 270, 1, 270, 1, 271, 1, 271, 1, 272, 1, 272, 1, 273, 1, 273, - 1, 274, 1, 274, 1, 275, 1, 275, 1, 276, 1, 276, 1, 277, 1, 277, 1, 278, - 1, 278, 1, 279, 1, 279, 1, 280, 1, 280, 1, 281, 1, 281, 1, 282, 1, 282, - 1, 283, 1, 283, 1, 284, 1, 284, 1, 285, 1, 285, 1, 286, 1, 286, 1, 287, - 1, 287, 1, 288, 1, 288, 1, 289, 1, 289, 1, 290, 1, 290, 1, 291, 1, 291, - 1, 292, 1, 292, 1, 293, 1, 293, 1, 294, 1, 294, 1, 295, 1, 295, 1, 296, - 1, 296, 1, 297, 1, 297, 1, 298, 1, 298, 1, 299, 1, 299, 1, 300, 1, 300, - 1, 301, 1, 301, 1, 302, 1, 302, 1, 303, 1, 303, 1, 304, 1, 304, 1, 305, - 1, 305, 1, 306, 1, 306, 1, 307, 1, 307, 1, 308, 1, 308, 1, 309, 1, 309, - 1, 310, 1, 310, 1, 311, 1, 311, 1, 311, 1, 311, 1, 311, 1, 311, 5, 311, - 2451, 8, 311, 10, 311, 12, 311, 2454, 9, 311, 1, 312, 1, 312, 1, 312, 0, - 0, 313, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, - 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, - 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, - 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, - 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, - 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, - 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, - 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 254, - 256, 258, 260, 262, 264, 266, 268, 270, 272, 274, 276, 278, 280, 282, 284, - 286, 288, 290, 292, 294, 296, 298, 300, 302, 304, 306, 308, 310, 312, 314, - 316, 318, 320, 322, 324, 326, 328, 330, 332, 334, 336, 338, 340, 342, 344, - 346, 348, 350, 352, 354, 356, 358, 360, 362, 364, 366, 368, 370, 372, 374, - 376, 378, 380, 382, 384, 386, 388, 390, 392, 394, 396, 398, 400, 402, 404, - 406, 408, 410, 412, 414, 416, 418, 420, 422, 424, 426, 428, 430, 432, 434, - 436, 438, 440, 442, 444, 446, 448, 450, 452, 454, 456, 458, 460, 462, 464, - 466, 468, 470, 472, 474, 476, 478, 480, 482, 484, 486, 488, 490, 492, 494, - 496, 498, 500, 502, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, - 526, 528, 530, 532, 534, 536, 538, 540, 542, 544, 546, 548, 550, 552, 554, - 556, 558, 560, 562, 564, 566, 568, 570, 572, 574, 576, 578, 580, 582, 584, - 586, 588, 590, 592, 594, 596, 598, 600, 602, 604, 606, 608, 610, 612, 614, - 616, 618, 620, 622, 624, 0, 8, 1, 0, 168, 169, 2, 0, 14, 14, 16, 16, 1, - 0, 19, 23, 1, 0, 176, 177, 1, 0, 170, 171, 2, 0, 57, 57, 131, 131, 6, 0, - 84, 84, 118, 118, 127, 127, 141, 141, 147, 167, 174, 174, 2, 0, 71, 71, - 174, 174, 2435, 0, 627, 1, 0, 0, 0, 2, 645, 1, 0, 0, 0, 4, 658, 1, 0, 0, - 0, 6, 660, 1, 0, 0, 0, 8, 700, 1, 0, 0, 0, 10, 704, 1, 0, 0, 0, 12, 712, - 1, 0, 0, 0, 14, 714, 1, 0, 0, 0, 16, 716, 1, 0, 0, 0, 18, 719, 1, 0, 0, - 0, 20, 724, 1, 0, 0, 0, 22, 728, 1, 0, 0, 0, 24, 735, 1, 0, 0, 0, 26, 745, - 1, 0, 0, 0, 28, 757, 1, 0, 0, 0, 30, 776, 1, 0, 0, 0, 32, 811, 1, 0, 0, - 0, 34, 813, 1, 0, 0, 0, 36, 826, 1, 0, 0, 0, 38, 835, 1, 0, 0, 0, 40, 850, - 1, 0, 0, 0, 42, 861, 1, 0, 0, 0, 44, 875, 1, 0, 0, 0, 46, 903, 1, 0, 0, - 0, 48, 910, 1, 0, 0, 0, 50, 919, 1, 0, 0, 0, 52, 930, 1, 0, 0, 0, 54, 932, - 1, 0, 0, 0, 56, 949, 1, 0, 0, 0, 58, 976, 1, 0, 0, 0, 60, 978, 1, 0, 0, - 0, 62, 991, 1, 0, 0, 0, 64, 997, 1, 0, 0, 0, 66, 1027, 1, 0, 0, 0, 68, - 1029, 1, 0, 0, 0, 70, 1041, 1, 0, 0, 0, 72, 1045, 1, 0, 0, 0, 74, 1058, - 1, 0, 0, 0, 76, 1070, 1, 0, 0, 0, 78, 1073, 1, 0, 0, 0, 80, 1081, 1, 0, - 0, 0, 82, 1086, 1, 0, 0, 0, 84, 1088, 1, 0, 0, 0, 86, 1101, 1, 0, 0, 0, - 88, 1103, 1, 0, 0, 0, 90, 1106, 1, 0, 0, 0, 92, 1115, 1, 0, 0, 0, 94, 1119, - 1, 0, 0, 0, 96, 1131, 1, 0, 0, 0, 98, 1136, 1, 0, 0, 0, 100, 1147, 1, 0, - 0, 0, 102, 1149, 1, 0, 0, 0, 104, 1152, 1, 0, 0, 0, 106, 1157, 1, 0, 0, - 0, 108, 1161, 1, 0, 0, 0, 110, 1164, 1, 0, 0, 0, 112, 1173, 1, 0, 0, 0, - 114, 1176, 1, 0, 0, 0, 116, 1185, 1, 0, 0, 0, 118, 1189, 1, 0, 0, 0, 120, - 1192, 1, 0, 0, 0, 122, 1201, 1, 0, 0, 0, 124, 1204, 1, 0, 0, 0, 126, 1210, - 1, 0, 0, 0, 128, 1236, 1, 0, 0, 0, 130, 1238, 1, 0, 0, 0, 132, 1252, 1, - 0, 0, 0, 134, 1259, 1, 0, 0, 0, 136, 1271, 1, 0, 0, 0, 138, 1284, 1, 0, - 0, 0, 140, 1296, 1, 0, 0, 0, 142, 1308, 1, 0, 0, 0, 144, 1317, 1, 0, 0, - 0, 146, 1324, 1, 0, 0, 0, 148, 1331, 1, 0, 0, 0, 150, 1338, 1, 0, 0, 0, - 152, 1350, 1, 0, 0, 0, 154, 1362, 1, 0, 0, 0, 156, 1369, 1, 0, 0, 0, 158, - 1379, 1, 0, 0, 0, 160, 1396, 1, 0, 0, 0, 162, 1398, 1, 0, 0, 0, 164, 1402, - 1, 0, 0, 0, 166, 1404, 1, 0, 0, 0, 168, 1416, 1, 0, 0, 0, 170, 1420, 1, - 0, 0, 0, 172, 1424, 1, 0, 0, 0, 174, 1426, 1, 0, 0, 0, 176, 1440, 1, 0, - 0, 0, 178, 1445, 1, 0, 0, 0, 180, 1448, 1, 0, 0, 0, 182, 1457, 1, 0, 0, - 0, 184, 1459, 1, 0, 0, 0, 186, 1461, 1, 0, 0, 0, 188, 1465, 1, 0, 0, 0, - 190, 1471, 1, 0, 0, 0, 192, 1480, 1, 0, 0, 0, 194, 1489, 1, 0, 0, 0, 196, - 1491, 1, 0, 0, 0, 198, 1493, 1, 0, 0, 0, 200, 1496, 1, 0, 0, 0, 202, 1506, - 1, 0, 0, 0, 204, 1508, 1, 0, 0, 0, 206, 1522, 1, 0, 0, 0, 208, 1537, 1, - 0, 0, 0, 210, 1539, 1, 0, 0, 0, 212, 1543, 1, 0, 0, 0, 214, 1546, 1, 0, - 0, 0, 216, 1552, 1, 0, 0, 0, 218, 1568, 1, 0, 0, 0, 220, 1574, 1, 0, 0, - 0, 222, 1576, 1, 0, 0, 0, 224, 1581, 1, 0, 0, 0, 226, 1586, 1, 0, 0, 0, - 228, 1592, 1, 0, 0, 0, 230, 1610, 1, 0, 0, 0, 232, 1627, 1, 0, 0, 0, 234, - 1630, 1, 0, 0, 0, 236, 1647, 1, 0, 0, 0, 238, 1650, 1, 0, 0, 0, 240, 1659, - 1, 0, 0, 0, 242, 1663, 1, 0, 0, 0, 244, 1676, 1, 0, 0, 0, 246, 1678, 1, - 0, 0, 0, 248, 1682, 1, 0, 0, 0, 250, 1688, 1, 0, 0, 0, 252, 1694, 1, 0, - 0, 0, 254, 1698, 1, 0, 0, 0, 256, 1703, 1, 0, 0, 0, 258, 1717, 1, 0, 0, - 0, 260, 1734, 1, 0, 0, 0, 262, 1748, 1, 0, 0, 0, 264, 1750, 1, 0, 0, 0, - 266, 1763, 1, 0, 0, 0, 268, 1797, 1, 0, 0, 0, 270, 1799, 1, 0, 0, 0, 272, - 1804, 1, 0, 0, 0, 274, 1807, 1, 0, 0, 0, 276, 1810, 1, 0, 0, 0, 278, 1814, - 1, 0, 0, 0, 280, 1825, 1, 0, 0, 0, 282, 1827, 1, 0, 0, 0, 284, 1831, 1, - 0, 0, 0, 286, 1840, 1, 0, 0, 0, 288, 1855, 1, 0, 0, 0, 290, 1857, 1, 0, - 0, 0, 292, 1884, 1, 0, 0, 0, 294, 1887, 1, 0, 0, 0, 296, 1892, 1, 0, 0, - 0, 298, 1897, 1, 0, 0, 0, 300, 1901, 1, 0, 0, 0, 302, 1904, 1, 0, 0, 0, - 304, 1915, 1, 0, 0, 0, 306, 1920, 1, 0, 0, 0, 308, 1923, 1, 0, 0, 0, 310, - 1927, 1, 0, 0, 0, 312, 1949, 1, 0, 0, 0, 314, 1951, 1, 0, 0, 0, 316, 1953, - 1, 0, 0, 0, 318, 1955, 1, 0, 0, 0, 320, 1960, 1, 0, 0, 0, 322, 1963, 1, - 0, 0, 0, 324, 2039, 1, 0, 0, 0, 326, 2041, 1, 0, 0, 0, 328, 2043, 1, 0, - 0, 0, 330, 2047, 1, 0, 0, 0, 332, 2051, 1, 0, 0, 0, 334, 2057, 1, 0, 0, - 0, 336, 2061, 1, 0, 0, 0, 338, 2065, 1, 0, 0, 0, 340, 2072, 1, 0, 0, 0, - 342, 2074, 1, 0, 0, 0, 344, 2078, 1, 0, 0, 0, 346, 2082, 1, 0, 0, 0, 348, - 2107, 1, 0, 0, 0, 350, 2112, 1, 0, 0, 0, 352, 2132, 1, 0, 0, 0, 354, 2143, - 1, 0, 0, 0, 356, 2145, 1, 0, 0, 0, 358, 2147, 1, 0, 0, 0, 360, 2149, 1, - 0, 0, 0, 362, 2151, 1, 0, 0, 0, 364, 2153, 1, 0, 0, 0, 366, 2159, 1, 0, - 0, 0, 368, 2168, 1, 0, 0, 0, 370, 2176, 1, 0, 0, 0, 372, 2178, 1, 0, 0, - 0, 374, 2182, 1, 0, 0, 0, 376, 2184, 1, 0, 0, 0, 378, 2198, 1, 0, 0, 0, - 380, 2200, 1, 0, 0, 0, 382, 2202, 1, 0, 0, 0, 384, 2204, 1, 0, 0, 0, 386, - 2206, 1, 0, 0, 0, 388, 2208, 1, 0, 0, 0, 390, 2210, 1, 0, 0, 0, 392, 2212, - 1, 0, 0, 0, 394, 2214, 1, 0, 0, 0, 396, 2216, 1, 0, 0, 0, 398, 2218, 1, - 0, 0, 0, 400, 2220, 1, 0, 0, 0, 402, 2222, 1, 0, 0, 0, 404, 2225, 1, 0, - 0, 0, 406, 2227, 1, 0, 0, 0, 408, 2229, 1, 0, 0, 0, 410, 2231, 1, 0, 0, - 0, 412, 2233, 1, 0, 0, 0, 414, 2236, 1, 0, 0, 0, 416, 2238, 1, 0, 0, 0, - 418, 2240, 1, 0, 0, 0, 420, 2242, 1, 0, 0, 0, 422, 2244, 1, 0, 0, 0, 424, - 2246, 1, 0, 0, 0, 426, 2248, 1, 0, 0, 0, 428, 2250, 1, 0, 0, 0, 430, 2252, - 1, 0, 0, 0, 432, 2254, 1, 0, 0, 0, 434, 2256, 1, 0, 0, 0, 436, 2258, 1, - 0, 0, 0, 438, 2260, 1, 0, 0, 0, 440, 2262, 1, 0, 0, 0, 442, 2264, 1, 0, - 0, 0, 444, 2266, 1, 0, 0, 0, 446, 2268, 1, 0, 0, 0, 448, 2270, 1, 0, 0, - 0, 450, 2272, 1, 0, 0, 0, 452, 2274, 1, 0, 0, 0, 454, 2276, 1, 0, 0, 0, - 456, 2278, 1, 0, 0, 0, 458, 2280, 1, 0, 0, 0, 460, 2282, 1, 0, 0, 0, 462, - 2284, 1, 0, 0, 0, 464, 2286, 1, 0, 0, 0, 466, 2288, 1, 0, 0, 0, 468, 2290, - 1, 0, 0, 0, 470, 2292, 1, 0, 0, 0, 472, 2294, 1, 0, 0, 0, 474, 2296, 1, - 0, 0, 0, 476, 2298, 1, 0, 0, 0, 478, 2300, 1, 0, 0, 0, 480, 2302, 1, 0, - 0, 0, 482, 2304, 1, 0, 0, 0, 484, 2306, 1, 0, 0, 0, 486, 2308, 1, 0, 0, - 0, 488, 2310, 1, 0, 0, 0, 490, 2312, 1, 0, 0, 0, 492, 2314, 1, 0, 0, 0, - 494, 2316, 1, 0, 0, 0, 496, 2318, 1, 0, 0, 0, 498, 2320, 1, 0, 0, 0, 500, - 2322, 1, 0, 0, 0, 502, 2324, 1, 0, 0, 0, 504, 2326, 1, 0, 0, 0, 506, 2328, - 1, 0, 0, 0, 508, 2330, 1, 0, 0, 0, 510, 2332, 1, 0, 0, 0, 512, 2334, 1, - 0, 0, 0, 514, 2336, 1, 0, 0, 0, 516, 2338, 1, 0, 0, 0, 518, 2340, 1, 0, - 0, 0, 520, 2342, 1, 0, 0, 0, 522, 2344, 1, 0, 0, 0, 524, 2346, 1, 0, 0, - 0, 526, 2348, 1, 0, 0, 0, 528, 2350, 1, 0, 0, 0, 530, 2352, 1, 0, 0, 0, - 532, 2354, 1, 0, 0, 0, 534, 2356, 1, 0, 0, 0, 536, 2358, 1, 0, 0, 0, 538, - 2360, 1, 0, 0, 0, 540, 2362, 1, 0, 0, 0, 542, 2364, 1, 0, 0, 0, 544, 2366, - 1, 0, 0, 0, 546, 2368, 1, 0, 0, 0, 548, 2370, 1, 0, 0, 0, 550, 2372, 1, - 0, 0, 0, 552, 2374, 1, 0, 0, 0, 554, 2376, 1, 0, 0, 0, 556, 2378, 1, 0, - 0, 0, 558, 2380, 1, 0, 0, 0, 560, 2382, 1, 0, 0, 0, 562, 2384, 1, 0, 0, - 0, 564, 2386, 1, 0, 0, 0, 566, 2388, 1, 0, 0, 0, 568, 2390, 1, 0, 0, 0, - 570, 2392, 1, 0, 0, 0, 572, 2394, 1, 0, 0, 0, 574, 2396, 1, 0, 0, 0, 576, - 2398, 1, 0, 0, 0, 578, 2400, 1, 0, 0, 0, 580, 2402, 1, 0, 0, 0, 582, 2404, - 1, 0, 0, 0, 584, 2406, 1, 0, 0, 0, 586, 2408, 1, 0, 0, 0, 588, 2410, 1, - 0, 0, 0, 590, 2412, 1, 0, 0, 0, 592, 2414, 1, 0, 0, 0, 594, 2416, 1, 0, - 0, 0, 596, 2418, 1, 0, 0, 0, 598, 2420, 1, 0, 0, 0, 600, 2422, 1, 0, 0, - 0, 602, 2424, 1, 0, 0, 0, 604, 2426, 1, 0, 0, 0, 606, 2428, 1, 0, 0, 0, - 608, 2430, 1, 0, 0, 0, 610, 2432, 1, 0, 0, 0, 612, 2434, 1, 0, 0, 0, 614, - 2436, 1, 0, 0, 0, 616, 2438, 1, 0, 0, 0, 618, 2440, 1, 0, 0, 0, 620, 2442, - 1, 0, 0, 0, 622, 2444, 1, 0, 0, 0, 624, 2455, 1, 0, 0, 0, 626, 628, 3, - 2, 1, 0, 627, 626, 1, 0, 0, 0, 628, 629, 1, 0, 0, 0, 629, 627, 1, 0, 0, - 0, 629, 630, 1, 0, 0, 0, 630, 632, 1, 0, 0, 0, 631, 633, 5, 15, 0, 0, 632, - 631, 1, 0, 0, 0, 632, 633, 1, 0, 0, 0, 633, 634, 1, 0, 0, 0, 634, 635, - 5, 0, 0, 1, 635, 1, 1, 0, 0, 0, 636, 638, 3, 8, 4, 0, 637, 639, 5, 15, - 0, 0, 638, 637, 1, 0, 0, 0, 638, 639, 1, 0, 0, 0, 639, 640, 1, 0, 0, 0, - 640, 641, 3, 4, 2, 0, 641, 644, 1, 0, 0, 0, 642, 644, 3, 6, 3, 0, 643, - 636, 1, 0, 0, 0, 643, 642, 1, 0, 0, 0, 644, 647, 1, 0, 0, 0, 645, 643, - 1, 0, 0, 0, 645, 646, 1, 0, 0, 0, 646, 656, 1, 0, 0, 0, 647, 645, 1, 0, - 0, 0, 648, 653, 3, 8, 4, 0, 649, 651, 5, 15, 0, 0, 650, 649, 1, 0, 0, 0, - 650, 651, 1, 0, 0, 0, 651, 652, 1, 0, 0, 0, 652, 654, 3, 4, 2, 0, 653, - 650, 1, 0, 0, 0, 653, 654, 1, 0, 0, 0, 654, 657, 1, 0, 0, 0, 655, 657, - 3, 6, 3, 0, 656, 648, 1, 0, 0, 0, 656, 655, 1, 0, 0, 0, 657, 3, 1, 0, 0, - 0, 658, 659, 5, 8, 0, 0, 659, 5, 1, 0, 0, 0, 660, 661, 3, 4, 2, 0, 661, - 7, 1, 0, 0, 0, 662, 701, 3, 204, 102, 0, 663, 701, 3, 130, 65, 0, 664, - 701, 3, 124, 62, 0, 665, 701, 3, 98, 49, 0, 666, 701, 3, 84, 42, 0, 667, - 701, 3, 78, 39, 0, 668, 701, 3, 198, 99, 0, 669, 701, 3, 64, 32, 0, 670, - 701, 3, 56, 28, 0, 671, 701, 3, 216, 108, 0, 672, 701, 3, 54, 27, 0, 673, - 701, 3, 44, 22, 0, 674, 701, 3, 36, 18, 0, 675, 701, 3, 152, 76, 0, 676, - 701, 3, 42, 21, 0, 677, 701, 3, 38, 19, 0, 678, 701, 3, 34, 17, 0, 679, - 701, 3, 228, 114, 0, 680, 701, 3, 138, 69, 0, 681, 701, 3, 140, 70, 0, - 682, 701, 3, 150, 75, 0, 683, 701, 3, 148, 74, 0, 684, 701, 3, 136, 68, - 0, 685, 701, 3, 144, 72, 0, 686, 701, 3, 146, 73, 0, 687, 701, 3, 142, - 71, 0, 688, 701, 3, 134, 67, 0, 689, 701, 3, 132, 66, 0, 690, 701, 3, 28, - 14, 0, 691, 701, 3, 266, 133, 0, 692, 701, 3, 26, 13, 0, 693, 701, 3, 24, - 12, 0, 694, 701, 3, 22, 11, 0, 695, 701, 3, 290, 145, 0, 696, 701, 3, 214, - 107, 0, 697, 701, 3, 234, 117, 0, 698, 701, 3, 212, 106, 0, 699, 701, 3, - 10, 5, 0, 700, 662, 1, 0, 0, 0, 700, 663, 1, 0, 0, 0, 700, 664, 1, 0, 0, - 0, 700, 665, 1, 0, 0, 0, 700, 666, 1, 0, 0, 0, 700, 667, 1, 0, 0, 0, 700, - 668, 1, 0, 0, 0, 700, 669, 1, 0, 0, 0, 700, 670, 1, 0, 0, 0, 700, 671, - 1, 0, 0, 0, 700, 672, 1, 0, 0, 0, 700, 673, 1, 0, 0, 0, 700, 674, 1, 0, - 0, 0, 700, 675, 1, 0, 0, 0, 700, 676, 1, 0, 0, 0, 700, 677, 1, 0, 0, 0, - 700, 678, 1, 0, 0, 0, 700, 679, 1, 0, 0, 0, 700, 680, 1, 0, 0, 0, 700, - 681, 1, 0, 0, 0, 700, 682, 1, 0, 0, 0, 700, 683, 1, 0, 0, 0, 700, 684, - 1, 0, 0, 0, 700, 685, 1, 0, 0, 0, 700, 686, 1, 0, 0, 0, 700, 687, 1, 0, - 0, 0, 700, 688, 1, 0, 0, 0, 700, 689, 1, 0, 0, 0, 700, 690, 1, 0, 0, 0, - 700, 691, 1, 0, 0, 0, 700, 692, 1, 0, 0, 0, 700, 693, 1, 0, 0, 0, 700, - 694, 1, 0, 0, 0, 700, 695, 1, 0, 0, 0, 700, 696, 1, 0, 0, 0, 700, 697, - 1, 0, 0, 0, 700, 698, 1, 0, 0, 0, 700, 699, 1, 0, 0, 0, 701, 9, 1, 0, 0, - 0, 702, 705, 3, 448, 224, 0, 703, 705, 3, 450, 225, 0, 704, 702, 1, 0, - 0, 0, 704, 703, 1, 0, 0, 0, 705, 706, 1, 0, 0, 0, 706, 707, 3, 12, 6, 0, - 707, 11, 1, 0, 0, 0, 708, 713, 3, 14, 7, 0, 709, 713, 3, 16, 8, 0, 710, - 713, 3, 18, 9, 0, 711, 713, 3, 20, 10, 0, 712, 708, 1, 0, 0, 0, 712, 709, - 1, 0, 0, 0, 712, 710, 1, 0, 0, 0, 712, 711, 1, 0, 0, 0, 713, 13, 1, 0, - 0, 0, 714, 715, 3, 502, 251, 0, 715, 15, 1, 0, 0, 0, 716, 717, 3, 566, - 283, 0, 717, 17, 1, 0, 0, 0, 718, 720, 3, 564, 282, 0, 719, 718, 1, 0, - 0, 0, 719, 720, 1, 0, 0, 0, 720, 721, 1, 0, 0, 0, 721, 722, 3, 298, 149, - 0, 722, 19, 1, 0, 0, 0, 723, 725, 3, 500, 250, 0, 724, 723, 1, 0, 0, 0, - 724, 725, 1, 0, 0, 0, 725, 726, 1, 0, 0, 0, 726, 727, 3, 366, 183, 0, 727, - 21, 1, 0, 0, 0, 728, 729, 3, 598, 299, 0, 729, 730, 3, 30, 15, 0, 730, - 731, 3, 528, 264, 0, 731, 732, 3, 32, 16, 0, 732, 733, 3, 468, 234, 0, - 733, 734, 3, 380, 190, 0, 734, 23, 1, 0, 0, 0, 735, 736, 3, 508, 254, 0, - 736, 740, 3, 550, 275, 0, 737, 738, 3, 526, 263, 0, 738, 739, 3, 380, 190, - 0, 739, 741, 1, 0, 0, 0, 740, 737, 1, 0, 0, 0, 740, 741, 1, 0, 0, 0, 741, - 743, 1, 0, 0, 0, 742, 744, 3, 520, 260, 0, 743, 742, 1, 0, 0, 0, 743, 744, - 1, 0, 0, 0, 744, 25, 1, 0, 0, 0, 745, 746, 3, 508, 254, 0, 746, 750, 3, - 30, 15, 0, 747, 748, 3, 528, 264, 0, 748, 749, 3, 32, 16, 0, 749, 751, - 1, 0, 0, 0, 750, 747, 1, 0, 0, 0, 750, 751, 1, 0, 0, 0, 751, 755, 1, 0, - 0, 0, 752, 753, 3, 526, 263, 0, 753, 754, 3, 380, 190, 0, 754, 756, 1, - 0, 0, 0, 755, 752, 1, 0, 0, 0, 755, 756, 1, 0, 0, 0, 756, 27, 1, 0, 0, - 0, 757, 758, 3, 476, 238, 0, 758, 759, 3, 30, 15, 0, 759, 760, 3, 528, - 264, 0, 760, 761, 3, 32, 16, 0, 761, 762, 3, 570, 285, 0, 762, 763, 3, - 380, 190, 0, 763, 29, 1, 0, 0, 0, 764, 767, 3, 410, 205, 0, 765, 767, 3, - 412, 206, 0, 766, 764, 1, 0, 0, 0, 766, 765, 1, 0, 0, 0, 767, 777, 1, 0, - 0, 0, 768, 777, 3, 416, 208, 0, 769, 777, 3, 426, 213, 0, 770, 777, 3, - 450, 225, 0, 771, 777, 3, 460, 230, 0, 772, 777, 3, 444, 222, 0, 773, 777, - 3, 454, 227, 0, 774, 777, 3, 516, 258, 0, 775, 777, 3, 552, 276, 0, 776, - 766, 1, 0, 0, 0, 776, 768, 1, 0, 0, 0, 776, 769, 1, 0, 0, 0, 776, 770, - 1, 0, 0, 0, 776, 771, 1, 0, 0, 0, 776, 772, 1, 0, 0, 0, 776, 773, 1, 0, - 0, 0, 776, 774, 1, 0, 0, 0, 776, 775, 1, 0, 0, 0, 777, 31, 1, 0, 0, 0, - 778, 779, 3, 410, 205, 0, 779, 780, 3, 474, 237, 0, 780, 812, 1, 0, 0, - 0, 781, 782, 3, 410, 205, 0, 782, 783, 3, 474, 237, 0, 783, 784, 3, 480, - 240, 0, 784, 785, 3, 500, 250, 0, 785, 786, 3, 366, 183, 0, 786, 812, 1, - 0, 0, 0, 787, 791, 3, 472, 236, 0, 788, 789, 3, 366, 183, 0, 789, 790, - 5, 10, 0, 0, 790, 792, 1, 0, 0, 0, 791, 788, 1, 0, 0, 0, 791, 792, 1, 0, - 0, 0, 792, 793, 1, 0, 0, 0, 793, 794, 3, 392, 196, 0, 794, 812, 1, 0, 0, - 0, 795, 796, 3, 410, 205, 0, 796, 797, 3, 502, 251, 0, 797, 812, 1, 0, - 0, 0, 798, 799, 3, 500, 250, 0, 799, 800, 3, 366, 183, 0, 800, 812, 1, - 0, 0, 0, 801, 803, 3, 564, 282, 0, 802, 801, 1, 0, 0, 0, 802, 803, 1, 0, - 0, 0, 803, 804, 1, 0, 0, 0, 804, 812, 3, 298, 149, 0, 805, 806, 3, 410, - 205, 0, 806, 807, 3, 550, 275, 0, 807, 812, 1, 0, 0, 0, 808, 809, 3, 548, - 274, 0, 809, 810, 3, 380, 190, 0, 810, 812, 1, 0, 0, 0, 811, 778, 1, 0, - 0, 0, 811, 781, 1, 0, 0, 0, 811, 787, 1, 0, 0, 0, 811, 795, 1, 0, 0, 0, - 811, 798, 1, 0, 0, 0, 811, 802, 1, 0, 0, 0, 811, 805, 1, 0, 0, 0, 811, - 808, 1, 0, 0, 0, 812, 33, 1, 0, 0, 0, 813, 814, 3, 444, 222, 0, 814, 816, - 3, 586, 293, 0, 815, 817, 3, 276, 138, 0, 816, 815, 1, 0, 0, 0, 816, 817, - 1, 0, 0, 0, 817, 818, 1, 0, 0, 0, 818, 819, 3, 396, 198, 0, 819, 820, 3, - 596, 298, 0, 820, 821, 3, 536, 268, 0, 821, 824, 3, 360, 180, 0, 822, 825, - 3, 562, 281, 0, 823, 825, 3, 518, 259, 0, 824, 822, 1, 0, 0, 0, 824, 823, - 1, 0, 0, 0, 824, 825, 1, 0, 0, 0, 825, 35, 1, 0, 0, 0, 826, 827, 3, 444, - 222, 0, 827, 829, 3, 548, 274, 0, 828, 830, 3, 276, 138, 0, 829, 828, 1, - 0, 0, 0, 829, 830, 1, 0, 0, 0, 830, 831, 1, 0, 0, 0, 831, 833, 3, 380, - 190, 0, 832, 834, 3, 126, 63, 0, 833, 832, 1, 0, 0, 0, 833, 834, 1, 0, - 0, 0, 834, 37, 1, 0, 0, 0, 835, 836, 3, 444, 222, 0, 836, 838, 3, 578, - 289, 0, 837, 839, 3, 276, 138, 0, 838, 837, 1, 0, 0, 0, 838, 839, 1, 0, - 0, 0, 839, 843, 1, 0, 0, 0, 840, 841, 3, 366, 183, 0, 841, 842, 5, 10, - 0, 0, 842, 844, 1, 0, 0, 0, 843, 840, 1, 0, 0, 0, 843, 844, 1, 0, 0, 0, - 844, 845, 1, 0, 0, 0, 845, 846, 3, 388, 194, 0, 846, 847, 3, 602, 301, - 0, 847, 848, 3, 40, 20, 0, 848, 849, 3, 604, 302, 0, 849, 39, 1, 0, 0, - 0, 850, 851, 3, 370, 185, 0, 851, 858, 3, 372, 186, 0, 852, 853, 3, 618, - 309, 0, 853, 854, 3, 370, 185, 0, 854, 855, 3, 372, 186, 0, 855, 857, 1, - 0, 0, 0, 856, 852, 1, 0, 0, 0, 857, 860, 1, 0, 0, 0, 858, 856, 1, 0, 0, - 0, 858, 859, 1, 0, 0, 0, 859, 41, 1, 0, 0, 0, 860, 858, 1, 0, 0, 0, 861, - 862, 3, 444, 222, 0, 862, 864, 3, 572, 286, 0, 863, 865, 3, 276, 138, 0, - 864, 863, 1, 0, 0, 0, 864, 865, 1, 0, 0, 0, 865, 869, 1, 0, 0, 0, 866, - 867, 3, 366, 183, 0, 867, 868, 5, 10, 0, 0, 868, 870, 1, 0, 0, 0, 869, - 866, 1, 0, 0, 0, 869, 870, 1, 0, 0, 0, 870, 871, 1, 0, 0, 0, 871, 872, - 3, 382, 191, 0, 872, 873, 3, 588, 294, 0, 873, 874, 3, 384, 192, 0, 874, - 43, 1, 0, 0, 0, 875, 876, 3, 444, 222, 0, 876, 877, 3, 514, 257, 0, 877, - 879, 3, 592, 296, 0, 878, 880, 3, 276, 138, 0, 879, 878, 1, 0, 0, 0, 879, - 880, 1, 0, 0, 0, 880, 884, 1, 0, 0, 0, 881, 882, 3, 366, 183, 0, 882, 883, - 5, 10, 0, 0, 883, 885, 1, 0, 0, 0, 884, 881, 1, 0, 0, 0, 884, 885, 1, 0, - 0, 0, 885, 886, 1, 0, 0, 0, 886, 887, 3, 386, 193, 0, 887, 888, 3, 422, - 211, 0, 888, 889, 3, 552, 276, 0, 889, 890, 3, 284, 142, 0, 890, 891, 3, - 468, 234, 0, 891, 892, 3, 298, 149, 0, 892, 893, 3, 46, 23, 0, 893, 894, - 3, 538, 269, 0, 894, 895, 3, 496, 248, 0, 895, 896, 3, 602, 301, 0, 896, - 897, 3, 284, 142, 0, 897, 901, 3, 604, 302, 0, 898, 899, 3, 596, 298, 0, - 899, 900, 3, 52, 26, 0, 900, 902, 1, 0, 0, 0, 901, 898, 1, 0, 0, 0, 901, - 902, 1, 0, 0, 0, 902, 45, 1, 0, 0, 0, 903, 904, 3, 594, 297, 0, 904, 908, - 3, 48, 24, 0, 905, 906, 3, 418, 209, 0, 906, 907, 3, 322, 161, 0, 907, - 909, 1, 0, 0, 0, 908, 905, 1, 0, 0, 0, 908, 909, 1, 0, 0, 0, 909, 47, 1, - 0, 0, 0, 910, 916, 3, 50, 25, 0, 911, 912, 3, 418, 209, 0, 912, 913, 3, - 50, 25, 0, 913, 915, 1, 0, 0, 0, 914, 911, 1, 0, 0, 0, 915, 918, 1, 0, - 0, 0, 916, 914, 1, 0, 0, 0, 916, 917, 1, 0, 0, 0, 917, 49, 1, 0, 0, 0, - 918, 916, 1, 0, 0, 0, 919, 920, 3, 370, 185, 0, 920, 921, 3, 492, 246, - 0, 921, 922, 3, 522, 261, 0, 922, 923, 3, 524, 262, 0, 923, 51, 1, 0, 0, - 0, 924, 931, 3, 158, 79, 0, 925, 926, 3, 158, 79, 0, 926, 927, 3, 418, - 209, 0, 927, 928, 3, 156, 78, 0, 928, 931, 1, 0, 0, 0, 929, 931, 3, 156, - 78, 0, 930, 924, 1, 0, 0, 0, 930, 925, 1, 0, 0, 0, 930, 929, 1, 0, 0, 0, - 931, 53, 1, 0, 0, 0, 932, 933, 3, 444, 222, 0, 933, 935, 3, 500, 250, 0, - 934, 936, 3, 276, 138, 0, 935, 934, 1, 0, 0, 0, 935, 936, 1, 0, 0, 0, 936, - 937, 1, 0, 0, 0, 937, 938, 3, 366, 183, 0, 938, 939, 3, 596, 298, 0, 939, - 940, 3, 544, 272, 0, 940, 941, 5, 19, 0, 0, 941, 942, 3, 606, 303, 0, 942, - 943, 3, 206, 103, 0, 943, 947, 3, 608, 304, 0, 944, 945, 3, 418, 209, 0, - 945, 946, 3, 210, 105, 0, 946, 948, 1, 0, 0, 0, 947, 944, 1, 0, 0, 0, 947, - 948, 1, 0, 0, 0, 948, 55, 1, 0, 0, 0, 949, 951, 3, 444, 222, 0, 950, 952, - 3, 76, 38, 0, 951, 950, 1, 0, 0, 0, 951, 952, 1, 0, 0, 0, 952, 953, 1, - 0, 0, 0, 953, 955, 3, 472, 236, 0, 954, 956, 3, 276, 138, 0, 955, 954, - 1, 0, 0, 0, 955, 956, 1, 0, 0, 0, 956, 960, 1, 0, 0, 0, 957, 958, 3, 366, - 183, 0, 958, 959, 5, 10, 0, 0, 959, 961, 1, 0, 0, 0, 960, 957, 1, 0, 0, - 0, 960, 961, 1, 0, 0, 0, 961, 962, 1, 0, 0, 0, 962, 963, 3, 392, 196, 0, - 963, 965, 3, 602, 301, 0, 964, 966, 3, 60, 30, 0, 965, 964, 1, 0, 0, 0, - 965, 966, 1, 0, 0, 0, 966, 967, 1, 0, 0, 0, 967, 968, 3, 604, 302, 0, 968, - 969, 3, 62, 31, 0, 969, 970, 3, 546, 273, 0, 970, 971, 3, 372, 186, 0, - 971, 972, 3, 504, 252, 0, 972, 973, 3, 394, 197, 0, 973, 974, 3, 422, 211, - 0, 974, 975, 3, 58, 29, 0, 975, 57, 1, 0, 0, 0, 976, 977, 7, 0, 0, 0, 977, - 59, 1, 0, 0, 0, 978, 984, 3, 402, 201, 0, 979, 980, 3, 618, 309, 0, 980, - 981, 3, 402, 201, 0, 981, 983, 1, 0, 0, 0, 982, 979, 1, 0, 0, 0, 983, 986, - 1, 0, 0, 0, 984, 982, 1, 0, 0, 0, 984, 985, 1, 0, 0, 0, 985, 61, 1, 0, - 0, 0, 986, 984, 1, 0, 0, 0, 987, 992, 3, 436, 218, 0, 988, 989, 3, 546, - 273, 0, 989, 990, 3, 524, 262, 0, 990, 992, 1, 0, 0, 0, 991, 987, 1, 0, - 0, 0, 991, 988, 1, 0, 0, 0, 992, 993, 1, 0, 0, 0, 993, 994, 3, 528, 264, - 0, 994, 995, 3, 524, 262, 0, 995, 996, 3, 486, 243, 0, 996, 63, 1, 0, 0, - 0, 997, 999, 3, 444, 222, 0, 998, 1000, 3, 76, 38, 0, 999, 998, 1, 0, 0, - 0, 999, 1000, 1, 0, 0, 0, 1000, 1001, 1, 0, 0, 0, 1001, 1003, 3, 408, 204, - 0, 1002, 1004, 3, 276, 138, 0, 1003, 1002, 1, 0, 0, 0, 1003, 1004, 1, 0, - 0, 0, 1004, 1008, 1, 0, 0, 0, 1005, 1006, 3, 366, 183, 0, 1006, 1007, 5, - 10, 0, 0, 1007, 1009, 1, 0, 0, 0, 1008, 1005, 1, 0, 0, 0, 1008, 1009, 1, - 0, 0, 0, 1009, 1010, 1, 0, 0, 0, 1010, 1011, 3, 390, 195, 0, 1011, 1012, - 3, 602, 301, 0, 1012, 1013, 3, 372, 186, 0, 1013, 1014, 3, 604, 302, 0, - 1014, 1015, 3, 556, 278, 0, 1015, 1016, 3, 392, 196, 0, 1016, 1017, 3, - 560, 280, 0, 1017, 1018, 3, 372, 186, 0, 1018, 1019, 3, 466, 233, 0, 1019, - 1020, 3, 392, 196, 0, 1020, 1021, 3, 484, 242, 0, 1021, 1022, 3, 66, 33, - 0, 1022, 65, 1, 0, 0, 0, 1023, 1028, 3, 354, 177, 0, 1024, 1028, 3, 74, - 37, 0, 1025, 1028, 3, 72, 36, 0, 1026, 1028, 3, 68, 34, 0, 1027, 1023, - 1, 0, 0, 0, 1027, 1024, 1, 0, 0, 0, 1027, 1025, 1, 0, 0, 0, 1027, 1026, - 1, 0, 0, 0, 1028, 67, 1, 0, 0, 0, 1029, 1030, 3, 606, 303, 0, 1030, 1036, - 3, 70, 35, 0, 1031, 1032, 3, 618, 309, 0, 1032, 1033, 3, 70, 35, 0, 1033, - 1035, 1, 0, 0, 0, 1034, 1031, 1, 0, 0, 0, 1035, 1038, 1, 0, 0, 0, 1036, - 1034, 1, 0, 0, 0, 1036, 1037, 1, 0, 0, 0, 1037, 1039, 1, 0, 0, 0, 1038, - 1036, 1, 0, 0, 0, 1039, 1040, 3, 608, 304, 0, 1040, 69, 1, 0, 0, 0, 1041, - 1042, 3, 400, 200, 0, 1042, 1043, 5, 9, 0, 0, 1043, 1044, 3, 66, 33, 0, - 1044, 71, 1, 0, 0, 0, 1045, 1046, 3, 602, 301, 0, 1046, 1053, 3, 74, 37, - 0, 1047, 1048, 3, 618, 309, 0, 1048, 1049, 3, 354, 177, 0, 1049, 1052, - 1, 0, 0, 0, 1050, 1052, 3, 74, 37, 0, 1051, 1047, 1, 0, 0, 0, 1051, 1050, - 1, 0, 0, 0, 1052, 1055, 1, 0, 0, 0, 1053, 1051, 1, 0, 0, 0, 1053, 1054, - 1, 0, 0, 0, 1054, 1056, 1, 0, 0, 0, 1055, 1053, 1, 0, 0, 0, 1056, 1057, - 3, 604, 302, 0, 1057, 73, 1, 0, 0, 0, 1058, 1059, 3, 602, 301, 0, 1059, - 1065, 3, 354, 177, 0, 1060, 1061, 3, 618, 309, 0, 1061, 1062, 3, 354, 177, - 0, 1062, 1064, 1, 0, 0, 0, 1063, 1060, 1, 0, 0, 0, 1064, 1067, 1, 0, 0, - 0, 1065, 1063, 1, 0, 0, 0, 1065, 1066, 1, 0, 0, 0, 1066, 1068, 1, 0, 0, - 0, 1067, 1065, 1, 0, 0, 0, 1068, 1069, 3, 604, 302, 0, 1069, 75, 1, 0, - 0, 0, 1070, 1071, 3, 532, 266, 0, 1071, 1072, 3, 542, 271, 0, 1072, 77, - 1, 0, 0, 0, 1073, 1074, 3, 416, 208, 0, 1074, 1075, 3, 586, 293, 0, 1075, - 1076, 3, 396, 198, 0, 1076, 1077, 3, 596, 298, 0, 1077, 1079, 3, 80, 40, - 0, 1078, 1080, 3, 82, 41, 0, 1079, 1078, 1, 0, 0, 0, 1079, 1080, 1, 0, - 0, 0, 1080, 79, 1, 0, 0, 0, 1081, 1082, 3, 536, 268, 0, 1082, 1083, 3, - 360, 180, 0, 1083, 81, 1, 0, 0, 0, 1084, 1087, 3, 562, 281, 0, 1085, 1087, - 3, 518, 259, 0, 1086, 1084, 1, 0, 0, 0, 1086, 1085, 1, 0, 0, 0, 1087, 83, - 1, 0, 0, 0, 1088, 1089, 3, 416, 208, 0, 1089, 1093, 3, 578, 289, 0, 1090, - 1091, 3, 366, 183, 0, 1091, 1092, 5, 10, 0, 0, 1092, 1094, 1, 0, 0, 0, - 1093, 1090, 1, 0, 0, 0, 1093, 1094, 1, 0, 0, 0, 1094, 1095, 1, 0, 0, 0, - 1095, 1096, 3, 388, 194, 0, 1096, 1097, 3, 86, 43, 0, 1097, 85, 1, 0, 0, - 0, 1098, 1102, 3, 96, 48, 0, 1099, 1102, 3, 94, 47, 0, 1100, 1102, 3, 88, - 44, 0, 1101, 1098, 1, 0, 0, 0, 1101, 1099, 1, 0, 0, 0, 1101, 1100, 1, 0, - 0, 0, 1102, 87, 1, 0, 0, 0, 1103, 1104, 3, 540, 270, 0, 1104, 1105, 3, - 90, 45, 0, 1105, 89, 1, 0, 0, 0, 1106, 1112, 3, 92, 46, 0, 1107, 1108, - 3, 418, 209, 0, 1108, 1109, 3, 92, 46, 0, 1109, 1111, 1, 0, 0, 0, 1110, - 1107, 1, 0, 0, 0, 1111, 1114, 1, 0, 0, 0, 1112, 1110, 1, 0, 0, 0, 1112, - 1113, 1, 0, 0, 0, 1113, 91, 1, 0, 0, 0, 1114, 1112, 1, 0, 0, 0, 1115, 1116, - 3, 370, 185, 0, 1116, 1117, 3, 570, 285, 0, 1117, 1118, 3, 370, 185, 0, - 1118, 93, 1, 0, 0, 0, 1119, 1120, 3, 406, 203, 0, 1120, 1121, 3, 370, 185, - 0, 1121, 1128, 3, 372, 186, 0, 1122, 1123, 3, 618, 309, 0, 1123, 1124, - 3, 370, 185, 0, 1124, 1125, 3, 372, 186, 0, 1125, 1127, 1, 0, 0, 0, 1126, - 1122, 1, 0, 0, 0, 1127, 1130, 1, 0, 0, 0, 1128, 1126, 1, 0, 0, 0, 1128, - 1129, 1, 0, 0, 0, 1129, 95, 1, 0, 0, 0, 1130, 1128, 1, 0, 0, 0, 1131, 1132, - 3, 416, 208, 0, 1132, 1133, 3, 370, 185, 0, 1133, 1134, 3, 578, 289, 0, - 1134, 1135, 3, 372, 186, 0, 1135, 97, 1, 0, 0, 0, 1136, 1137, 3, 416, 208, - 0, 1137, 1138, 3, 564, 282, 0, 1138, 1139, 3, 298, 149, 0, 1139, 1140, - 3, 100, 50, 0, 1140, 99, 1, 0, 0, 0, 1141, 1148, 3, 118, 59, 0, 1142, 1148, - 3, 108, 54, 0, 1143, 1148, 3, 106, 53, 0, 1144, 1148, 3, 112, 56, 0, 1145, - 1148, 3, 104, 52, 0, 1146, 1148, 3, 102, 51, 0, 1147, 1141, 1, 0, 0, 0, - 1147, 1142, 1, 0, 0, 0, 1147, 1143, 1, 0, 0, 0, 1147, 1144, 1, 0, 0, 0, - 1147, 1145, 1, 0, 0, 0, 1147, 1146, 1, 0, 0, 0, 1148, 101, 1, 0, 0, 0, - 1149, 1150, 3, 596, 298, 0, 1150, 1151, 3, 158, 79, 0, 1151, 103, 1, 0, - 0, 0, 1152, 1153, 3, 540, 270, 0, 1153, 1154, 3, 370, 185, 0, 1154, 1155, - 3, 570, 285, 0, 1155, 1156, 3, 370, 185, 0, 1156, 105, 1, 0, 0, 0, 1157, - 1158, 3, 454, 227, 0, 1158, 1159, 3, 440, 220, 0, 1159, 1160, 3, 558, 279, - 0, 1160, 107, 1, 0, 0, 0, 1161, 1162, 3, 454, 227, 0, 1162, 1163, 3, 110, - 55, 0, 1163, 109, 1, 0, 0, 0, 1164, 1170, 3, 370, 185, 0, 1165, 1166, 3, - 618, 309, 0, 1166, 1167, 3, 370, 185, 0, 1167, 1169, 1, 0, 0, 0, 1168, - 1165, 1, 0, 0, 0, 1169, 1172, 1, 0, 0, 0, 1170, 1168, 1, 0, 0, 0, 1170, - 1171, 1, 0, 0, 0, 1171, 111, 1, 0, 0, 0, 1172, 1170, 1, 0, 0, 0, 1173, - 1174, 3, 416, 208, 0, 1174, 1175, 3, 114, 57, 0, 1175, 113, 1, 0, 0, 0, - 1176, 1182, 3, 116, 58, 0, 1177, 1178, 3, 618, 309, 0, 1178, 1179, 3, 116, - 58, 0, 1179, 1181, 1, 0, 0, 0, 1180, 1177, 1, 0, 0, 0, 1181, 1184, 1, 0, - 0, 0, 1182, 1180, 1, 0, 0, 0, 1182, 1183, 1, 0, 0, 0, 1183, 115, 1, 0, - 0, 0, 1184, 1182, 1, 0, 0, 0, 1185, 1186, 3, 370, 185, 0, 1186, 1187, 3, - 578, 289, 0, 1187, 1188, 3, 372, 186, 0, 1188, 117, 1, 0, 0, 0, 1189, 1190, - 3, 406, 203, 0, 1190, 1191, 3, 120, 60, 0, 1191, 119, 1, 0, 0, 0, 1192, - 1198, 3, 122, 61, 0, 1193, 1194, 3, 618, 309, 0, 1194, 1195, 3, 122, 61, - 0, 1195, 1197, 1, 0, 0, 0, 1196, 1193, 1, 0, 0, 0, 1197, 1200, 1, 0, 0, - 0, 1198, 1196, 1, 0, 0, 0, 1198, 1199, 1, 0, 0, 0, 1199, 121, 1, 0, 0, - 0, 1200, 1198, 1, 0, 0, 0, 1201, 1202, 3, 370, 185, 0, 1202, 1203, 3, 372, - 186, 0, 1203, 123, 1, 0, 0, 0, 1204, 1205, 3, 416, 208, 0, 1205, 1206, - 3, 548, 274, 0, 1206, 1208, 3, 380, 190, 0, 1207, 1209, 3, 126, 63, 0, - 1208, 1207, 1, 0, 0, 0, 1208, 1209, 1, 0, 0, 0, 1209, 125, 1, 0, 0, 0, - 1210, 1211, 3, 596, 298, 0, 1211, 1217, 3, 128, 64, 0, 1212, 1213, 3, 418, - 209, 0, 1213, 1214, 3, 128, 64, 0, 1214, 1216, 1, 0, 0, 0, 1215, 1212, - 1, 0, 0, 0, 1216, 1219, 1, 0, 0, 0, 1217, 1215, 1, 0, 0, 0, 1217, 1218, - 1, 0, 0, 0, 1218, 127, 1, 0, 0, 0, 1219, 1217, 1, 0, 0, 0, 1220, 1221, - 3, 536, 268, 0, 1221, 1222, 5, 19, 0, 0, 1222, 1223, 3, 360, 180, 0, 1223, - 1237, 1, 0, 0, 0, 1224, 1225, 3, 512, 256, 0, 1225, 1226, 5, 19, 0, 0, - 1226, 1227, 3, 362, 181, 0, 1227, 1237, 1, 0, 0, 0, 1228, 1229, 3, 562, - 281, 0, 1229, 1230, 5, 19, 0, 0, 1230, 1231, 3, 362, 181, 0, 1231, 1237, - 1, 0, 0, 0, 1232, 1233, 3, 530, 265, 0, 1233, 1234, 5, 19, 0, 0, 1234, - 1235, 3, 166, 83, 0, 1235, 1237, 1, 0, 0, 0, 1236, 1220, 1, 0, 0, 0, 1236, - 1224, 1, 0, 0, 0, 1236, 1228, 1, 0, 0, 0, 1236, 1232, 1, 0, 0, 0, 1237, - 129, 1, 0, 0, 0, 1238, 1239, 3, 416, 208, 0, 1239, 1240, 3, 514, 257, 0, - 1240, 1244, 3, 592, 296, 0, 1241, 1242, 3, 366, 183, 0, 1242, 1243, 5, - 10, 0, 0, 1243, 1245, 1, 0, 0, 0, 1244, 1241, 1, 0, 0, 0, 1244, 1245, 1, - 0, 0, 0, 1245, 1246, 1, 0, 0, 0, 1246, 1250, 3, 386, 193, 0, 1247, 1248, - 3, 596, 298, 0, 1248, 1249, 3, 158, 79, 0, 1249, 1251, 1, 0, 0, 0, 1250, - 1247, 1, 0, 0, 0, 1250, 1251, 1, 0, 0, 0, 1251, 131, 1, 0, 0, 0, 1252, - 1253, 3, 454, 227, 0, 1253, 1255, 3, 586, 293, 0, 1254, 1256, 3, 278, 139, - 0, 1255, 1254, 1, 0, 0, 0, 1255, 1256, 1, 0, 0, 0, 1256, 1257, 1, 0, 0, - 0, 1257, 1258, 3, 396, 198, 0, 1258, 133, 1, 0, 0, 0, 1259, 1260, 3, 454, - 227, 0, 1260, 1262, 3, 578, 289, 0, 1261, 1263, 3, 278, 139, 0, 1262, 1261, - 1, 0, 0, 0, 1262, 1263, 1, 0, 0, 0, 1263, 1267, 1, 0, 0, 0, 1264, 1265, - 3, 366, 183, 0, 1265, 1266, 5, 10, 0, 0, 1266, 1268, 1, 0, 0, 0, 1267, - 1264, 1, 0, 0, 0, 1267, 1268, 1, 0, 0, 0, 1268, 1269, 1, 0, 0, 0, 1269, - 1270, 3, 388, 194, 0, 1270, 135, 1, 0, 0, 0, 1271, 1272, 3, 454, 227, 0, - 1272, 1273, 3, 514, 257, 0, 1273, 1275, 3, 592, 296, 0, 1274, 1276, 3, - 278, 139, 0, 1275, 1274, 1, 0, 0, 0, 1275, 1276, 1, 0, 0, 0, 1276, 1280, - 1, 0, 0, 0, 1277, 1278, 3, 366, 183, 0, 1278, 1279, 5, 10, 0, 0, 1279, - 1281, 1, 0, 0, 0, 1280, 1277, 1, 0, 0, 0, 1280, 1281, 1, 0, 0, 0, 1281, - 1282, 1, 0, 0, 0, 1282, 1283, 3, 386, 193, 0, 1283, 137, 1, 0, 0, 0, 1284, - 1285, 3, 454, 227, 0, 1285, 1287, 3, 408, 204, 0, 1286, 1288, 3, 278, 139, - 0, 1287, 1286, 1, 0, 0, 0, 1287, 1288, 1, 0, 0, 0, 1288, 1292, 1, 0, 0, - 0, 1289, 1290, 3, 366, 183, 0, 1290, 1291, 5, 10, 0, 0, 1291, 1293, 1, - 0, 0, 0, 1292, 1289, 1, 0, 0, 0, 1292, 1293, 1, 0, 0, 0, 1293, 1294, 1, - 0, 0, 0, 1294, 1295, 3, 390, 195, 0, 1295, 139, 1, 0, 0, 0, 1296, 1297, - 3, 454, 227, 0, 1297, 1299, 3, 472, 236, 0, 1298, 1300, 3, 278, 139, 0, - 1299, 1298, 1, 0, 0, 0, 1299, 1300, 1, 0, 0, 0, 1300, 1304, 1, 0, 0, 0, - 1301, 1302, 3, 366, 183, 0, 1302, 1303, 5, 10, 0, 0, 1303, 1305, 1, 0, - 0, 0, 1304, 1301, 1, 0, 0, 0, 1304, 1305, 1, 0, 0, 0, 1305, 1306, 1, 0, - 0, 0, 1306, 1307, 3, 392, 196, 0, 1307, 141, 1, 0, 0, 0, 1308, 1309, 3, - 454, 227, 0, 1309, 1311, 3, 572, 286, 0, 1310, 1312, 3, 278, 139, 0, 1311, - 1310, 1, 0, 0, 0, 1311, 1312, 1, 0, 0, 0, 1312, 1313, 1, 0, 0, 0, 1313, - 1314, 3, 382, 191, 0, 1314, 1315, 3, 528, 264, 0, 1315, 1316, 3, 298, 149, - 0, 1316, 143, 1, 0, 0, 0, 1317, 1318, 3, 454, 227, 0, 1318, 1320, 3, 548, - 274, 0, 1319, 1321, 3, 278, 139, 0, 1320, 1319, 1, 0, 0, 0, 1320, 1321, - 1, 0, 0, 0, 1321, 1322, 1, 0, 0, 0, 1322, 1323, 3, 380, 190, 0, 1323, 145, - 1, 0, 0, 0, 1324, 1325, 3, 454, 227, 0, 1325, 1327, 3, 564, 282, 0, 1326, - 1328, 3, 278, 139, 0, 1327, 1326, 1, 0, 0, 0, 1327, 1328, 1, 0, 0, 0, 1328, - 1329, 1, 0, 0, 0, 1329, 1330, 3, 298, 149, 0, 1330, 147, 1, 0, 0, 0, 1331, - 1332, 3, 454, 227, 0, 1332, 1334, 3, 500, 250, 0, 1333, 1335, 3, 278, 139, - 0, 1334, 1333, 1, 0, 0, 0, 1334, 1335, 1, 0, 0, 0, 1335, 1336, 1, 0, 0, - 0, 1336, 1337, 3, 366, 183, 0, 1337, 149, 1, 0, 0, 0, 1338, 1339, 3, 454, - 227, 0, 1339, 1341, 3, 482, 241, 0, 1340, 1342, 3, 278, 139, 0, 1341, 1340, - 1, 0, 0, 0, 1341, 1342, 1, 0, 0, 0, 1342, 1346, 1, 0, 0, 0, 1343, 1344, - 3, 366, 183, 0, 1344, 1345, 5, 10, 0, 0, 1345, 1347, 1, 0, 0, 0, 1346, - 1343, 1, 0, 0, 0, 1346, 1347, 1, 0, 0, 0, 1347, 1348, 1, 0, 0, 0, 1348, - 1349, 3, 218, 109, 0, 1349, 151, 1, 0, 0, 0, 1350, 1351, 3, 444, 222, 0, - 1351, 1353, 3, 564, 282, 0, 1352, 1354, 3, 276, 138, 0, 1353, 1352, 1, - 0, 0, 0, 1353, 1354, 1, 0, 0, 0, 1354, 1355, 1, 0, 0, 0, 1355, 1356, 3, - 298, 149, 0, 1356, 1357, 3, 602, 301, 0, 1357, 1358, 3, 174, 87, 0, 1358, - 1360, 3, 604, 302, 0, 1359, 1361, 3, 154, 77, 0, 1360, 1359, 1, 0, 0, 0, - 1360, 1361, 1, 0, 0, 0, 1361, 153, 1, 0, 0, 0, 1362, 1364, 3, 596, 298, - 0, 1363, 1365, 3, 158, 79, 0, 1364, 1363, 1, 0, 0, 0, 1364, 1365, 1, 0, - 0, 0, 1365, 1367, 1, 0, 0, 0, 1366, 1368, 3, 156, 78, 0, 1367, 1366, 1, - 0, 0, 0, 1367, 1368, 1, 0, 0, 0, 1368, 155, 1, 0, 0, 0, 1369, 1370, 3, - 438, 219, 0, 1370, 1371, 3, 534, 267, 0, 1371, 1372, 3, 434, 217, 0, 1372, - 1373, 3, 602, 301, 0, 1373, 1375, 3, 370, 185, 0, 1374, 1376, 3, 378, 189, - 0, 1375, 1374, 1, 0, 0, 0, 1375, 1376, 1, 0, 0, 0, 1376, 1377, 1, 0, 0, - 0, 1377, 1378, 3, 604, 302, 0, 1378, 157, 1, 0, 0, 0, 1379, 1385, 3, 160, - 80, 0, 1380, 1381, 3, 418, 209, 0, 1381, 1382, 3, 160, 80, 0, 1382, 1384, - 1, 0, 0, 0, 1383, 1380, 1, 0, 0, 0, 1384, 1387, 1, 0, 0, 0, 1385, 1383, - 1, 0, 0, 0, 1385, 1386, 1, 0, 0, 0, 1386, 159, 1, 0, 0, 0, 1387, 1385, - 1, 0, 0, 0, 1388, 1389, 3, 162, 81, 0, 1389, 1390, 5, 19, 0, 0, 1390, 1391, - 3, 164, 82, 0, 1391, 1397, 1, 0, 0, 0, 1392, 1393, 3, 162, 81, 0, 1393, - 1394, 5, 19, 0, 0, 1394, 1395, 3, 166, 83, 0, 1395, 1397, 1, 0, 0, 0, 1396, - 1388, 1, 0, 0, 0, 1396, 1392, 1, 0, 0, 0, 1397, 161, 1, 0, 0, 0, 1398, - 1399, 5, 174, 0, 0, 1399, 163, 1, 0, 0, 0, 1400, 1403, 3, 360, 180, 0, - 1401, 1403, 3, 358, 179, 0, 1402, 1400, 1, 0, 0, 0, 1402, 1401, 1, 0, 0, - 0, 1403, 165, 1, 0, 0, 0, 1404, 1405, 3, 606, 303, 0, 1405, 1411, 3, 168, - 84, 0, 1406, 1407, 3, 618, 309, 0, 1407, 1408, 3, 168, 84, 0, 1408, 1410, - 1, 0, 0, 0, 1409, 1406, 1, 0, 0, 0, 1410, 1413, 1, 0, 0, 0, 1411, 1409, - 1, 0, 0, 0, 1411, 1412, 1, 0, 0, 0, 1412, 1414, 1, 0, 0, 0, 1413, 1411, - 1, 0, 0, 0, 1414, 1415, 3, 608, 304, 0, 1415, 167, 1, 0, 0, 0, 1416, 1417, - 3, 170, 85, 0, 1417, 1418, 5, 9, 0, 0, 1418, 1419, 3, 172, 86, 0, 1419, - 169, 1, 0, 0, 0, 1420, 1421, 3, 360, 180, 0, 1421, 171, 1, 0, 0, 0, 1422, - 1425, 3, 360, 180, 0, 1423, 1425, 3, 358, 179, 0, 1424, 1422, 1, 0, 0, - 0, 1424, 1423, 1, 0, 0, 0, 1425, 173, 1, 0, 0, 0, 1426, 1432, 3, 176, 88, - 0, 1427, 1428, 3, 618, 309, 0, 1428, 1429, 3, 176, 88, 0, 1429, 1431, 1, - 0, 0, 0, 1430, 1427, 1, 0, 0, 0, 1431, 1434, 1, 0, 0, 0, 1432, 1430, 1, - 0, 0, 0, 1432, 1433, 1, 0, 0, 0, 1433, 1438, 1, 0, 0, 0, 1434, 1432, 1, - 0, 0, 0, 1435, 1436, 3, 618, 309, 0, 1436, 1437, 3, 180, 90, 0, 1437, 1439, - 1, 0, 0, 0, 1438, 1435, 1, 0, 0, 0, 1438, 1439, 1, 0, 0, 0, 1439, 175, - 1, 0, 0, 0, 1440, 1441, 3, 370, 185, 0, 1441, 1443, 3, 372, 186, 0, 1442, - 1444, 3, 178, 89, 0, 1443, 1442, 1, 0, 0, 0, 1443, 1444, 1, 0, 0, 0, 1444, - 177, 1, 0, 0, 0, 1445, 1446, 3, 538, 269, 0, 1446, 1447, 3, 496, 248, 0, - 1447, 179, 1, 0, 0, 0, 1448, 1449, 3, 538, 269, 0, 1449, 1450, 3, 496, - 248, 0, 1450, 1451, 3, 602, 301, 0, 1451, 1452, 3, 182, 91, 0, 1452, 1453, - 3, 604, 302, 0, 1453, 181, 1, 0, 0, 0, 1454, 1458, 3, 184, 92, 0, 1455, - 1458, 3, 186, 93, 0, 1456, 1458, 3, 188, 94, 0, 1457, 1454, 1, 0, 0, 0, - 1457, 1455, 1, 0, 0, 0, 1457, 1456, 1, 0, 0, 0, 1458, 183, 1, 0, 0, 0, - 1459, 1460, 3, 370, 185, 0, 1460, 185, 1, 0, 0, 0, 1461, 1462, 3, 194, - 97, 0, 1462, 1463, 3, 618, 309, 0, 1463, 1464, 3, 192, 96, 0, 1464, 187, - 1, 0, 0, 0, 1465, 1466, 3, 602, 301, 0, 1466, 1467, 3, 190, 95, 0, 1467, - 1468, 3, 604, 302, 0, 1468, 1469, 3, 618, 309, 0, 1469, 1470, 3, 192, 96, - 0, 1470, 189, 1, 0, 0, 0, 1471, 1477, 3, 194, 97, 0, 1472, 1473, 3, 618, - 309, 0, 1473, 1474, 3, 194, 97, 0, 1474, 1476, 1, 0, 0, 0, 1475, 1472, - 1, 0, 0, 0, 1476, 1479, 1, 0, 0, 0, 1477, 1475, 1, 0, 0, 0, 1477, 1478, - 1, 0, 0, 0, 1478, 191, 1, 0, 0, 0, 1479, 1477, 1, 0, 0, 0, 1480, 1486, - 3, 196, 98, 0, 1481, 1482, 3, 618, 309, 0, 1482, 1483, 3, 196, 98, 0, 1483, - 1485, 1, 0, 0, 0, 1484, 1481, 1, 0, 0, 0, 1485, 1488, 1, 0, 0, 0, 1486, - 1484, 1, 0, 0, 0, 1486, 1487, 1, 0, 0, 0, 1487, 193, 1, 0, 0, 0, 1488, - 1486, 1, 0, 0, 0, 1489, 1490, 3, 370, 185, 0, 1490, 195, 1, 0, 0, 0, 1491, - 1492, 3, 370, 185, 0, 1492, 197, 1, 0, 0, 0, 1493, 1494, 3, 420, 210, 0, - 1494, 1495, 3, 428, 214, 0, 1495, 199, 1, 0, 0, 0, 1496, 1498, 3, 432, - 216, 0, 1497, 1499, 3, 202, 101, 0, 1498, 1497, 1, 0, 0, 0, 1498, 1499, - 1, 0, 0, 0, 1499, 1500, 1, 0, 0, 0, 1500, 1502, 3, 428, 214, 0, 1501, 1503, - 3, 274, 137, 0, 1502, 1501, 1, 0, 0, 0, 1502, 1503, 1, 0, 0, 0, 1503, 201, - 1, 0, 0, 0, 1504, 1507, 3, 510, 255, 0, 1505, 1507, 3, 580, 290, 0, 1506, - 1504, 1, 0, 0, 0, 1506, 1505, 1, 0, 0, 0, 1507, 203, 1, 0, 0, 0, 1508, - 1509, 3, 416, 208, 0, 1509, 1510, 3, 500, 250, 0, 1510, 1511, 3, 366, 183, - 0, 1511, 1512, 3, 596, 298, 0, 1512, 1513, 3, 544, 272, 0, 1513, 1514, - 5, 19, 0, 0, 1514, 1515, 3, 606, 303, 0, 1515, 1516, 3, 206, 103, 0, 1516, - 1520, 3, 608, 304, 0, 1517, 1518, 3, 418, 209, 0, 1518, 1519, 3, 210, 105, - 0, 1519, 1521, 1, 0, 0, 0, 1520, 1517, 1, 0, 0, 0, 1520, 1521, 1, 0, 0, - 0, 1521, 205, 1, 0, 0, 0, 1522, 1528, 3, 208, 104, 0, 1523, 1524, 3, 618, - 309, 0, 1524, 1525, 3, 208, 104, 0, 1525, 1527, 1, 0, 0, 0, 1526, 1523, - 1, 0, 0, 0, 1527, 1530, 1, 0, 0, 0, 1528, 1526, 1, 0, 0, 0, 1528, 1529, - 1, 0, 0, 0, 1529, 207, 1, 0, 0, 0, 1530, 1528, 1, 0, 0, 0, 1531, 1532, - 5, 169, 0, 0, 1532, 1533, 5, 9, 0, 0, 1533, 1538, 5, 169, 0, 0, 1534, 1535, - 5, 169, 0, 0, 1535, 1536, 5, 9, 0, 0, 1536, 1538, 5, 170, 0, 0, 1537, 1531, - 1, 0, 0, 0, 1537, 1534, 1, 0, 0, 0, 1538, 209, 1, 0, 0, 0, 1539, 1540, - 3, 456, 228, 0, 1540, 1541, 5, 19, 0, 0, 1541, 1542, 3, 362, 181, 0, 1542, - 211, 1, 0, 0, 0, 1543, 1544, 3, 584, 292, 0, 1544, 1545, 3, 366, 183, 0, - 1545, 213, 1, 0, 0, 0, 1546, 1548, 3, 574, 287, 0, 1547, 1549, 3, 564, - 282, 0, 1548, 1547, 1, 0, 0, 0, 1548, 1549, 1, 0, 0, 0, 1549, 1550, 1, - 0, 0, 0, 1550, 1551, 3, 298, 149, 0, 1551, 215, 1, 0, 0, 0, 1552, 1553, - 3, 444, 222, 0, 1553, 1555, 3, 482, 241, 0, 1554, 1556, 3, 276, 138, 0, - 1555, 1554, 1, 0, 0, 0, 1555, 1556, 1, 0, 0, 0, 1556, 1558, 1, 0, 0, 0, - 1557, 1559, 3, 218, 109, 0, 1558, 1557, 1, 0, 0, 0, 1558, 1559, 1, 0, 0, - 0, 1559, 1560, 1, 0, 0, 0, 1560, 1561, 3, 528, 264, 0, 1561, 1562, 3, 298, - 149, 0, 1562, 1563, 3, 602, 301, 0, 1563, 1564, 3, 220, 110, 0, 1564, 1565, - 3, 604, 302, 0, 1565, 217, 1, 0, 0, 0, 1566, 1569, 5, 174, 0, 0, 1567, - 1569, 3, 360, 180, 0, 1568, 1566, 1, 0, 0, 0, 1568, 1567, 1, 0, 0, 0, 1569, - 219, 1, 0, 0, 0, 1570, 1575, 3, 370, 185, 0, 1571, 1575, 3, 222, 111, 0, - 1572, 1575, 3, 224, 112, 0, 1573, 1575, 3, 226, 113, 0, 1574, 1570, 1, - 0, 0, 0, 1574, 1571, 1, 0, 0, 0, 1574, 1572, 1, 0, 0, 0, 1574, 1573, 1, - 0, 0, 0, 1575, 221, 1, 0, 0, 0, 1576, 1577, 3, 498, 249, 0, 1577, 1578, - 3, 602, 301, 0, 1578, 1579, 5, 174, 0, 0, 1579, 1580, 3, 604, 302, 0, 1580, - 223, 1, 0, 0, 0, 1581, 1582, 3, 458, 229, 0, 1582, 1583, 3, 602, 301, 0, - 1583, 1584, 5, 174, 0, 0, 1584, 1585, 3, 604, 302, 0, 1585, 225, 1, 0, - 0, 0, 1586, 1587, 3, 470, 235, 0, 1587, 1588, 3, 602, 301, 0, 1588, 1589, - 5, 174, 0, 0, 1589, 1590, 3, 604, 302, 0, 1590, 227, 1, 0, 0, 0, 1591, - 1593, 3, 200, 100, 0, 1592, 1591, 1, 0, 0, 0, 1592, 1593, 1, 0, 0, 0, 1593, - 1594, 1, 0, 0, 0, 1594, 1596, 3, 446, 223, 0, 1595, 1597, 3, 230, 115, - 0, 1596, 1595, 1, 0, 0, 0, 1596, 1597, 1, 0, 0, 0, 1597, 1598, 1, 0, 0, - 0, 1598, 1600, 3, 300, 150, 0, 1599, 1601, 3, 274, 137, 0, 1600, 1599, - 1, 0, 0, 0, 1600, 1601, 1, 0, 0, 0, 1601, 1602, 1, 0, 0, 0, 1602, 1605, - 3, 306, 153, 0, 1603, 1606, 3, 278, 139, 0, 1604, 1606, 3, 236, 118, 0, - 1605, 1603, 1, 0, 0, 0, 1605, 1604, 1, 0, 0, 0, 1605, 1606, 1, 0, 0, 0, - 1606, 1608, 1, 0, 0, 0, 1607, 1609, 3, 4, 2, 0, 1608, 1607, 1, 0, 0, 0, - 1608, 1609, 1, 0, 0, 0, 1609, 229, 1, 0, 0, 0, 1610, 1616, 3, 232, 116, - 0, 1611, 1612, 3, 618, 309, 0, 1612, 1613, 3, 232, 116, 0, 1613, 1615, - 1, 0, 0, 0, 1614, 1611, 1, 0, 0, 0, 1615, 1618, 1, 0, 0, 0, 1616, 1614, - 1, 0, 0, 0, 1616, 1617, 1, 0, 0, 0, 1617, 231, 1, 0, 0, 0, 1618, 1616, - 1, 0, 0, 0, 1619, 1621, 3, 314, 157, 0, 1620, 1622, 3, 320, 160, 0, 1621, - 1620, 1, 0, 0, 0, 1621, 1622, 1, 0, 0, 0, 1622, 1628, 1, 0, 0, 0, 1623, - 1625, 3, 318, 159, 0, 1624, 1626, 3, 320, 160, 0, 1625, 1624, 1, 0, 0, - 0, 1625, 1626, 1, 0, 0, 0, 1626, 1628, 1, 0, 0, 0, 1627, 1619, 1, 0, 0, - 0, 1627, 1623, 1, 0, 0, 0, 1628, 233, 1, 0, 0, 0, 1629, 1631, 3, 200, 100, - 0, 1630, 1629, 1, 0, 0, 0, 1630, 1631, 1, 0, 0, 0, 1631, 1632, 1, 0, 0, - 0, 1632, 1633, 3, 582, 291, 0, 1633, 1635, 3, 298, 149, 0, 1634, 1636, - 3, 268, 134, 0, 1635, 1634, 1, 0, 0, 0, 1635, 1636, 1, 0, 0, 0, 1636, 1637, - 1, 0, 0, 0, 1637, 1638, 3, 554, 277, 0, 1638, 1639, 3, 242, 121, 0, 1639, - 1642, 3, 306, 153, 0, 1640, 1643, 3, 278, 139, 0, 1641, 1643, 3, 236, 118, - 0, 1642, 1640, 1, 0, 0, 0, 1642, 1641, 1, 0, 0, 0, 1642, 1643, 1, 0, 0, - 0, 1643, 1645, 1, 0, 0, 0, 1644, 1646, 3, 4, 2, 0, 1645, 1644, 1, 0, 0, - 0, 1645, 1646, 1, 0, 0, 0, 1646, 235, 1, 0, 0, 0, 1647, 1648, 3, 478, 239, - 0, 1648, 1649, 3, 238, 119, 0, 1649, 237, 1, 0, 0, 0, 1650, 1656, 3, 240, - 120, 0, 1651, 1652, 3, 418, 209, 0, 1652, 1653, 3, 240, 120, 0, 1653, 1655, - 1, 0, 0, 0, 1654, 1651, 1, 0, 0, 0, 1655, 1658, 1, 0, 0, 0, 1656, 1654, - 1, 0, 0, 0, 1656, 1657, 1, 0, 0, 0, 1657, 239, 1, 0, 0, 0, 1658, 1656, - 1, 0, 0, 0, 1659, 1660, 5, 174, 0, 0, 1660, 1661, 5, 19, 0, 0, 1661, 1662, - 3, 354, 177, 0, 1662, 241, 1, 0, 0, 0, 1663, 1669, 3, 244, 122, 0, 1664, - 1665, 3, 618, 309, 0, 1665, 1666, 3, 244, 122, 0, 1666, 1668, 1, 0, 0, - 0, 1667, 1664, 1, 0, 0, 0, 1668, 1671, 1, 0, 0, 0, 1669, 1667, 1, 0, 0, - 0, 1669, 1670, 1, 0, 0, 0, 1670, 243, 1, 0, 0, 0, 1671, 1669, 1, 0, 0, - 0, 1672, 1677, 3, 250, 125, 0, 1673, 1677, 3, 248, 124, 0, 1674, 1677, - 3, 246, 123, 0, 1675, 1677, 3, 254, 127, 0, 1676, 1672, 1, 0, 0, 0, 1676, - 1673, 1, 0, 0, 0, 1676, 1674, 1, 0, 0, 0, 1676, 1675, 1, 0, 0, 0, 1677, - 245, 1, 0, 0, 0, 1678, 1679, 3, 370, 185, 0, 1679, 1680, 5, 19, 0, 0, 1680, - 1681, 3, 352, 176, 0, 1681, 247, 1, 0, 0, 0, 1682, 1683, 3, 370, 185, 0, - 1683, 1684, 5, 19, 0, 0, 1684, 1685, 3, 352, 176, 0, 1685, 1686, 3, 262, - 131, 0, 1686, 1687, 5, 174, 0, 0, 1687, 249, 1, 0, 0, 0, 1688, 1689, 3, - 370, 185, 0, 1689, 1690, 5, 19, 0, 0, 1690, 1691, 5, 174, 0, 0, 1691, 1692, - 3, 262, 131, 0, 1692, 1693, 3, 352, 176, 0, 1693, 251, 1, 0, 0, 0, 1694, - 1695, 3, 614, 307, 0, 1695, 1696, 3, 354, 177, 0, 1696, 1697, 3, 616, 308, - 0, 1697, 253, 1, 0, 0, 0, 1698, 1699, 3, 370, 185, 0, 1699, 1700, 3, 252, - 126, 0, 1700, 1701, 5, 19, 0, 0, 1701, 1702, 3, 354, 177, 0, 1702, 255, - 1, 0, 0, 0, 1703, 1713, 3, 606, 303, 0, 1704, 1710, 3, 354, 177, 0, 1705, - 1706, 3, 618, 309, 0, 1706, 1707, 3, 354, 177, 0, 1707, 1709, 1, 0, 0, - 0, 1708, 1705, 1, 0, 0, 0, 1709, 1712, 1, 0, 0, 0, 1710, 1708, 1, 0, 0, - 0, 1710, 1711, 1, 0, 0, 0, 1711, 1714, 1, 0, 0, 0, 1712, 1710, 1, 0, 0, - 0, 1713, 1704, 1, 0, 0, 0, 1713, 1714, 1, 0, 0, 0, 1714, 1715, 1, 0, 0, - 0, 1715, 1716, 3, 608, 304, 0, 1716, 257, 1, 0, 0, 0, 1717, 1718, 3, 606, - 303, 0, 1718, 1719, 3, 354, 177, 0, 1719, 1720, 3, 620, 310, 0, 1720, 1721, - 3, 354, 177, 0, 1721, 1729, 1, 0, 0, 0, 1722, 1723, 3, 618, 309, 0, 1723, - 1724, 3, 354, 177, 0, 1724, 1725, 3, 620, 310, 0, 1725, 1726, 3, 354, 177, - 0, 1726, 1728, 1, 0, 0, 0, 1727, 1722, 1, 0, 0, 0, 1728, 1731, 1, 0, 0, - 0, 1729, 1727, 1, 0, 0, 0, 1729, 1730, 1, 0, 0, 0, 1730, 1732, 1, 0, 0, - 0, 1731, 1729, 1, 0, 0, 0, 1732, 1733, 3, 608, 304, 0, 1733, 259, 1, 0, - 0, 0, 1734, 1744, 3, 614, 307, 0, 1735, 1741, 3, 354, 177, 0, 1736, 1737, - 3, 618, 309, 0, 1737, 1738, 3, 354, 177, 0, 1738, 1740, 1, 0, 0, 0, 1739, - 1736, 1, 0, 0, 0, 1740, 1743, 1, 0, 0, 0, 1741, 1739, 1, 0, 0, 0, 1741, - 1742, 1, 0, 0, 0, 1742, 1745, 1, 0, 0, 0, 1743, 1741, 1, 0, 0, 0, 1744, - 1735, 1, 0, 0, 0, 1744, 1745, 1, 0, 0, 0, 1745, 1746, 1, 0, 0, 0, 1746, - 1747, 3, 616, 308, 0, 1747, 261, 1, 0, 0, 0, 1748, 1749, 7, 1, 0, 0, 1749, - 263, 1, 0, 0, 0, 1750, 1751, 3, 602, 301, 0, 1751, 1757, 3, 288, 144, 0, - 1752, 1753, 3, 618, 309, 0, 1753, 1754, 3, 288, 144, 0, 1754, 1756, 1, - 0, 0, 0, 1755, 1752, 1, 0, 0, 0, 1756, 1759, 1, 0, 0, 0, 1757, 1755, 1, - 0, 0, 0, 1757, 1758, 1, 0, 0, 0, 1758, 1760, 1, 0, 0, 0, 1759, 1757, 1, - 0, 0, 0, 1760, 1761, 3, 604, 302, 0, 1761, 265, 1, 0, 0, 0, 1762, 1764, - 3, 200, 100, 0, 1763, 1762, 1, 0, 0, 0, 1763, 1764, 1, 0, 0, 0, 1764, 1765, - 1, 0, 0, 0, 1765, 1766, 3, 488, 244, 0, 1766, 1767, 3, 490, 245, 0, 1767, - 1769, 3, 298, 149, 0, 1768, 1770, 3, 282, 141, 0, 1769, 1768, 1, 0, 0, - 0, 1769, 1770, 1, 0, 0, 0, 1770, 1771, 1, 0, 0, 0, 1771, 1773, 3, 280, - 140, 0, 1772, 1774, 3, 276, 138, 0, 1773, 1772, 1, 0, 0, 0, 1773, 1774, - 1, 0, 0, 0, 1774, 1776, 1, 0, 0, 0, 1775, 1777, 3, 268, 134, 0, 1776, 1775, - 1, 0, 0, 0, 1776, 1777, 1, 0, 0, 0, 1777, 1779, 1, 0, 0, 0, 1778, 1780, - 3, 4, 2, 0, 1779, 1778, 1, 0, 0, 0, 1779, 1780, 1, 0, 0, 0, 1780, 267, - 1, 0, 0, 0, 1781, 1782, 3, 588, 294, 0, 1782, 1783, 3, 272, 136, 0, 1783, - 1798, 1, 0, 0, 0, 1784, 1785, 3, 588, 294, 0, 1785, 1786, 3, 272, 136, - 0, 1786, 1787, 3, 418, 209, 0, 1787, 1788, 3, 270, 135, 0, 1788, 1798, - 1, 0, 0, 0, 1789, 1790, 3, 588, 294, 0, 1790, 1791, 3, 270, 135, 0, 1791, - 1798, 1, 0, 0, 0, 1792, 1793, 3, 588, 294, 0, 1793, 1794, 3, 270, 135, - 0, 1794, 1795, 3, 418, 209, 0, 1795, 1796, 3, 272, 136, 0, 1796, 1798, - 1, 0, 0, 0, 1797, 1781, 1, 0, 0, 0, 1797, 1784, 1, 0, 0, 0, 1797, 1789, - 1, 0, 0, 0, 1797, 1792, 1, 0, 0, 0, 1798, 269, 1, 0, 0, 0, 1799, 1802, - 3, 568, 284, 0, 1800, 1803, 3, 338, 169, 0, 1801, 1803, 3, 356, 178, 0, - 1802, 1800, 1, 0, 0, 0, 1802, 1801, 1, 0, 0, 0, 1803, 271, 1, 0, 0, 0, - 1804, 1805, 3, 576, 288, 0, 1805, 1806, 3, 356, 178, 0, 1806, 273, 1, 0, - 0, 0, 1807, 1808, 3, 588, 294, 0, 1808, 1809, 3, 270, 135, 0, 1809, 275, - 1, 0, 0, 0, 1810, 1811, 3, 478, 239, 0, 1811, 1812, 3, 522, 261, 0, 1812, - 1813, 3, 462, 231, 0, 1813, 277, 1, 0, 0, 0, 1814, 1815, 3, 478, 239, 0, - 1815, 1816, 3, 462, 231, 0, 1816, 279, 1, 0, 0, 0, 1817, 1818, 3, 590, - 295, 0, 1818, 1819, 5, 1, 0, 0, 1819, 1820, 3, 286, 143, 0, 1820, 1821, - 5, 2, 0, 0, 1821, 1826, 1, 0, 0, 0, 1822, 1823, 3, 494, 247, 0, 1823, 1824, - 3, 354, 177, 0, 1824, 1826, 1, 0, 0, 0, 1825, 1817, 1, 0, 0, 0, 1825, 1822, - 1, 0, 0, 0, 1826, 281, 1, 0, 0, 0, 1827, 1828, 5, 1, 0, 0, 1828, 1829, - 3, 284, 142, 0, 1829, 1830, 5, 2, 0, 0, 1830, 283, 1, 0, 0, 0, 1831, 1837, - 3, 370, 185, 0, 1832, 1833, 3, 618, 309, 0, 1833, 1834, 3, 370, 185, 0, - 1834, 1836, 1, 0, 0, 0, 1835, 1832, 1, 0, 0, 0, 1836, 1839, 1, 0, 0, 0, - 1837, 1835, 1, 0, 0, 0, 1837, 1838, 1, 0, 0, 0, 1838, 285, 1, 0, 0, 0, - 1839, 1837, 1, 0, 0, 0, 1840, 1846, 3, 352, 176, 0, 1841, 1842, 3, 618, - 309, 0, 1842, 1843, 3, 352, 176, 0, 1843, 1845, 1, 0, 0, 0, 1844, 1841, - 1, 0, 0, 0, 1845, 1848, 1, 0, 0, 0, 1846, 1844, 1, 0, 0, 0, 1846, 1847, - 1, 0, 0, 0, 1847, 287, 1, 0, 0, 0, 1848, 1846, 1, 0, 0, 0, 1849, 1856, - 3, 354, 177, 0, 1850, 1856, 3, 348, 174, 0, 1851, 1856, 3, 258, 129, 0, - 1852, 1856, 3, 256, 128, 0, 1853, 1856, 3, 260, 130, 0, 1854, 1856, 3, - 264, 132, 0, 1855, 1849, 1, 0, 0, 0, 1855, 1850, 1, 0, 0, 0, 1855, 1851, - 1, 0, 0, 0, 1855, 1852, 1, 0, 0, 0, 1855, 1853, 1, 0, 0, 0, 1855, 1854, - 1, 0, 0, 0, 1856, 289, 1, 0, 0, 0, 1857, 1859, 3, 552, 276, 0, 1858, 1860, - 3, 308, 154, 0, 1859, 1858, 1, 0, 0, 0, 1859, 1860, 1, 0, 0, 0, 1860, 1862, - 1, 0, 0, 0, 1861, 1863, 3, 494, 247, 0, 1862, 1861, 1, 0, 0, 0, 1862, 1863, - 1, 0, 0, 0, 1863, 1864, 1, 0, 0, 0, 1864, 1865, 3, 310, 155, 0, 1865, 1867, - 3, 300, 150, 0, 1866, 1868, 3, 306, 153, 0, 1867, 1866, 1, 0, 0, 0, 1867, - 1868, 1, 0, 0, 0, 1868, 1870, 1, 0, 0, 0, 1869, 1871, 3, 622, 311, 0, 1870, - 1869, 1, 0, 0, 0, 1870, 1871, 1, 0, 0, 0, 1871, 1873, 1, 0, 0, 0, 1872, - 1874, 3, 302, 151, 0, 1873, 1872, 1, 0, 0, 0, 1873, 1874, 1, 0, 0, 0, 1874, - 1876, 1, 0, 0, 0, 1875, 1877, 3, 294, 147, 0, 1876, 1875, 1, 0, 0, 0, 1876, - 1877, 1, 0, 0, 0, 1877, 1879, 1, 0, 0, 0, 1878, 1880, 3, 292, 146, 0, 1879, - 1878, 1, 0, 0, 0, 1879, 1880, 1, 0, 0, 0, 1880, 1882, 1, 0, 0, 0, 1881, - 1883, 3, 4, 2, 0, 1882, 1881, 1, 0, 0, 0, 1882, 1883, 1, 0, 0, 0, 1883, - 291, 1, 0, 0, 0, 1884, 1885, 3, 414, 207, 0, 1885, 1886, 3, 464, 232, 0, - 1886, 293, 1, 0, 0, 0, 1887, 1890, 3, 506, 253, 0, 1888, 1891, 3, 338, - 169, 0, 1889, 1891, 3, 356, 178, 0, 1890, 1888, 1, 0, 0, 0, 1890, 1889, - 1, 0, 0, 0, 1891, 295, 1, 0, 0, 0, 1892, 1893, 5, 83, 0, 0, 1893, 297, - 1, 0, 0, 0, 1894, 1895, 3, 366, 183, 0, 1895, 1896, 5, 10, 0, 0, 1896, - 1898, 1, 0, 0, 0, 1897, 1894, 1, 0, 0, 0, 1897, 1898, 1, 0, 0, 0, 1898, - 1899, 1, 0, 0, 0, 1899, 1900, 3, 368, 184, 0, 1900, 299, 1, 0, 0, 0, 1901, - 1902, 3, 468, 234, 0, 1902, 1903, 3, 298, 149, 0, 1903, 301, 1, 0, 0, 0, - 1904, 1905, 3, 534, 267, 0, 1905, 1906, 3, 434, 217, 0, 1906, 1912, 3, - 304, 152, 0, 1907, 1908, 3, 618, 309, 0, 1908, 1909, 3, 304, 152, 0, 1909, - 1911, 1, 0, 0, 0, 1910, 1907, 1, 0, 0, 0, 1911, 1914, 1, 0, 0, 0, 1912, - 1910, 1, 0, 0, 0, 1912, 1913, 1, 0, 0, 0, 1913, 303, 1, 0, 0, 0, 1914, - 1912, 1, 0, 0, 0, 1915, 1918, 5, 174, 0, 0, 1916, 1919, 3, 424, 212, 0, - 1917, 1919, 3, 448, 224, 0, 1918, 1916, 1, 0, 0, 0, 1918, 1917, 1, 0, 0, - 0, 1918, 1919, 1, 0, 0, 0, 1919, 305, 1, 0, 0, 0, 1920, 1921, 3, 594, 297, - 0, 1921, 1922, 3, 322, 161, 0, 1922, 307, 1, 0, 0, 0, 1923, 1924, 3, 452, - 226, 0, 1924, 309, 1, 0, 0, 0, 1925, 1928, 5, 11, 0, 0, 1926, 1928, 3, - 312, 156, 0, 1927, 1925, 1, 0, 0, 0, 1927, 1926, 1, 0, 0, 0, 1928, 1934, - 1, 0, 0, 0, 1929, 1930, 3, 618, 309, 0, 1930, 1931, 3, 312, 156, 0, 1931, - 1933, 1, 0, 0, 0, 1932, 1929, 1, 0, 0, 0, 1933, 1936, 1, 0, 0, 0, 1934, - 1932, 1, 0, 0, 0, 1934, 1935, 1, 0, 0, 0, 1935, 311, 1, 0, 0, 0, 1936, - 1934, 1, 0, 0, 0, 1937, 1939, 3, 314, 157, 0, 1938, 1940, 3, 320, 160, - 0, 1939, 1938, 1, 0, 0, 0, 1939, 1940, 1, 0, 0, 0, 1940, 1950, 1, 0, 0, - 0, 1941, 1943, 3, 316, 158, 0, 1942, 1944, 3, 320, 160, 0, 1943, 1942, - 1, 0, 0, 0, 1943, 1944, 1, 0, 0, 0, 1944, 1950, 1, 0, 0, 0, 1945, 1947, - 3, 318, 159, 0, 1946, 1948, 3, 320, 160, 0, 1947, 1946, 1, 0, 0, 0, 1947, - 1948, 1, 0, 0, 0, 1948, 1950, 1, 0, 0, 0, 1949, 1937, 1, 0, 0, 0, 1949, - 1941, 1, 0, 0, 0, 1949, 1945, 1, 0, 0, 0, 1950, 313, 1, 0, 0, 0, 1951, - 1952, 3, 370, 185, 0, 1952, 315, 1, 0, 0, 0, 1953, 1954, 3, 348, 174, 0, - 1954, 317, 1, 0, 0, 0, 1955, 1956, 3, 370, 185, 0, 1956, 1957, 3, 614, - 307, 0, 1957, 1958, 3, 354, 177, 0, 1958, 1959, 3, 616, 308, 0, 1959, 319, - 1, 0, 0, 0, 1960, 1961, 3, 422, 211, 0, 1961, 1962, 5, 174, 0, 0, 1962, - 321, 1, 0, 0, 0, 1963, 1969, 3, 324, 162, 0, 1964, 1965, 3, 418, 209, 0, - 1965, 1966, 3, 324, 162, 0, 1966, 1968, 1, 0, 0, 0, 1967, 1964, 1, 0, 0, - 0, 1968, 1971, 1, 0, 0, 0, 1969, 1967, 1, 0, 0, 0, 1969, 1970, 1, 0, 0, - 0, 1970, 323, 1, 0, 0, 0, 1971, 1969, 1, 0, 0, 0, 1972, 2040, 3, 334, 167, - 0, 1973, 2040, 3, 336, 168, 0, 1974, 2040, 3, 332, 166, 0, 1975, 2040, - 3, 328, 164, 0, 1976, 2040, 3, 330, 165, 0, 1977, 2040, 3, 346, 173, 0, - 1978, 2040, 3, 344, 172, 0, 1979, 2040, 3, 342, 171, 0, 1980, 1981, 5, - 174, 0, 0, 1981, 1982, 5, 10, 0, 0, 1982, 1983, 5, 174, 0, 0, 1983, 1984, - 3, 296, 148, 0, 1984, 1985, 3, 354, 177, 0, 1985, 2040, 1, 0, 0, 0, 1986, - 1987, 5, 174, 0, 0, 1987, 1988, 5, 10, 0, 0, 1988, 1989, 5, 174, 0, 0, - 1989, 1990, 3, 430, 215, 0, 1990, 1991, 3, 354, 177, 0, 1991, 1992, 3, - 418, 209, 0, 1992, 1993, 3, 354, 177, 0, 1993, 2040, 1, 0, 0, 0, 1994, - 1995, 5, 1, 0, 0, 1995, 2001, 5, 174, 0, 0, 1996, 1997, 3, 618, 309, 0, - 1997, 1998, 5, 174, 0, 0, 1998, 2000, 1, 0, 0, 0, 1999, 1996, 1, 0, 0, - 0, 2000, 2003, 1, 0, 0, 0, 2001, 1999, 1, 0, 0, 0, 2001, 2002, 1, 0, 0, - 0, 2002, 2004, 1, 0, 0, 0, 2003, 2001, 1, 0, 0, 0, 2004, 2005, 5, 2, 0, - 0, 2005, 2006, 3, 480, 240, 0, 2006, 2007, 5, 1, 0, 0, 2007, 2013, 3, 264, - 132, 0, 2008, 2009, 3, 618, 309, 0, 2009, 2010, 3, 264, 132, 0, 2010, 2012, - 1, 0, 0, 0, 2011, 2008, 1, 0, 0, 0, 2012, 2015, 1, 0, 0, 0, 2013, 2011, - 1, 0, 0, 0, 2013, 2014, 1, 0, 0, 0, 2014, 2016, 1, 0, 0, 0, 2015, 2013, - 1, 0, 0, 0, 2016, 2017, 5, 2, 0, 0, 2017, 2040, 1, 0, 0, 0, 2018, 2019, - 5, 1, 0, 0, 2019, 2025, 5, 174, 0, 0, 2020, 2021, 3, 618, 309, 0, 2021, - 2022, 5, 174, 0, 0, 2022, 2024, 1, 0, 0, 0, 2023, 2020, 1, 0, 0, 0, 2024, - 2027, 1, 0, 0, 0, 2025, 2023, 1, 0, 0, 0, 2025, 2026, 1, 0, 0, 0, 2026, - 2028, 1, 0, 0, 0, 2027, 2025, 1, 0, 0, 0, 2028, 2029, 5, 2, 0, 0, 2029, - 2030, 3, 326, 163, 0, 2030, 2036, 3, 264, 132, 0, 2031, 2032, 3, 618, 309, - 0, 2032, 2033, 3, 264, 132, 0, 2033, 2035, 1, 0, 0, 0, 2034, 2031, 1, 0, - 0, 0, 2035, 2038, 1, 0, 0, 0, 2036, 2034, 1, 0, 0, 0, 2036, 2037, 1, 0, - 0, 0, 2037, 2040, 1, 0, 0, 0, 2038, 2036, 1, 0, 0, 0, 2039, 1972, 1, 0, - 0, 0, 2039, 1973, 1, 0, 0, 0, 2039, 1974, 1, 0, 0, 0, 2039, 1975, 1, 0, - 0, 0, 2039, 1976, 1, 0, 0, 0, 2039, 1977, 1, 0, 0, 0, 2039, 1978, 1, 0, - 0, 0, 2039, 1979, 1, 0, 0, 0, 2039, 1980, 1, 0, 0, 0, 2039, 1986, 1, 0, - 0, 0, 2039, 1994, 1, 0, 0, 0, 2039, 2018, 1, 0, 0, 0, 2040, 325, 1, 0, - 0, 0, 2041, 2042, 7, 2, 0, 0, 2042, 327, 1, 0, 0, 0, 2043, 2044, 3, 348, - 174, 0, 2044, 2045, 3, 326, 163, 0, 2045, 2046, 3, 354, 177, 0, 2046, 329, - 1, 0, 0, 0, 2047, 2048, 3, 348, 174, 0, 2048, 2049, 3, 326, 163, 0, 2049, - 2050, 3, 348, 174, 0, 2050, 331, 1, 0, 0, 0, 2051, 2052, 3, 370, 185, 0, - 2052, 2053, 3, 430, 215, 0, 2053, 2054, 3, 354, 177, 0, 2054, 2055, 3, - 418, 209, 0, 2055, 2056, 3, 354, 177, 0, 2056, 333, 1, 0, 0, 0, 2057, 2058, - 3, 370, 185, 0, 2058, 2059, 3, 326, 163, 0, 2059, 2060, 3, 354, 177, 0, - 2060, 335, 1, 0, 0, 0, 2061, 2062, 3, 370, 185, 0, 2062, 2063, 3, 296, - 148, 0, 2063, 2064, 3, 354, 177, 0, 2064, 337, 1, 0, 0, 0, 2065, 2066, - 7, 3, 0, 0, 2066, 339, 1, 0, 0, 0, 2067, 2073, 3, 338, 169, 0, 2068, 2069, - 5, 1, 0, 0, 2069, 2070, 3, 350, 175, 0, 2070, 2071, 5, 2, 0, 0, 2071, 2073, - 1, 0, 0, 0, 2072, 2067, 1, 0, 0, 0, 2072, 2068, 1, 0, 0, 0, 2073, 341, - 1, 0, 0, 0, 2074, 2075, 3, 370, 185, 0, 2075, 2076, 3, 480, 240, 0, 2076, - 2077, 3, 340, 170, 0, 2077, 343, 1, 0, 0, 0, 2078, 2079, 3, 370, 185, 0, - 2079, 2080, 3, 442, 221, 0, 2080, 2081, 3, 354, 177, 0, 2081, 345, 1, 0, - 0, 0, 2082, 2083, 3, 370, 185, 0, 2083, 2084, 3, 442, 221, 0, 2084, 2085, - 3, 496, 248, 0, 2085, 2086, 1, 0, 0, 0, 2086, 2087, 3, 354, 177, 0, 2087, - 347, 1, 0, 0, 0, 2088, 2089, 5, 174, 0, 0, 2089, 2090, 5, 1, 0, 0, 2090, - 2091, 5, 11, 0, 0, 2091, 2108, 5, 2, 0, 0, 2092, 2093, 5, 174, 0, 0, 2093, - 2095, 5, 1, 0, 0, 2094, 2096, 3, 350, 175, 0, 2095, 2094, 1, 0, 0, 0, 2095, - 2096, 1, 0, 0, 0, 2096, 2097, 1, 0, 0, 0, 2097, 2108, 5, 2, 0, 0, 2098, - 2099, 5, 141, 0, 0, 2099, 2100, 5, 1, 0, 0, 2100, 2108, 5, 2, 0, 0, 2101, - 2102, 5, 146, 0, 0, 2102, 2104, 5, 1, 0, 0, 2103, 2105, 3, 350, 175, 0, - 2104, 2103, 1, 0, 0, 0, 2104, 2105, 1, 0, 0, 0, 2105, 2106, 1, 0, 0, 0, - 2106, 2108, 5, 2, 0, 0, 2107, 2088, 1, 0, 0, 0, 2107, 2092, 1, 0, 0, 0, - 2107, 2098, 1, 0, 0, 0, 2107, 2101, 1, 0, 0, 0, 2108, 349, 1, 0, 0, 0, - 2109, 2113, 3, 354, 177, 0, 2110, 2113, 5, 174, 0, 0, 2111, 2113, 3, 348, - 174, 0, 2112, 2109, 1, 0, 0, 0, 2112, 2110, 1, 0, 0, 0, 2112, 2111, 1, - 0, 0, 0, 2113, 2122, 1, 0, 0, 0, 2114, 2118, 3, 618, 309, 0, 2115, 2119, - 3, 354, 177, 0, 2116, 2119, 5, 174, 0, 0, 2117, 2119, 3, 348, 174, 0, 2118, - 2115, 1, 0, 0, 0, 2118, 2116, 1, 0, 0, 0, 2118, 2117, 1, 0, 0, 0, 2119, - 2121, 1, 0, 0, 0, 2120, 2114, 1, 0, 0, 0, 2121, 2124, 1, 0, 0, 0, 2122, - 2120, 1, 0, 0, 0, 2122, 2123, 1, 0, 0, 0, 2123, 351, 1, 0, 0, 0, 2124, - 2122, 1, 0, 0, 0, 2125, 2133, 3, 338, 169, 0, 2126, 2133, 3, 354, 177, - 0, 2127, 2133, 3, 348, 174, 0, 2128, 2133, 3, 258, 129, 0, 2129, 2133, - 3, 256, 128, 0, 2130, 2133, 3, 260, 130, 0, 2131, 2133, 3, 264, 132, 0, - 2132, 2125, 1, 0, 0, 0, 2132, 2126, 1, 0, 0, 0, 2132, 2127, 1, 0, 0, 0, - 2132, 2128, 1, 0, 0, 0, 2132, 2129, 1, 0, 0, 0, 2132, 2130, 1, 0, 0, 0, - 2132, 2131, 1, 0, 0, 0, 2133, 353, 1, 0, 0, 0, 2134, 2144, 3, 338, 169, - 0, 2135, 2144, 3, 524, 262, 0, 2136, 2144, 5, 175, 0, 0, 2137, 2144, 3, - 360, 180, 0, 2138, 2144, 3, 356, 178, 0, 2139, 2144, 3, 358, 179, 0, 2140, - 2144, 3, 364, 182, 0, 2141, 2144, 3, 362, 181, 0, 2142, 2144, 3, 58, 29, - 0, 2143, 2134, 1, 0, 0, 0, 2143, 2135, 1, 0, 0, 0, 2143, 2136, 1, 0, 0, - 0, 2143, 2137, 1, 0, 0, 0, 2143, 2138, 1, 0, 0, 0, 2143, 2139, 1, 0, 0, - 0, 2143, 2140, 1, 0, 0, 0, 2143, 2141, 1, 0, 0, 0, 2143, 2142, 1, 0, 0, - 0, 2144, 355, 1, 0, 0, 0, 2145, 2146, 5, 170, 0, 0, 2146, 357, 1, 0, 0, - 0, 2147, 2148, 7, 4, 0, 0, 2148, 359, 1, 0, 0, 0, 2149, 2150, 5, 169, 0, - 0, 2150, 361, 1, 0, 0, 0, 2151, 2152, 7, 5, 0, 0, 2152, 363, 1, 0, 0, 0, - 2153, 2154, 5, 172, 0, 0, 2154, 365, 1, 0, 0, 0, 2155, 2160, 5, 174, 0, - 0, 2156, 2157, 5, 17, 0, 0, 2157, 2158, 5, 174, 0, 0, 2158, 2160, 5, 17, - 0, 0, 2159, 2155, 1, 0, 0, 0, 2159, 2156, 1, 0, 0, 0, 2160, 367, 1, 0, - 0, 0, 2161, 2169, 5, 174, 0, 0, 2162, 2169, 5, 79, 0, 0, 2163, 2169, 5, - 125, 0, 0, 2164, 2169, 5, 63, 0, 0, 2165, 2166, 5, 17, 0, 0, 2166, 2167, - 5, 174, 0, 0, 2167, 2169, 5, 17, 0, 0, 2168, 2161, 1, 0, 0, 0, 2168, 2162, - 1, 0, 0, 0, 2168, 2163, 1, 0, 0, 0, 2168, 2164, 1, 0, 0, 0, 2168, 2165, - 1, 0, 0, 0, 2169, 369, 1, 0, 0, 0, 2170, 2177, 5, 174, 0, 0, 2171, 2177, - 3, 578, 289, 0, 2172, 2177, 5, 76, 0, 0, 2173, 2174, 5, 17, 0, 0, 2174, - 2175, 5, 174, 0, 0, 2175, 2177, 5, 17, 0, 0, 2176, 2170, 1, 0, 0, 0, 2176, - 2171, 1, 0, 0, 0, 2176, 2172, 1, 0, 0, 0, 2176, 2173, 1, 0, 0, 0, 2177, - 371, 1, 0, 0, 0, 2178, 2180, 3, 374, 187, 0, 2179, 2181, 3, 376, 188, 0, - 2180, 2179, 1, 0, 0, 0, 2180, 2181, 1, 0, 0, 0, 2181, 373, 1, 0, 0, 0, - 2182, 2183, 7, 6, 0, 0, 2183, 375, 1, 0, 0, 0, 2184, 2185, 3, 610, 305, - 0, 2185, 2191, 3, 372, 186, 0, 2186, 2187, 3, 618, 309, 0, 2187, 2188, - 3, 372, 186, 0, 2188, 2190, 1, 0, 0, 0, 2189, 2186, 1, 0, 0, 0, 2190, 2193, - 1, 0, 0, 0, 2191, 2189, 1, 0, 0, 0, 2191, 2192, 1, 0, 0, 0, 2192, 2194, - 1, 0, 0, 0, 2193, 2191, 1, 0, 0, 0, 2194, 2195, 3, 612, 306, 0, 2195, 377, - 1, 0, 0, 0, 2196, 2199, 3, 424, 212, 0, 2197, 2199, 3, 448, 224, 0, 2198, - 2196, 1, 0, 0, 0, 2198, 2197, 1, 0, 0, 0, 2199, 379, 1, 0, 0, 0, 2200, - 2201, 5, 174, 0, 0, 2201, 381, 1, 0, 0, 0, 2202, 2203, 5, 174, 0, 0, 2203, - 383, 1, 0, 0, 0, 2204, 2205, 3, 360, 180, 0, 2205, 385, 1, 0, 0, 0, 2206, - 2207, 5, 174, 0, 0, 2207, 387, 1, 0, 0, 0, 2208, 2209, 5, 174, 0, 0, 2209, - 389, 1, 0, 0, 0, 2210, 2211, 5, 174, 0, 0, 2211, 391, 1, 0, 0, 0, 2212, - 2213, 5, 174, 0, 0, 2213, 393, 1, 0, 0, 0, 2214, 2215, 5, 174, 0, 0, 2215, - 395, 1, 0, 0, 0, 2216, 2217, 5, 174, 0, 0, 2217, 397, 1, 0, 0, 0, 2218, - 2219, 3, 360, 180, 0, 2219, 399, 1, 0, 0, 0, 2220, 2221, 5, 174, 0, 0, - 2221, 401, 1, 0, 0, 0, 2222, 2223, 3, 404, 202, 0, 2223, 2224, 3, 372, - 186, 0, 2224, 403, 1, 0, 0, 0, 2225, 2226, 7, 7, 0, 0, 2226, 405, 1, 0, - 0, 0, 2227, 2228, 5, 24, 0, 0, 2228, 407, 1, 0, 0, 0, 2229, 2230, 5, 25, - 0, 0, 2230, 409, 1, 0, 0, 0, 2231, 2232, 5, 26, 0, 0, 2232, 411, 1, 0, - 0, 0, 2233, 2234, 5, 26, 0, 0, 2234, 2235, 5, 106, 0, 0, 2235, 413, 1, - 0, 0, 0, 2236, 2237, 5, 27, 0, 0, 2237, 415, 1, 0, 0, 0, 2238, 2239, 5, - 28, 0, 0, 2239, 417, 1, 0, 0, 0, 2240, 2241, 5, 29, 0, 0, 2241, 419, 1, - 0, 0, 0, 2242, 2243, 5, 31, 0, 0, 2243, 421, 1, 0, 0, 0, 2244, 2245, 5, - 32, 0, 0, 2245, 423, 1, 0, 0, 0, 2246, 2247, 5, 33, 0, 0, 2247, 425, 1, - 0, 0, 0, 2248, 2249, 5, 34, 0, 0, 2249, 427, 1, 0, 0, 0, 2250, 2251, 5, - 35, 0, 0, 2251, 429, 1, 0, 0, 0, 2252, 2253, 5, 37, 0, 0, 2253, 431, 1, - 0, 0, 0, 2254, 2255, 5, 36, 0, 0, 2255, 433, 1, 0, 0, 0, 2256, 2257, 5, - 38, 0, 0, 2257, 435, 1, 0, 0, 0, 2258, 2259, 5, 39, 0, 0, 2259, 437, 1, - 0, 0, 0, 2260, 2261, 5, 40, 0, 0, 2261, 439, 1, 0, 0, 0, 2262, 2263, 5, - 42, 0, 0, 2263, 441, 1, 0, 0, 0, 2264, 2265, 5, 44, 0, 0, 2265, 443, 1, - 0, 0, 0, 2266, 2267, 5, 45, 0, 0, 2267, 445, 1, 0, 0, 0, 2268, 2269, 5, - 47, 0, 0, 2269, 447, 1, 0, 0, 0, 2270, 2271, 5, 48, 0, 0, 2271, 449, 1, - 0, 0, 0, 2272, 2273, 5, 49, 0, 0, 2273, 451, 1, 0, 0, 0, 2274, 2275, 5, - 50, 0, 0, 2275, 453, 1, 0, 0, 0, 2276, 2277, 5, 51, 0, 0, 2277, 455, 1, - 0, 0, 0, 2278, 2279, 5, 52, 0, 0, 2279, 457, 1, 0, 0, 0, 2280, 2281, 5, - 54, 0, 0, 2281, 459, 1, 0, 0, 0, 2282, 2283, 5, 55, 0, 0, 2283, 461, 1, - 0, 0, 0, 2284, 2285, 5, 56, 0, 0, 2285, 463, 1, 0, 0, 0, 2286, 2287, 5, - 58, 0, 0, 2287, 465, 1, 0, 0, 0, 2288, 2289, 5, 59, 0, 0, 2289, 467, 1, - 0, 0, 0, 2290, 2291, 5, 60, 0, 0, 2291, 469, 1, 0, 0, 0, 2292, 2293, 5, - 61, 0, 0, 2293, 471, 1, 0, 0, 0, 2294, 2295, 5, 62, 0, 0, 2295, 473, 1, - 0, 0, 0, 2296, 2297, 5, 63, 0, 0, 2297, 475, 1, 0, 0, 0, 2298, 2299, 5, - 64, 0, 0, 2299, 477, 1, 0, 0, 0, 2300, 2301, 5, 66, 0, 0, 2301, 479, 1, - 0, 0, 0, 2302, 2303, 5, 67, 0, 0, 2303, 481, 1, 0, 0, 0, 2304, 2305, 5, - 68, 0, 0, 2305, 483, 1, 0, 0, 0, 2306, 2307, 5, 70, 0, 0, 2307, 485, 1, - 0, 0, 0, 2308, 2309, 5, 71, 0, 0, 2309, 487, 1, 0, 0, 0, 2310, 2311, 5, - 72, 0, 0, 2311, 489, 1, 0, 0, 0, 2312, 2313, 5, 73, 0, 0, 2313, 491, 1, - 0, 0, 0, 2314, 2315, 5, 74, 0, 0, 2315, 493, 1, 0, 0, 0, 2316, 2317, 5, - 75, 0, 0, 2317, 495, 1, 0, 0, 0, 2318, 2319, 5, 76, 0, 0, 2319, 497, 1, - 0, 0, 0, 2320, 2321, 5, 77, 0, 0, 2321, 499, 1, 0, 0, 0, 2322, 2323, 5, - 78, 0, 0, 2323, 501, 1, 0, 0, 0, 2324, 2325, 5, 79, 0, 0, 2325, 503, 1, - 0, 0, 0, 2326, 2327, 5, 80, 0, 0, 2327, 505, 1, 0, 0, 0, 2328, 2329, 5, - 82, 0, 0, 2329, 507, 1, 0, 0, 0, 2330, 2331, 5, 84, 0, 0, 2331, 509, 1, - 0, 0, 0, 2332, 2333, 5, 87, 0, 0, 2333, 511, 1, 0, 0, 0, 2334, 2335, 5, - 88, 0, 0, 2335, 513, 1, 0, 0, 0, 2336, 2337, 5, 89, 0, 0, 2337, 515, 1, - 0, 0, 0, 2338, 2339, 5, 90, 0, 0, 2339, 517, 1, 0, 0, 0, 2340, 2341, 5, - 93, 0, 0, 2341, 519, 1, 0, 0, 0, 2342, 2343, 5, 92, 0, 0, 2343, 521, 1, - 0, 0, 0, 2344, 2345, 5, 94, 0, 0, 2345, 523, 1, 0, 0, 0, 2346, 2347, 5, - 95, 0, 0, 2347, 525, 1, 0, 0, 0, 2348, 2349, 5, 96, 0, 0, 2349, 527, 1, - 0, 0, 0, 2350, 2351, 5, 97, 0, 0, 2351, 529, 1, 0, 0, 0, 2352, 2353, 5, - 99, 0, 0, 2353, 531, 1, 0, 0, 0, 2354, 2355, 5, 100, 0, 0, 2355, 533, 1, - 0, 0, 0, 2356, 2357, 5, 101, 0, 0, 2357, 535, 1, 0, 0, 0, 2358, 2359, 5, - 103, 0, 0, 2359, 537, 1, 0, 0, 0, 2360, 2361, 5, 107, 0, 0, 2361, 539, - 1, 0, 0, 0, 2362, 2363, 5, 109, 0, 0, 2363, 541, 1, 0, 0, 0, 2364, 2365, - 5, 110, 0, 0, 2365, 543, 1, 0, 0, 0, 2366, 2367, 5, 111, 0, 0, 2367, 545, - 1, 0, 0, 0, 2368, 2369, 5, 112, 0, 0, 2369, 547, 1, 0, 0, 0, 2370, 2371, - 5, 114, 0, 0, 2371, 549, 1, 0, 0, 0, 2372, 2373, 5, 115, 0, 0, 2373, 551, - 1, 0, 0, 0, 2374, 2375, 5, 117, 0, 0, 2375, 553, 1, 0, 0, 0, 2376, 2377, - 5, 118, 0, 0, 2377, 555, 1, 0, 0, 0, 2378, 2379, 5, 119, 0, 0, 2379, 557, - 1, 0, 0, 0, 2380, 2381, 5, 121, 0, 0, 2381, 559, 1, 0, 0, 0, 2382, 2383, - 5, 122, 0, 0, 2383, 561, 1, 0, 0, 0, 2384, 2385, 5, 123, 0, 0, 2385, 563, - 1, 0, 0, 0, 2386, 2387, 5, 124, 0, 0, 2387, 565, 1, 0, 0, 0, 2388, 2389, - 5, 125, 0, 0, 2389, 567, 1, 0, 0, 0, 2390, 2391, 5, 127, 0, 0, 2391, 569, - 1, 0, 0, 0, 2392, 2393, 5, 128, 0, 0, 2393, 571, 1, 0, 0, 0, 2394, 2395, - 5, 130, 0, 0, 2395, 573, 1, 0, 0, 0, 2396, 2397, 5, 132, 0, 0, 2397, 575, - 1, 0, 0, 0, 2398, 2399, 5, 133, 0, 0, 2399, 577, 1, 0, 0, 0, 2400, 2401, - 5, 135, 0, 0, 2401, 579, 1, 0, 0, 0, 2402, 2403, 5, 136, 0, 0, 2403, 581, - 1, 0, 0, 0, 2404, 2405, 5, 137, 0, 0, 2405, 583, 1, 0, 0, 0, 2406, 2407, - 5, 138, 0, 0, 2407, 585, 1, 0, 0, 0, 2408, 2409, 5, 139, 0, 0, 2409, 587, - 1, 0, 0, 0, 2410, 2411, 5, 140, 0, 0, 2411, 589, 1, 0, 0, 0, 2412, 2413, - 5, 142, 0, 0, 2413, 591, 1, 0, 0, 0, 2414, 2415, 5, 143, 0, 0, 2415, 593, - 1, 0, 0, 0, 2416, 2417, 5, 144, 0, 0, 2417, 595, 1, 0, 0, 0, 2418, 2419, - 5, 145, 0, 0, 2419, 597, 1, 0, 0, 0, 2420, 2421, 5, 113, 0, 0, 2421, 599, - 1, 0, 0, 0, 2422, 2423, 5, 65, 0, 0, 2423, 601, 1, 0, 0, 0, 2424, 2425, - 5, 1, 0, 0, 2425, 603, 1, 0, 0, 0, 2426, 2427, 5, 2, 0, 0, 2427, 605, 1, - 0, 0, 0, 2428, 2429, 5, 3, 0, 0, 2429, 607, 1, 0, 0, 0, 2430, 2431, 5, - 4, 0, 0, 2431, 609, 1, 0, 0, 0, 2432, 2433, 5, 20, 0, 0, 2433, 611, 1, - 0, 0, 0, 2434, 2435, 5, 21, 0, 0, 2435, 613, 1, 0, 0, 0, 2436, 2437, 5, - 5, 0, 0, 2437, 615, 1, 0, 0, 0, 2438, 2439, 5, 6, 0, 0, 2439, 617, 1, 0, - 0, 0, 2440, 2441, 5, 7, 0, 0, 2441, 619, 1, 0, 0, 0, 2442, 2443, 5, 9, - 0, 0, 2443, 621, 1, 0, 0, 0, 2444, 2445, 3, 600, 300, 0, 2445, 2446, 3, - 434, 217, 0, 2446, 2452, 3, 624, 312, 0, 2447, 2448, 3, 618, 309, 0, 2448, - 2449, 3, 624, 312, 0, 2449, 2451, 1, 0, 0, 0, 2450, 2447, 1, 0, 0, 0, 2451, - 2454, 1, 0, 0, 0, 2452, 2450, 1, 0, 0, 0, 2452, 2453, 1, 0, 0, 0, 2453, - 623, 1, 0, 0, 0, 2454, 2452, 1, 0, 0, 0, 2455, 2456, 5, 174, 0, 0, 2456, - 625, 1, 0, 0, 0, 183, 629, 632, 638, 643, 645, 650, 653, 656, 700, 704, - 712, 719, 724, 740, 743, 750, 755, 766, 776, 791, 802, 811, 816, 824, 829, - 833, 838, 843, 858, 864, 869, 879, 884, 901, 908, 916, 930, 935, 947, 951, - 955, 960, 965, 984, 991, 999, 1003, 1008, 1027, 1036, 1051, 1053, 1065, - 1079, 1086, 1093, 1101, 1112, 1128, 1147, 1170, 1182, 1198, 1208, 1217, - 1236, 1244, 1250, 1255, 1262, 1267, 1275, 1280, 1287, 1292, 1299, 1304, - 1311, 1320, 1327, 1334, 1341, 1346, 1353, 1360, 1364, 1367, 1375, 1385, - 1396, 1402, 1411, 1424, 1432, 1438, 1443, 1457, 1477, 1486, 1498, 1502, - 1506, 1520, 1528, 1537, 1548, 1555, 1558, 1568, 1574, 1592, 1596, 1600, - 1605, 1608, 1616, 1621, 1625, 1627, 1630, 1635, 1642, 1645, 1656, 1669, - 1676, 1710, 1713, 1729, 1741, 1744, 1757, 1763, 1769, 1773, 1776, 1779, - 1797, 1802, 1825, 1837, 1846, 1855, 1859, 1862, 1867, 1870, 1873, 1876, - 1879, 1882, 1890, 1897, 1912, 1918, 1927, 1934, 1939, 1943, 1947, 1949, - 1969, 2001, 2013, 2025, 2036, 2039, 2072, 2095, 2104, 2107, 2112, 2118, - 2122, 2132, 2143, 2159, 2168, 2176, 2180, 2191, 2198, 2452, + 1, 162, 5, 162, 2010, 8, 162, 10, 162, 12, 162, 2013, 9, 162, 1, 162, 1, + 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 5, 162, 2022, 8, 162, 10, + 162, 12, 162, 2025, 9, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, + 162, 1, 162, 5, 162, 2034, 8, 162, 10, 162, 12, 162, 2037, 9, 162, 1, 162, + 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 5, 162, 2045, 8, 162, 10, 162, + 12, 162, 2048, 9, 162, 3, 162, 2050, 8, 162, 1, 163, 1, 163, 1, 164, 1, + 164, 1, 164, 1, 164, 1, 165, 1, 165, 1, 165, 1, 165, 1, 166, 1, 166, 1, + 166, 1, 166, 1, 167, 1, 167, 1, 167, 1, 167, 1, 168, 1, 168, 1, 168, 1, + 168, 1, 168, 1, 168, 1, 169, 1, 169, 1, 169, 1, 169, 1, 170, 1, 170, 1, + 170, 1, 170, 1, 171, 1, 171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 172, 3, + 172, 2091, 8, 172, 1, 173, 1, 173, 1, 173, 1, 173, 1, 174, 1, 174, 1, 174, + 1, 174, 1, 175, 1, 175, 1, 175, 1, 175, 1, 175, 1, 175, 1, 176, 1, 176, + 1, 176, 3, 176, 2110, 8, 176, 1, 176, 1, 176, 1, 177, 1, 177, 1, 178, 1, + 178, 1, 178, 1, 178, 5, 178, 2120, 8, 178, 10, 178, 12, 178, 2123, 9, 178, + 1, 179, 1, 179, 1, 179, 3, 179, 2128, 8, 179, 1, 180, 1, 180, 1, 180, 1, + 180, 1, 180, 1, 180, 1, 180, 3, 180, 2137, 8, 180, 1, 181, 1, 181, 1, 181, + 1, 181, 1, 181, 1, 181, 1, 181, 1, 181, 1, 181, 3, 181, 2148, 8, 181, 1, + 182, 1, 182, 1, 183, 1, 183, 1, 184, 1, 184, 1, 185, 1, 185, 1, 186, 1, + 186, 1, 187, 1, 187, 1, 187, 1, 187, 3, 187, 2164, 8, 187, 1, 188, 1, 188, + 1, 188, 1, 188, 1, 188, 1, 188, 1, 188, 3, 188, 2173, 8, 188, 1, 189, 1, + 189, 1, 189, 1, 189, 1, 189, 1, 189, 3, 189, 2181, 8, 189, 1, 190, 1, 190, + 3, 190, 2185, 8, 190, 1, 191, 1, 191, 1, 192, 1, 192, 1, 192, 1, 192, 1, + 192, 5, 192, 2194, 8, 192, 10, 192, 12, 192, 2197, 9, 192, 1, 192, 1, 192, + 1, 193, 1, 193, 3, 193, 2203, 8, 193, 1, 194, 1, 194, 1, 195, 1, 195, 1, + 196, 1, 196, 1, 197, 1, 197, 1, 198, 1, 198, 1, 199, 1, 199, 1, 200, 1, + 200, 1, 201, 1, 201, 1, 202, 1, 202, 1, 203, 1, 203, 1, 204, 1, 204, 1, + 205, 1, 205, 1, 205, 1, 206, 1, 206, 1, 207, 1, 207, 1, 208, 1, 208, 1, + 209, 1, 209, 1, 210, 1, 210, 1, 210, 1, 211, 1, 211, 1, 212, 1, 212, 1, + 213, 1, 213, 1, 214, 1, 214, 1, 215, 1, 215, 1, 216, 1, 216, 1, 217, 1, + 217, 1, 218, 1, 218, 1, 219, 1, 219, 1, 220, 1, 220, 1, 221, 1, 221, 1, + 222, 1, 222, 1, 223, 1, 223, 1, 224, 1, 224, 1, 225, 1, 225, 1, 226, 1, + 226, 1, 227, 1, 227, 1, 228, 1, 228, 1, 229, 1, 229, 1, 230, 1, 230, 1, + 231, 1, 231, 1, 232, 1, 232, 1, 233, 1, 233, 1, 234, 1, 234, 1, 235, 1, + 235, 1, 236, 1, 236, 1, 237, 1, 237, 1, 238, 1, 238, 1, 239, 1, 239, 1, + 240, 1, 240, 1, 241, 1, 241, 1, 242, 1, 242, 1, 243, 1, 243, 1, 244, 1, + 244, 1, 245, 1, 245, 1, 246, 1, 246, 1, 247, 1, 247, 1, 248, 1, 248, 1, + 249, 1, 249, 1, 250, 1, 250, 1, 251, 1, 251, 1, 252, 1, 252, 1, 253, 1, + 253, 1, 254, 1, 254, 1, 255, 1, 255, 1, 256, 1, 256, 1, 257, 1, 257, 1, + 258, 1, 258, 1, 259, 1, 259, 1, 260, 1, 260, 1, 261, 1, 261, 1, 262, 1, + 262, 1, 263, 1, 263, 1, 264, 1, 264, 1, 265, 1, 265, 1, 266, 1, 266, 1, + 267, 1, 267, 1, 268, 1, 268, 1, 269, 1, 269, 1, 270, 1, 270, 1, 271, 1, + 271, 1, 272, 1, 272, 1, 273, 1, 273, 1, 274, 1, 274, 1, 275, 1, 275, 1, + 276, 1, 276, 1, 277, 1, 277, 1, 278, 1, 278, 1, 279, 1, 279, 1, 280, 1, + 280, 1, 281, 1, 281, 1, 282, 1, 282, 1, 283, 1, 283, 1, 284, 1, 284, 1, + 285, 1, 285, 1, 286, 1, 286, 1, 287, 1, 287, 1, 288, 1, 288, 1, 289, 1, + 289, 1, 290, 1, 290, 1, 291, 1, 291, 1, 292, 1, 292, 1, 293, 1, 293, 1, + 294, 1, 294, 1, 295, 1, 295, 1, 296, 1, 296, 1, 297, 1, 297, 1, 298, 1, + 298, 1, 299, 1, 299, 1, 300, 1, 300, 1, 301, 1, 301, 1, 302, 1, 302, 1, + 303, 1, 303, 1, 304, 1, 304, 1, 305, 1, 305, 1, 306, 1, 306, 1, 307, 1, + 307, 1, 308, 1, 308, 1, 309, 1, 309, 1, 310, 1, 310, 1, 311, 1, 311, 1, + 312, 1, 312, 1, 313, 1, 313, 1, 314, 1, 314, 1, 315, 1, 315, 1, 315, 1, + 315, 1, 315, 1, 315, 5, 315, 2455, 8, 315, 10, 315, 12, 315, 2458, 9, 315, + 1, 316, 1, 316, 1, 316, 0, 0, 317, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, + 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, + 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, + 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, + 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, + 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, + 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, + 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, + 244, 246, 248, 250, 252, 254, 256, 258, 260, 262, 264, 266, 268, 270, 272, + 274, 276, 278, 280, 282, 284, 286, 288, 290, 292, 294, 296, 298, 300, 302, + 304, 306, 308, 310, 312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 332, + 334, 336, 338, 340, 342, 344, 346, 348, 350, 352, 354, 356, 358, 360, 362, + 364, 366, 368, 370, 372, 374, 376, 378, 380, 382, 384, 386, 388, 390, 392, + 394, 396, 398, 400, 402, 404, 406, 408, 410, 412, 414, 416, 418, 420, 422, + 424, 426, 428, 430, 432, 434, 436, 438, 440, 442, 444, 446, 448, 450, 452, + 454, 456, 458, 460, 462, 464, 466, 468, 470, 472, 474, 476, 478, 480, 482, + 484, 486, 488, 490, 492, 494, 496, 498, 500, 502, 504, 506, 508, 510, 512, + 514, 516, 518, 520, 522, 524, 526, 528, 530, 532, 534, 536, 538, 540, 542, + 544, 546, 548, 550, 552, 554, 556, 558, 560, 562, 564, 566, 568, 570, 572, + 574, 576, 578, 580, 582, 584, 586, 588, 590, 592, 594, 596, 598, 600, 602, + 604, 606, 608, 610, 612, 614, 616, 618, 620, 622, 624, 626, 628, 630, 632, + 0, 9, 1, 0, 168, 169, 2, 0, 14, 14, 16, 16, 1, 0, 19, 23, 1, 0, 176, 177, + 3, 0, 141, 141, 146, 146, 174, 174, 1, 0, 170, 171, 2, 0, 57, 57, 131, + 131, 6, 0, 84, 84, 118, 118, 127, 127, 141, 141, 147, 167, 174, 174, 2, + 0, 71, 71, 174, 174, 2431, 0, 635, 1, 0, 0, 0, 2, 653, 1, 0, 0, 0, 4, 666, + 1, 0, 0, 0, 6, 668, 1, 0, 0, 0, 8, 708, 1, 0, 0, 0, 10, 712, 1, 0, 0, 0, + 12, 720, 1, 0, 0, 0, 14, 722, 1, 0, 0, 0, 16, 724, 1, 0, 0, 0, 18, 727, + 1, 0, 0, 0, 20, 732, 1, 0, 0, 0, 22, 736, 1, 0, 0, 0, 24, 743, 1, 0, 0, + 0, 26, 753, 1, 0, 0, 0, 28, 765, 1, 0, 0, 0, 30, 784, 1, 0, 0, 0, 32, 819, + 1, 0, 0, 0, 34, 821, 1, 0, 0, 0, 36, 834, 1, 0, 0, 0, 38, 843, 1, 0, 0, + 0, 40, 858, 1, 0, 0, 0, 42, 869, 1, 0, 0, 0, 44, 883, 1, 0, 0, 0, 46, 911, + 1, 0, 0, 0, 48, 918, 1, 0, 0, 0, 50, 927, 1, 0, 0, 0, 52, 938, 1, 0, 0, + 0, 54, 940, 1, 0, 0, 0, 56, 957, 1, 0, 0, 0, 58, 984, 1, 0, 0, 0, 60, 986, + 1, 0, 0, 0, 62, 999, 1, 0, 0, 0, 64, 1005, 1, 0, 0, 0, 66, 1035, 1, 0, + 0, 0, 68, 1037, 1, 0, 0, 0, 70, 1049, 1, 0, 0, 0, 72, 1053, 1, 0, 0, 0, + 74, 1066, 1, 0, 0, 0, 76, 1078, 1, 0, 0, 0, 78, 1081, 1, 0, 0, 0, 80, 1089, + 1, 0, 0, 0, 82, 1094, 1, 0, 0, 0, 84, 1096, 1, 0, 0, 0, 86, 1109, 1, 0, + 0, 0, 88, 1111, 1, 0, 0, 0, 90, 1114, 1, 0, 0, 0, 92, 1123, 1, 0, 0, 0, + 94, 1127, 1, 0, 0, 0, 96, 1139, 1, 0, 0, 0, 98, 1144, 1, 0, 0, 0, 100, + 1155, 1, 0, 0, 0, 102, 1157, 1, 0, 0, 0, 104, 1160, 1, 0, 0, 0, 106, 1165, + 1, 0, 0, 0, 108, 1169, 1, 0, 0, 0, 110, 1172, 1, 0, 0, 0, 112, 1181, 1, + 0, 0, 0, 114, 1184, 1, 0, 0, 0, 116, 1193, 1, 0, 0, 0, 118, 1197, 1, 0, + 0, 0, 120, 1200, 1, 0, 0, 0, 122, 1209, 1, 0, 0, 0, 124, 1212, 1, 0, 0, + 0, 126, 1218, 1, 0, 0, 0, 128, 1244, 1, 0, 0, 0, 130, 1246, 1, 0, 0, 0, + 132, 1260, 1, 0, 0, 0, 134, 1267, 1, 0, 0, 0, 136, 1279, 1, 0, 0, 0, 138, + 1292, 1, 0, 0, 0, 140, 1304, 1, 0, 0, 0, 142, 1316, 1, 0, 0, 0, 144, 1325, + 1, 0, 0, 0, 146, 1332, 1, 0, 0, 0, 148, 1339, 1, 0, 0, 0, 150, 1346, 1, + 0, 0, 0, 152, 1358, 1, 0, 0, 0, 154, 1370, 1, 0, 0, 0, 156, 1377, 1, 0, + 0, 0, 158, 1387, 1, 0, 0, 0, 160, 1404, 1, 0, 0, 0, 162, 1406, 1, 0, 0, + 0, 164, 1410, 1, 0, 0, 0, 166, 1412, 1, 0, 0, 0, 168, 1424, 1, 0, 0, 0, + 170, 1428, 1, 0, 0, 0, 172, 1432, 1, 0, 0, 0, 174, 1434, 1, 0, 0, 0, 176, + 1448, 1, 0, 0, 0, 178, 1453, 1, 0, 0, 0, 180, 1456, 1, 0, 0, 0, 182, 1465, + 1, 0, 0, 0, 184, 1467, 1, 0, 0, 0, 186, 1469, 1, 0, 0, 0, 188, 1473, 1, + 0, 0, 0, 190, 1479, 1, 0, 0, 0, 192, 1488, 1, 0, 0, 0, 194, 1497, 1, 0, + 0, 0, 196, 1499, 1, 0, 0, 0, 198, 1501, 1, 0, 0, 0, 200, 1504, 1, 0, 0, + 0, 202, 1514, 1, 0, 0, 0, 204, 1516, 1, 0, 0, 0, 206, 1530, 1, 0, 0, 0, + 208, 1545, 1, 0, 0, 0, 210, 1547, 1, 0, 0, 0, 212, 1551, 1, 0, 0, 0, 214, + 1554, 1, 0, 0, 0, 216, 1560, 1, 0, 0, 0, 218, 1576, 1, 0, 0, 0, 220, 1582, + 1, 0, 0, 0, 222, 1584, 1, 0, 0, 0, 224, 1589, 1, 0, 0, 0, 226, 1594, 1, + 0, 0, 0, 228, 1600, 1, 0, 0, 0, 230, 1618, 1, 0, 0, 0, 232, 1635, 1, 0, + 0, 0, 234, 1638, 1, 0, 0, 0, 236, 1655, 1, 0, 0, 0, 238, 1658, 1, 0, 0, + 0, 240, 1667, 1, 0, 0, 0, 242, 1671, 1, 0, 0, 0, 244, 1684, 1, 0, 0, 0, + 246, 1686, 1, 0, 0, 0, 248, 1690, 1, 0, 0, 0, 250, 1696, 1, 0, 0, 0, 252, + 1702, 1, 0, 0, 0, 254, 1706, 1, 0, 0, 0, 256, 1711, 1, 0, 0, 0, 258, 1725, + 1, 0, 0, 0, 260, 1742, 1, 0, 0, 0, 262, 1756, 1, 0, 0, 0, 264, 1758, 1, + 0, 0, 0, 266, 1771, 1, 0, 0, 0, 268, 1805, 1, 0, 0, 0, 270, 1807, 1, 0, + 0, 0, 272, 1812, 1, 0, 0, 0, 274, 1815, 1, 0, 0, 0, 276, 1818, 1, 0, 0, + 0, 278, 1822, 1, 0, 0, 0, 280, 1833, 1, 0, 0, 0, 282, 1835, 1, 0, 0, 0, + 284, 1839, 1, 0, 0, 0, 286, 1848, 1, 0, 0, 0, 288, 1863, 1, 0, 0, 0, 290, + 1865, 1, 0, 0, 0, 292, 1892, 1, 0, 0, 0, 294, 1895, 1, 0, 0, 0, 296, 1900, + 1, 0, 0, 0, 298, 1905, 1, 0, 0, 0, 300, 1909, 1, 0, 0, 0, 302, 1912, 1, + 0, 0, 0, 304, 1923, 1, 0, 0, 0, 306, 1928, 1, 0, 0, 0, 308, 1931, 1, 0, + 0, 0, 310, 1935, 1, 0, 0, 0, 312, 1957, 1, 0, 0, 0, 314, 1959, 1, 0, 0, + 0, 316, 1961, 1, 0, 0, 0, 318, 1963, 1, 0, 0, 0, 320, 1968, 1, 0, 0, 0, + 322, 1971, 1, 0, 0, 0, 324, 2049, 1, 0, 0, 0, 326, 2051, 1, 0, 0, 0, 328, + 2053, 1, 0, 0, 0, 330, 2057, 1, 0, 0, 0, 332, 2061, 1, 0, 0, 0, 334, 2065, + 1, 0, 0, 0, 336, 2069, 1, 0, 0, 0, 338, 2075, 1, 0, 0, 0, 340, 2079, 1, + 0, 0, 0, 342, 2083, 1, 0, 0, 0, 344, 2090, 1, 0, 0, 0, 346, 2092, 1, 0, + 0, 0, 348, 2096, 1, 0, 0, 0, 350, 2100, 1, 0, 0, 0, 352, 2106, 1, 0, 0, + 0, 354, 2113, 1, 0, 0, 0, 356, 2115, 1, 0, 0, 0, 358, 2127, 1, 0, 0, 0, + 360, 2136, 1, 0, 0, 0, 362, 2147, 1, 0, 0, 0, 364, 2149, 1, 0, 0, 0, 366, + 2151, 1, 0, 0, 0, 368, 2153, 1, 0, 0, 0, 370, 2155, 1, 0, 0, 0, 372, 2157, + 1, 0, 0, 0, 374, 2163, 1, 0, 0, 0, 376, 2172, 1, 0, 0, 0, 378, 2180, 1, + 0, 0, 0, 380, 2182, 1, 0, 0, 0, 382, 2186, 1, 0, 0, 0, 384, 2188, 1, 0, + 0, 0, 386, 2202, 1, 0, 0, 0, 388, 2204, 1, 0, 0, 0, 390, 2206, 1, 0, 0, + 0, 392, 2208, 1, 0, 0, 0, 394, 2210, 1, 0, 0, 0, 396, 2212, 1, 0, 0, 0, + 398, 2214, 1, 0, 0, 0, 400, 2216, 1, 0, 0, 0, 402, 2218, 1, 0, 0, 0, 404, + 2220, 1, 0, 0, 0, 406, 2222, 1, 0, 0, 0, 408, 2224, 1, 0, 0, 0, 410, 2226, + 1, 0, 0, 0, 412, 2229, 1, 0, 0, 0, 414, 2231, 1, 0, 0, 0, 416, 2233, 1, + 0, 0, 0, 418, 2235, 1, 0, 0, 0, 420, 2237, 1, 0, 0, 0, 422, 2240, 1, 0, + 0, 0, 424, 2242, 1, 0, 0, 0, 426, 2244, 1, 0, 0, 0, 428, 2246, 1, 0, 0, + 0, 430, 2248, 1, 0, 0, 0, 432, 2250, 1, 0, 0, 0, 434, 2252, 1, 0, 0, 0, + 436, 2254, 1, 0, 0, 0, 438, 2256, 1, 0, 0, 0, 440, 2258, 1, 0, 0, 0, 442, + 2260, 1, 0, 0, 0, 444, 2262, 1, 0, 0, 0, 446, 2264, 1, 0, 0, 0, 448, 2266, + 1, 0, 0, 0, 450, 2268, 1, 0, 0, 0, 452, 2270, 1, 0, 0, 0, 454, 2272, 1, + 0, 0, 0, 456, 2274, 1, 0, 0, 0, 458, 2276, 1, 0, 0, 0, 460, 2278, 1, 0, + 0, 0, 462, 2280, 1, 0, 0, 0, 464, 2282, 1, 0, 0, 0, 466, 2284, 1, 0, 0, + 0, 468, 2286, 1, 0, 0, 0, 470, 2288, 1, 0, 0, 0, 472, 2290, 1, 0, 0, 0, + 474, 2292, 1, 0, 0, 0, 476, 2294, 1, 0, 0, 0, 478, 2296, 1, 0, 0, 0, 480, + 2298, 1, 0, 0, 0, 482, 2300, 1, 0, 0, 0, 484, 2302, 1, 0, 0, 0, 486, 2304, + 1, 0, 0, 0, 488, 2306, 1, 0, 0, 0, 490, 2308, 1, 0, 0, 0, 492, 2310, 1, + 0, 0, 0, 494, 2312, 1, 0, 0, 0, 496, 2314, 1, 0, 0, 0, 498, 2316, 1, 0, + 0, 0, 500, 2318, 1, 0, 0, 0, 502, 2320, 1, 0, 0, 0, 504, 2322, 1, 0, 0, + 0, 506, 2324, 1, 0, 0, 0, 508, 2326, 1, 0, 0, 0, 510, 2328, 1, 0, 0, 0, + 512, 2330, 1, 0, 0, 0, 514, 2332, 1, 0, 0, 0, 516, 2334, 1, 0, 0, 0, 518, + 2336, 1, 0, 0, 0, 520, 2338, 1, 0, 0, 0, 522, 2340, 1, 0, 0, 0, 524, 2342, + 1, 0, 0, 0, 526, 2344, 1, 0, 0, 0, 528, 2346, 1, 0, 0, 0, 530, 2348, 1, + 0, 0, 0, 532, 2350, 1, 0, 0, 0, 534, 2352, 1, 0, 0, 0, 536, 2354, 1, 0, + 0, 0, 538, 2356, 1, 0, 0, 0, 540, 2358, 1, 0, 0, 0, 542, 2360, 1, 0, 0, + 0, 544, 2362, 1, 0, 0, 0, 546, 2364, 1, 0, 0, 0, 548, 2366, 1, 0, 0, 0, + 550, 2368, 1, 0, 0, 0, 552, 2370, 1, 0, 0, 0, 554, 2372, 1, 0, 0, 0, 556, + 2374, 1, 0, 0, 0, 558, 2376, 1, 0, 0, 0, 560, 2378, 1, 0, 0, 0, 562, 2380, + 1, 0, 0, 0, 564, 2382, 1, 0, 0, 0, 566, 2384, 1, 0, 0, 0, 568, 2386, 1, + 0, 0, 0, 570, 2388, 1, 0, 0, 0, 572, 2390, 1, 0, 0, 0, 574, 2392, 1, 0, + 0, 0, 576, 2394, 1, 0, 0, 0, 578, 2396, 1, 0, 0, 0, 580, 2398, 1, 0, 0, + 0, 582, 2400, 1, 0, 0, 0, 584, 2402, 1, 0, 0, 0, 586, 2404, 1, 0, 0, 0, + 588, 2406, 1, 0, 0, 0, 590, 2408, 1, 0, 0, 0, 592, 2410, 1, 0, 0, 0, 594, + 2412, 1, 0, 0, 0, 596, 2414, 1, 0, 0, 0, 598, 2416, 1, 0, 0, 0, 600, 2418, + 1, 0, 0, 0, 602, 2420, 1, 0, 0, 0, 604, 2422, 1, 0, 0, 0, 606, 2424, 1, + 0, 0, 0, 608, 2426, 1, 0, 0, 0, 610, 2428, 1, 0, 0, 0, 612, 2430, 1, 0, + 0, 0, 614, 2432, 1, 0, 0, 0, 616, 2434, 1, 0, 0, 0, 618, 2436, 1, 0, 0, + 0, 620, 2438, 1, 0, 0, 0, 622, 2440, 1, 0, 0, 0, 624, 2442, 1, 0, 0, 0, + 626, 2444, 1, 0, 0, 0, 628, 2446, 1, 0, 0, 0, 630, 2448, 1, 0, 0, 0, 632, + 2459, 1, 0, 0, 0, 634, 636, 3, 2, 1, 0, 635, 634, 1, 0, 0, 0, 636, 637, + 1, 0, 0, 0, 637, 635, 1, 0, 0, 0, 637, 638, 1, 0, 0, 0, 638, 640, 1, 0, + 0, 0, 639, 641, 5, 15, 0, 0, 640, 639, 1, 0, 0, 0, 640, 641, 1, 0, 0, 0, + 641, 642, 1, 0, 0, 0, 642, 643, 5, 0, 0, 1, 643, 1, 1, 0, 0, 0, 644, 646, + 3, 8, 4, 0, 645, 647, 5, 15, 0, 0, 646, 645, 1, 0, 0, 0, 646, 647, 1, 0, + 0, 0, 647, 648, 1, 0, 0, 0, 648, 649, 3, 4, 2, 0, 649, 652, 1, 0, 0, 0, + 650, 652, 3, 6, 3, 0, 651, 644, 1, 0, 0, 0, 651, 650, 1, 0, 0, 0, 652, + 655, 1, 0, 0, 0, 653, 651, 1, 0, 0, 0, 653, 654, 1, 0, 0, 0, 654, 664, + 1, 0, 0, 0, 655, 653, 1, 0, 0, 0, 656, 661, 3, 8, 4, 0, 657, 659, 5, 15, + 0, 0, 658, 657, 1, 0, 0, 0, 658, 659, 1, 0, 0, 0, 659, 660, 1, 0, 0, 0, + 660, 662, 3, 4, 2, 0, 661, 658, 1, 0, 0, 0, 661, 662, 1, 0, 0, 0, 662, + 665, 1, 0, 0, 0, 663, 665, 3, 6, 3, 0, 664, 656, 1, 0, 0, 0, 664, 663, + 1, 0, 0, 0, 665, 3, 1, 0, 0, 0, 666, 667, 5, 8, 0, 0, 667, 5, 1, 0, 0, + 0, 668, 669, 3, 4, 2, 0, 669, 7, 1, 0, 0, 0, 670, 709, 3, 204, 102, 0, + 671, 709, 3, 130, 65, 0, 672, 709, 3, 124, 62, 0, 673, 709, 3, 98, 49, + 0, 674, 709, 3, 84, 42, 0, 675, 709, 3, 78, 39, 0, 676, 709, 3, 198, 99, + 0, 677, 709, 3, 64, 32, 0, 678, 709, 3, 56, 28, 0, 679, 709, 3, 216, 108, + 0, 680, 709, 3, 54, 27, 0, 681, 709, 3, 44, 22, 0, 682, 709, 3, 36, 18, + 0, 683, 709, 3, 152, 76, 0, 684, 709, 3, 42, 21, 0, 685, 709, 3, 38, 19, + 0, 686, 709, 3, 34, 17, 0, 687, 709, 3, 228, 114, 0, 688, 709, 3, 138, + 69, 0, 689, 709, 3, 140, 70, 0, 690, 709, 3, 150, 75, 0, 691, 709, 3, 148, + 74, 0, 692, 709, 3, 136, 68, 0, 693, 709, 3, 144, 72, 0, 694, 709, 3, 146, + 73, 0, 695, 709, 3, 142, 71, 0, 696, 709, 3, 134, 67, 0, 697, 709, 3, 132, + 66, 0, 698, 709, 3, 28, 14, 0, 699, 709, 3, 266, 133, 0, 700, 709, 3, 26, + 13, 0, 701, 709, 3, 24, 12, 0, 702, 709, 3, 22, 11, 0, 703, 709, 3, 290, + 145, 0, 704, 709, 3, 214, 107, 0, 705, 709, 3, 234, 117, 0, 706, 709, 3, + 212, 106, 0, 707, 709, 3, 10, 5, 0, 708, 670, 1, 0, 0, 0, 708, 671, 1, + 0, 0, 0, 708, 672, 1, 0, 0, 0, 708, 673, 1, 0, 0, 0, 708, 674, 1, 0, 0, + 0, 708, 675, 1, 0, 0, 0, 708, 676, 1, 0, 0, 0, 708, 677, 1, 0, 0, 0, 708, + 678, 1, 0, 0, 0, 708, 679, 1, 0, 0, 0, 708, 680, 1, 0, 0, 0, 708, 681, + 1, 0, 0, 0, 708, 682, 1, 0, 0, 0, 708, 683, 1, 0, 0, 0, 708, 684, 1, 0, + 0, 0, 708, 685, 1, 0, 0, 0, 708, 686, 1, 0, 0, 0, 708, 687, 1, 0, 0, 0, + 708, 688, 1, 0, 0, 0, 708, 689, 1, 0, 0, 0, 708, 690, 1, 0, 0, 0, 708, + 691, 1, 0, 0, 0, 708, 692, 1, 0, 0, 0, 708, 693, 1, 0, 0, 0, 708, 694, + 1, 0, 0, 0, 708, 695, 1, 0, 0, 0, 708, 696, 1, 0, 0, 0, 708, 697, 1, 0, + 0, 0, 708, 698, 1, 0, 0, 0, 708, 699, 1, 0, 0, 0, 708, 700, 1, 0, 0, 0, + 708, 701, 1, 0, 0, 0, 708, 702, 1, 0, 0, 0, 708, 703, 1, 0, 0, 0, 708, + 704, 1, 0, 0, 0, 708, 705, 1, 0, 0, 0, 708, 706, 1, 0, 0, 0, 708, 707, + 1, 0, 0, 0, 709, 9, 1, 0, 0, 0, 710, 713, 3, 456, 228, 0, 711, 713, 3, + 458, 229, 0, 712, 710, 1, 0, 0, 0, 712, 711, 1, 0, 0, 0, 713, 714, 1, 0, + 0, 0, 714, 715, 3, 12, 6, 0, 715, 11, 1, 0, 0, 0, 716, 721, 3, 14, 7, 0, + 717, 721, 3, 16, 8, 0, 718, 721, 3, 18, 9, 0, 719, 721, 3, 20, 10, 0, 720, + 716, 1, 0, 0, 0, 720, 717, 1, 0, 0, 0, 720, 718, 1, 0, 0, 0, 720, 719, + 1, 0, 0, 0, 721, 13, 1, 0, 0, 0, 722, 723, 3, 510, 255, 0, 723, 15, 1, + 0, 0, 0, 724, 725, 3, 574, 287, 0, 725, 17, 1, 0, 0, 0, 726, 728, 3, 572, + 286, 0, 727, 726, 1, 0, 0, 0, 727, 728, 1, 0, 0, 0, 728, 729, 1, 0, 0, + 0, 729, 730, 3, 298, 149, 0, 730, 19, 1, 0, 0, 0, 731, 733, 3, 508, 254, + 0, 732, 731, 1, 0, 0, 0, 732, 733, 1, 0, 0, 0, 733, 734, 1, 0, 0, 0, 734, + 735, 3, 374, 187, 0, 735, 21, 1, 0, 0, 0, 736, 737, 3, 606, 303, 0, 737, + 738, 3, 30, 15, 0, 738, 739, 3, 536, 268, 0, 739, 740, 3, 32, 16, 0, 740, + 741, 3, 476, 238, 0, 741, 742, 3, 388, 194, 0, 742, 23, 1, 0, 0, 0, 743, + 744, 3, 516, 258, 0, 744, 748, 3, 558, 279, 0, 745, 746, 3, 534, 267, 0, + 746, 747, 3, 388, 194, 0, 747, 749, 1, 0, 0, 0, 748, 745, 1, 0, 0, 0, 748, + 749, 1, 0, 0, 0, 749, 751, 1, 0, 0, 0, 750, 752, 3, 528, 264, 0, 751, 750, + 1, 0, 0, 0, 751, 752, 1, 0, 0, 0, 752, 25, 1, 0, 0, 0, 753, 754, 3, 516, + 258, 0, 754, 758, 3, 30, 15, 0, 755, 756, 3, 536, 268, 0, 756, 757, 3, + 32, 16, 0, 757, 759, 1, 0, 0, 0, 758, 755, 1, 0, 0, 0, 758, 759, 1, 0, + 0, 0, 759, 763, 1, 0, 0, 0, 760, 761, 3, 534, 267, 0, 761, 762, 3, 388, + 194, 0, 762, 764, 1, 0, 0, 0, 763, 760, 1, 0, 0, 0, 763, 764, 1, 0, 0, + 0, 764, 27, 1, 0, 0, 0, 765, 766, 3, 484, 242, 0, 766, 767, 3, 30, 15, + 0, 767, 768, 3, 536, 268, 0, 768, 769, 3, 32, 16, 0, 769, 770, 3, 578, + 289, 0, 770, 771, 3, 388, 194, 0, 771, 29, 1, 0, 0, 0, 772, 775, 3, 418, + 209, 0, 773, 775, 3, 420, 210, 0, 774, 772, 1, 0, 0, 0, 774, 773, 1, 0, + 0, 0, 775, 785, 1, 0, 0, 0, 776, 785, 3, 424, 212, 0, 777, 785, 3, 434, + 217, 0, 778, 785, 3, 458, 229, 0, 779, 785, 3, 468, 234, 0, 780, 785, 3, + 452, 226, 0, 781, 785, 3, 462, 231, 0, 782, 785, 3, 524, 262, 0, 783, 785, + 3, 560, 280, 0, 784, 774, 1, 0, 0, 0, 784, 776, 1, 0, 0, 0, 784, 777, 1, + 0, 0, 0, 784, 778, 1, 0, 0, 0, 784, 779, 1, 0, 0, 0, 784, 780, 1, 0, 0, + 0, 784, 781, 1, 0, 0, 0, 784, 782, 1, 0, 0, 0, 784, 783, 1, 0, 0, 0, 785, + 31, 1, 0, 0, 0, 786, 787, 3, 418, 209, 0, 787, 788, 3, 482, 241, 0, 788, + 820, 1, 0, 0, 0, 789, 790, 3, 418, 209, 0, 790, 791, 3, 482, 241, 0, 791, + 792, 3, 488, 244, 0, 792, 793, 3, 508, 254, 0, 793, 794, 3, 374, 187, 0, + 794, 820, 1, 0, 0, 0, 795, 799, 3, 480, 240, 0, 796, 797, 3, 374, 187, + 0, 797, 798, 5, 10, 0, 0, 798, 800, 1, 0, 0, 0, 799, 796, 1, 0, 0, 0, 799, + 800, 1, 0, 0, 0, 800, 801, 1, 0, 0, 0, 801, 802, 3, 400, 200, 0, 802, 820, + 1, 0, 0, 0, 803, 804, 3, 418, 209, 0, 804, 805, 3, 510, 255, 0, 805, 820, + 1, 0, 0, 0, 806, 807, 3, 508, 254, 0, 807, 808, 3, 374, 187, 0, 808, 820, + 1, 0, 0, 0, 809, 811, 3, 572, 286, 0, 810, 809, 1, 0, 0, 0, 810, 811, 1, + 0, 0, 0, 811, 812, 1, 0, 0, 0, 812, 820, 3, 298, 149, 0, 813, 814, 3, 418, + 209, 0, 814, 815, 3, 558, 279, 0, 815, 820, 1, 0, 0, 0, 816, 817, 3, 556, + 278, 0, 817, 818, 3, 388, 194, 0, 818, 820, 1, 0, 0, 0, 819, 786, 1, 0, + 0, 0, 819, 789, 1, 0, 0, 0, 819, 795, 1, 0, 0, 0, 819, 803, 1, 0, 0, 0, + 819, 806, 1, 0, 0, 0, 819, 810, 1, 0, 0, 0, 819, 813, 1, 0, 0, 0, 819, + 816, 1, 0, 0, 0, 820, 33, 1, 0, 0, 0, 821, 822, 3, 452, 226, 0, 822, 824, + 3, 594, 297, 0, 823, 825, 3, 276, 138, 0, 824, 823, 1, 0, 0, 0, 824, 825, + 1, 0, 0, 0, 825, 826, 1, 0, 0, 0, 826, 827, 3, 404, 202, 0, 827, 828, 3, + 604, 302, 0, 828, 829, 3, 544, 272, 0, 829, 832, 3, 368, 184, 0, 830, 833, + 3, 570, 285, 0, 831, 833, 3, 526, 263, 0, 832, 830, 1, 0, 0, 0, 832, 831, + 1, 0, 0, 0, 832, 833, 1, 0, 0, 0, 833, 35, 1, 0, 0, 0, 834, 835, 3, 452, + 226, 0, 835, 837, 3, 556, 278, 0, 836, 838, 3, 276, 138, 0, 837, 836, 1, + 0, 0, 0, 837, 838, 1, 0, 0, 0, 838, 839, 1, 0, 0, 0, 839, 841, 3, 388, + 194, 0, 840, 842, 3, 126, 63, 0, 841, 840, 1, 0, 0, 0, 841, 842, 1, 0, + 0, 0, 842, 37, 1, 0, 0, 0, 843, 844, 3, 452, 226, 0, 844, 846, 3, 586, + 293, 0, 845, 847, 3, 276, 138, 0, 846, 845, 1, 0, 0, 0, 846, 847, 1, 0, + 0, 0, 847, 851, 1, 0, 0, 0, 848, 849, 3, 374, 187, 0, 849, 850, 5, 10, + 0, 0, 850, 852, 1, 0, 0, 0, 851, 848, 1, 0, 0, 0, 851, 852, 1, 0, 0, 0, + 852, 853, 1, 0, 0, 0, 853, 854, 3, 396, 198, 0, 854, 855, 3, 610, 305, + 0, 855, 856, 3, 40, 20, 0, 856, 857, 3, 612, 306, 0, 857, 39, 1, 0, 0, + 0, 858, 859, 3, 378, 189, 0, 859, 866, 3, 380, 190, 0, 860, 861, 3, 626, + 313, 0, 861, 862, 3, 378, 189, 0, 862, 863, 3, 380, 190, 0, 863, 865, 1, + 0, 0, 0, 864, 860, 1, 0, 0, 0, 865, 868, 1, 0, 0, 0, 866, 864, 1, 0, 0, + 0, 866, 867, 1, 0, 0, 0, 867, 41, 1, 0, 0, 0, 868, 866, 1, 0, 0, 0, 869, + 870, 3, 452, 226, 0, 870, 872, 3, 580, 290, 0, 871, 873, 3, 276, 138, 0, + 872, 871, 1, 0, 0, 0, 872, 873, 1, 0, 0, 0, 873, 877, 1, 0, 0, 0, 874, + 875, 3, 374, 187, 0, 875, 876, 5, 10, 0, 0, 876, 878, 1, 0, 0, 0, 877, + 874, 1, 0, 0, 0, 877, 878, 1, 0, 0, 0, 878, 879, 1, 0, 0, 0, 879, 880, + 3, 390, 195, 0, 880, 881, 3, 596, 298, 0, 881, 882, 3, 392, 196, 0, 882, + 43, 1, 0, 0, 0, 883, 884, 3, 452, 226, 0, 884, 885, 3, 522, 261, 0, 885, + 887, 3, 600, 300, 0, 886, 888, 3, 276, 138, 0, 887, 886, 1, 0, 0, 0, 887, + 888, 1, 0, 0, 0, 888, 892, 1, 0, 0, 0, 889, 890, 3, 374, 187, 0, 890, 891, + 5, 10, 0, 0, 891, 893, 1, 0, 0, 0, 892, 889, 1, 0, 0, 0, 892, 893, 1, 0, + 0, 0, 893, 894, 1, 0, 0, 0, 894, 895, 3, 394, 197, 0, 895, 896, 3, 430, + 215, 0, 896, 897, 3, 560, 280, 0, 897, 898, 3, 284, 142, 0, 898, 899, 3, + 476, 238, 0, 899, 900, 3, 298, 149, 0, 900, 901, 3, 46, 23, 0, 901, 902, + 3, 546, 273, 0, 902, 903, 3, 504, 252, 0, 903, 904, 3, 610, 305, 0, 904, + 905, 3, 284, 142, 0, 905, 909, 3, 612, 306, 0, 906, 907, 3, 604, 302, 0, + 907, 908, 3, 52, 26, 0, 908, 910, 1, 0, 0, 0, 909, 906, 1, 0, 0, 0, 909, + 910, 1, 0, 0, 0, 910, 45, 1, 0, 0, 0, 911, 912, 3, 602, 301, 0, 912, 916, + 3, 48, 24, 0, 913, 914, 3, 426, 213, 0, 914, 915, 3, 322, 161, 0, 915, + 917, 1, 0, 0, 0, 916, 913, 1, 0, 0, 0, 916, 917, 1, 0, 0, 0, 917, 47, 1, + 0, 0, 0, 918, 924, 3, 50, 25, 0, 919, 920, 3, 426, 213, 0, 920, 921, 3, + 50, 25, 0, 921, 923, 1, 0, 0, 0, 922, 919, 1, 0, 0, 0, 923, 926, 1, 0, + 0, 0, 924, 922, 1, 0, 0, 0, 924, 925, 1, 0, 0, 0, 925, 49, 1, 0, 0, 0, + 926, 924, 1, 0, 0, 0, 927, 928, 3, 378, 189, 0, 928, 929, 3, 500, 250, + 0, 929, 930, 3, 530, 265, 0, 930, 931, 3, 532, 266, 0, 931, 51, 1, 0, 0, + 0, 932, 939, 3, 158, 79, 0, 933, 934, 3, 158, 79, 0, 934, 935, 3, 426, + 213, 0, 935, 936, 3, 156, 78, 0, 936, 939, 1, 0, 0, 0, 937, 939, 3, 156, + 78, 0, 938, 932, 1, 0, 0, 0, 938, 933, 1, 0, 0, 0, 938, 937, 1, 0, 0, 0, + 939, 53, 1, 0, 0, 0, 940, 941, 3, 452, 226, 0, 941, 943, 3, 508, 254, 0, + 942, 944, 3, 276, 138, 0, 943, 942, 1, 0, 0, 0, 943, 944, 1, 0, 0, 0, 944, + 945, 1, 0, 0, 0, 945, 946, 3, 374, 187, 0, 946, 947, 3, 604, 302, 0, 947, + 948, 3, 552, 276, 0, 948, 949, 5, 19, 0, 0, 949, 950, 3, 614, 307, 0, 950, + 951, 3, 206, 103, 0, 951, 955, 3, 616, 308, 0, 952, 953, 3, 426, 213, 0, + 953, 954, 3, 210, 105, 0, 954, 956, 1, 0, 0, 0, 955, 952, 1, 0, 0, 0, 955, + 956, 1, 0, 0, 0, 956, 55, 1, 0, 0, 0, 957, 959, 3, 452, 226, 0, 958, 960, + 3, 76, 38, 0, 959, 958, 1, 0, 0, 0, 959, 960, 1, 0, 0, 0, 960, 961, 1, + 0, 0, 0, 961, 963, 3, 480, 240, 0, 962, 964, 3, 276, 138, 0, 963, 962, + 1, 0, 0, 0, 963, 964, 1, 0, 0, 0, 964, 968, 1, 0, 0, 0, 965, 966, 3, 374, + 187, 0, 966, 967, 5, 10, 0, 0, 967, 969, 1, 0, 0, 0, 968, 965, 1, 0, 0, + 0, 968, 969, 1, 0, 0, 0, 969, 970, 1, 0, 0, 0, 970, 971, 3, 400, 200, 0, + 971, 973, 3, 610, 305, 0, 972, 974, 3, 60, 30, 0, 973, 972, 1, 0, 0, 0, + 973, 974, 1, 0, 0, 0, 974, 975, 1, 0, 0, 0, 975, 976, 3, 612, 306, 0, 976, + 977, 3, 62, 31, 0, 977, 978, 3, 554, 277, 0, 978, 979, 3, 380, 190, 0, + 979, 980, 3, 512, 256, 0, 980, 981, 3, 402, 201, 0, 981, 982, 3, 430, 215, + 0, 982, 983, 3, 58, 29, 0, 983, 57, 1, 0, 0, 0, 984, 985, 7, 0, 0, 0, 985, + 59, 1, 0, 0, 0, 986, 992, 3, 410, 205, 0, 987, 988, 3, 626, 313, 0, 988, + 989, 3, 410, 205, 0, 989, 991, 1, 0, 0, 0, 990, 987, 1, 0, 0, 0, 991, 994, + 1, 0, 0, 0, 992, 990, 1, 0, 0, 0, 992, 993, 1, 0, 0, 0, 993, 61, 1, 0, + 0, 0, 994, 992, 1, 0, 0, 0, 995, 1000, 3, 444, 222, 0, 996, 997, 3, 554, + 277, 0, 997, 998, 3, 532, 266, 0, 998, 1000, 1, 0, 0, 0, 999, 995, 1, 0, + 0, 0, 999, 996, 1, 0, 0, 0, 1000, 1001, 1, 0, 0, 0, 1001, 1002, 3, 536, + 268, 0, 1002, 1003, 3, 532, 266, 0, 1003, 1004, 3, 494, 247, 0, 1004, 63, + 1, 0, 0, 0, 1005, 1007, 3, 452, 226, 0, 1006, 1008, 3, 76, 38, 0, 1007, + 1006, 1, 0, 0, 0, 1007, 1008, 1, 0, 0, 0, 1008, 1009, 1, 0, 0, 0, 1009, + 1011, 3, 416, 208, 0, 1010, 1012, 3, 276, 138, 0, 1011, 1010, 1, 0, 0, + 0, 1011, 1012, 1, 0, 0, 0, 1012, 1016, 1, 0, 0, 0, 1013, 1014, 3, 374, + 187, 0, 1014, 1015, 5, 10, 0, 0, 1015, 1017, 1, 0, 0, 0, 1016, 1013, 1, + 0, 0, 0, 1016, 1017, 1, 0, 0, 0, 1017, 1018, 1, 0, 0, 0, 1018, 1019, 3, + 398, 199, 0, 1019, 1020, 3, 610, 305, 0, 1020, 1021, 3, 380, 190, 0, 1021, + 1022, 3, 612, 306, 0, 1022, 1023, 3, 564, 282, 0, 1023, 1024, 3, 400, 200, + 0, 1024, 1025, 3, 568, 284, 0, 1025, 1026, 3, 380, 190, 0, 1026, 1027, + 3, 474, 237, 0, 1027, 1028, 3, 400, 200, 0, 1028, 1029, 3, 492, 246, 0, + 1029, 1030, 3, 66, 33, 0, 1030, 65, 1, 0, 0, 0, 1031, 1036, 3, 362, 181, + 0, 1032, 1036, 3, 74, 37, 0, 1033, 1036, 3, 72, 36, 0, 1034, 1036, 3, 68, + 34, 0, 1035, 1031, 1, 0, 0, 0, 1035, 1032, 1, 0, 0, 0, 1035, 1033, 1, 0, + 0, 0, 1035, 1034, 1, 0, 0, 0, 1036, 67, 1, 0, 0, 0, 1037, 1038, 3, 614, + 307, 0, 1038, 1044, 3, 70, 35, 0, 1039, 1040, 3, 626, 313, 0, 1040, 1041, + 3, 70, 35, 0, 1041, 1043, 1, 0, 0, 0, 1042, 1039, 1, 0, 0, 0, 1043, 1046, + 1, 0, 0, 0, 1044, 1042, 1, 0, 0, 0, 1044, 1045, 1, 0, 0, 0, 1045, 1047, + 1, 0, 0, 0, 1046, 1044, 1, 0, 0, 0, 1047, 1048, 3, 616, 308, 0, 1048, 69, + 1, 0, 0, 0, 1049, 1050, 3, 408, 204, 0, 1050, 1051, 5, 9, 0, 0, 1051, 1052, + 3, 66, 33, 0, 1052, 71, 1, 0, 0, 0, 1053, 1054, 3, 610, 305, 0, 1054, 1061, + 3, 74, 37, 0, 1055, 1056, 3, 626, 313, 0, 1056, 1057, 3, 362, 181, 0, 1057, + 1060, 1, 0, 0, 0, 1058, 1060, 3, 74, 37, 0, 1059, 1055, 1, 0, 0, 0, 1059, + 1058, 1, 0, 0, 0, 1060, 1063, 1, 0, 0, 0, 1061, 1059, 1, 0, 0, 0, 1061, + 1062, 1, 0, 0, 0, 1062, 1064, 1, 0, 0, 0, 1063, 1061, 1, 0, 0, 0, 1064, + 1065, 3, 612, 306, 0, 1065, 73, 1, 0, 0, 0, 1066, 1067, 3, 610, 305, 0, + 1067, 1073, 3, 362, 181, 0, 1068, 1069, 3, 626, 313, 0, 1069, 1070, 3, + 362, 181, 0, 1070, 1072, 1, 0, 0, 0, 1071, 1068, 1, 0, 0, 0, 1072, 1075, + 1, 0, 0, 0, 1073, 1071, 1, 0, 0, 0, 1073, 1074, 1, 0, 0, 0, 1074, 1076, + 1, 0, 0, 0, 1075, 1073, 1, 0, 0, 0, 1076, 1077, 3, 612, 306, 0, 1077, 75, + 1, 0, 0, 0, 1078, 1079, 3, 540, 270, 0, 1079, 1080, 3, 550, 275, 0, 1080, + 77, 1, 0, 0, 0, 1081, 1082, 3, 424, 212, 0, 1082, 1083, 3, 594, 297, 0, + 1083, 1084, 3, 404, 202, 0, 1084, 1085, 3, 604, 302, 0, 1085, 1087, 3, + 80, 40, 0, 1086, 1088, 3, 82, 41, 0, 1087, 1086, 1, 0, 0, 0, 1087, 1088, + 1, 0, 0, 0, 1088, 79, 1, 0, 0, 0, 1089, 1090, 3, 544, 272, 0, 1090, 1091, + 3, 368, 184, 0, 1091, 81, 1, 0, 0, 0, 1092, 1095, 3, 570, 285, 0, 1093, + 1095, 3, 526, 263, 0, 1094, 1092, 1, 0, 0, 0, 1094, 1093, 1, 0, 0, 0, 1095, + 83, 1, 0, 0, 0, 1096, 1097, 3, 424, 212, 0, 1097, 1101, 3, 586, 293, 0, + 1098, 1099, 3, 374, 187, 0, 1099, 1100, 5, 10, 0, 0, 1100, 1102, 1, 0, + 0, 0, 1101, 1098, 1, 0, 0, 0, 1101, 1102, 1, 0, 0, 0, 1102, 1103, 1, 0, + 0, 0, 1103, 1104, 3, 396, 198, 0, 1104, 1105, 3, 86, 43, 0, 1105, 85, 1, + 0, 0, 0, 1106, 1110, 3, 96, 48, 0, 1107, 1110, 3, 94, 47, 0, 1108, 1110, + 3, 88, 44, 0, 1109, 1106, 1, 0, 0, 0, 1109, 1107, 1, 0, 0, 0, 1109, 1108, + 1, 0, 0, 0, 1110, 87, 1, 0, 0, 0, 1111, 1112, 3, 548, 274, 0, 1112, 1113, + 3, 90, 45, 0, 1113, 89, 1, 0, 0, 0, 1114, 1120, 3, 92, 46, 0, 1115, 1116, + 3, 426, 213, 0, 1116, 1117, 3, 92, 46, 0, 1117, 1119, 1, 0, 0, 0, 1118, + 1115, 1, 0, 0, 0, 1119, 1122, 1, 0, 0, 0, 1120, 1118, 1, 0, 0, 0, 1120, + 1121, 1, 0, 0, 0, 1121, 91, 1, 0, 0, 0, 1122, 1120, 1, 0, 0, 0, 1123, 1124, + 3, 378, 189, 0, 1124, 1125, 3, 578, 289, 0, 1125, 1126, 3, 378, 189, 0, + 1126, 93, 1, 0, 0, 0, 1127, 1128, 3, 414, 207, 0, 1128, 1129, 3, 378, 189, + 0, 1129, 1136, 3, 380, 190, 0, 1130, 1131, 3, 626, 313, 0, 1131, 1132, + 3, 378, 189, 0, 1132, 1133, 3, 380, 190, 0, 1133, 1135, 1, 0, 0, 0, 1134, + 1130, 1, 0, 0, 0, 1135, 1138, 1, 0, 0, 0, 1136, 1134, 1, 0, 0, 0, 1136, + 1137, 1, 0, 0, 0, 1137, 95, 1, 0, 0, 0, 1138, 1136, 1, 0, 0, 0, 1139, 1140, + 3, 424, 212, 0, 1140, 1141, 3, 378, 189, 0, 1141, 1142, 3, 586, 293, 0, + 1142, 1143, 3, 380, 190, 0, 1143, 97, 1, 0, 0, 0, 1144, 1145, 3, 424, 212, + 0, 1145, 1146, 3, 572, 286, 0, 1146, 1147, 3, 298, 149, 0, 1147, 1148, + 3, 100, 50, 0, 1148, 99, 1, 0, 0, 0, 1149, 1156, 3, 118, 59, 0, 1150, 1156, + 3, 108, 54, 0, 1151, 1156, 3, 106, 53, 0, 1152, 1156, 3, 112, 56, 0, 1153, + 1156, 3, 104, 52, 0, 1154, 1156, 3, 102, 51, 0, 1155, 1149, 1, 0, 0, 0, + 1155, 1150, 1, 0, 0, 0, 1155, 1151, 1, 0, 0, 0, 1155, 1152, 1, 0, 0, 0, + 1155, 1153, 1, 0, 0, 0, 1155, 1154, 1, 0, 0, 0, 1156, 101, 1, 0, 0, 0, + 1157, 1158, 3, 604, 302, 0, 1158, 1159, 3, 158, 79, 0, 1159, 103, 1, 0, + 0, 0, 1160, 1161, 3, 548, 274, 0, 1161, 1162, 3, 378, 189, 0, 1162, 1163, + 3, 578, 289, 0, 1163, 1164, 3, 378, 189, 0, 1164, 105, 1, 0, 0, 0, 1165, + 1166, 3, 462, 231, 0, 1166, 1167, 3, 448, 224, 0, 1167, 1168, 3, 566, 283, + 0, 1168, 107, 1, 0, 0, 0, 1169, 1170, 3, 462, 231, 0, 1170, 1171, 3, 110, + 55, 0, 1171, 109, 1, 0, 0, 0, 1172, 1178, 3, 378, 189, 0, 1173, 1174, 3, + 626, 313, 0, 1174, 1175, 3, 378, 189, 0, 1175, 1177, 1, 0, 0, 0, 1176, + 1173, 1, 0, 0, 0, 1177, 1180, 1, 0, 0, 0, 1178, 1176, 1, 0, 0, 0, 1178, + 1179, 1, 0, 0, 0, 1179, 111, 1, 0, 0, 0, 1180, 1178, 1, 0, 0, 0, 1181, + 1182, 3, 424, 212, 0, 1182, 1183, 3, 114, 57, 0, 1183, 113, 1, 0, 0, 0, + 1184, 1190, 3, 116, 58, 0, 1185, 1186, 3, 626, 313, 0, 1186, 1187, 3, 116, + 58, 0, 1187, 1189, 1, 0, 0, 0, 1188, 1185, 1, 0, 0, 0, 1189, 1192, 1, 0, + 0, 0, 1190, 1188, 1, 0, 0, 0, 1190, 1191, 1, 0, 0, 0, 1191, 115, 1, 0, + 0, 0, 1192, 1190, 1, 0, 0, 0, 1193, 1194, 3, 378, 189, 0, 1194, 1195, 3, + 586, 293, 0, 1195, 1196, 3, 380, 190, 0, 1196, 117, 1, 0, 0, 0, 1197, 1198, + 3, 414, 207, 0, 1198, 1199, 3, 120, 60, 0, 1199, 119, 1, 0, 0, 0, 1200, + 1206, 3, 122, 61, 0, 1201, 1202, 3, 626, 313, 0, 1202, 1203, 3, 122, 61, + 0, 1203, 1205, 1, 0, 0, 0, 1204, 1201, 1, 0, 0, 0, 1205, 1208, 1, 0, 0, + 0, 1206, 1204, 1, 0, 0, 0, 1206, 1207, 1, 0, 0, 0, 1207, 121, 1, 0, 0, + 0, 1208, 1206, 1, 0, 0, 0, 1209, 1210, 3, 378, 189, 0, 1210, 1211, 3, 380, + 190, 0, 1211, 123, 1, 0, 0, 0, 1212, 1213, 3, 424, 212, 0, 1213, 1214, + 3, 556, 278, 0, 1214, 1216, 3, 388, 194, 0, 1215, 1217, 3, 126, 63, 0, + 1216, 1215, 1, 0, 0, 0, 1216, 1217, 1, 0, 0, 0, 1217, 125, 1, 0, 0, 0, + 1218, 1219, 3, 604, 302, 0, 1219, 1225, 3, 128, 64, 0, 1220, 1221, 3, 426, + 213, 0, 1221, 1222, 3, 128, 64, 0, 1222, 1224, 1, 0, 0, 0, 1223, 1220, + 1, 0, 0, 0, 1224, 1227, 1, 0, 0, 0, 1225, 1223, 1, 0, 0, 0, 1225, 1226, + 1, 0, 0, 0, 1226, 127, 1, 0, 0, 0, 1227, 1225, 1, 0, 0, 0, 1228, 1229, + 3, 544, 272, 0, 1229, 1230, 5, 19, 0, 0, 1230, 1231, 3, 368, 184, 0, 1231, + 1245, 1, 0, 0, 0, 1232, 1233, 3, 520, 260, 0, 1233, 1234, 5, 19, 0, 0, + 1234, 1235, 3, 370, 185, 0, 1235, 1245, 1, 0, 0, 0, 1236, 1237, 3, 570, + 285, 0, 1237, 1238, 5, 19, 0, 0, 1238, 1239, 3, 370, 185, 0, 1239, 1245, + 1, 0, 0, 0, 1240, 1241, 3, 538, 269, 0, 1241, 1242, 5, 19, 0, 0, 1242, + 1243, 3, 166, 83, 0, 1243, 1245, 1, 0, 0, 0, 1244, 1228, 1, 0, 0, 0, 1244, + 1232, 1, 0, 0, 0, 1244, 1236, 1, 0, 0, 0, 1244, 1240, 1, 0, 0, 0, 1245, + 129, 1, 0, 0, 0, 1246, 1247, 3, 424, 212, 0, 1247, 1248, 3, 522, 261, 0, + 1248, 1252, 3, 600, 300, 0, 1249, 1250, 3, 374, 187, 0, 1250, 1251, 5, + 10, 0, 0, 1251, 1253, 1, 0, 0, 0, 1252, 1249, 1, 0, 0, 0, 1252, 1253, 1, + 0, 0, 0, 1253, 1254, 1, 0, 0, 0, 1254, 1258, 3, 394, 197, 0, 1255, 1256, + 3, 604, 302, 0, 1256, 1257, 3, 158, 79, 0, 1257, 1259, 1, 0, 0, 0, 1258, + 1255, 1, 0, 0, 0, 1258, 1259, 1, 0, 0, 0, 1259, 131, 1, 0, 0, 0, 1260, + 1261, 3, 462, 231, 0, 1261, 1263, 3, 594, 297, 0, 1262, 1264, 3, 278, 139, + 0, 1263, 1262, 1, 0, 0, 0, 1263, 1264, 1, 0, 0, 0, 1264, 1265, 1, 0, 0, + 0, 1265, 1266, 3, 404, 202, 0, 1266, 133, 1, 0, 0, 0, 1267, 1268, 3, 462, + 231, 0, 1268, 1270, 3, 586, 293, 0, 1269, 1271, 3, 278, 139, 0, 1270, 1269, + 1, 0, 0, 0, 1270, 1271, 1, 0, 0, 0, 1271, 1275, 1, 0, 0, 0, 1272, 1273, + 3, 374, 187, 0, 1273, 1274, 5, 10, 0, 0, 1274, 1276, 1, 0, 0, 0, 1275, + 1272, 1, 0, 0, 0, 1275, 1276, 1, 0, 0, 0, 1276, 1277, 1, 0, 0, 0, 1277, + 1278, 3, 396, 198, 0, 1278, 135, 1, 0, 0, 0, 1279, 1280, 3, 462, 231, 0, + 1280, 1281, 3, 522, 261, 0, 1281, 1283, 3, 600, 300, 0, 1282, 1284, 3, + 278, 139, 0, 1283, 1282, 1, 0, 0, 0, 1283, 1284, 1, 0, 0, 0, 1284, 1288, + 1, 0, 0, 0, 1285, 1286, 3, 374, 187, 0, 1286, 1287, 5, 10, 0, 0, 1287, + 1289, 1, 0, 0, 0, 1288, 1285, 1, 0, 0, 0, 1288, 1289, 1, 0, 0, 0, 1289, + 1290, 1, 0, 0, 0, 1290, 1291, 3, 394, 197, 0, 1291, 137, 1, 0, 0, 0, 1292, + 1293, 3, 462, 231, 0, 1293, 1295, 3, 416, 208, 0, 1294, 1296, 3, 278, 139, + 0, 1295, 1294, 1, 0, 0, 0, 1295, 1296, 1, 0, 0, 0, 1296, 1300, 1, 0, 0, + 0, 1297, 1298, 3, 374, 187, 0, 1298, 1299, 5, 10, 0, 0, 1299, 1301, 1, + 0, 0, 0, 1300, 1297, 1, 0, 0, 0, 1300, 1301, 1, 0, 0, 0, 1301, 1302, 1, + 0, 0, 0, 1302, 1303, 3, 398, 199, 0, 1303, 139, 1, 0, 0, 0, 1304, 1305, + 3, 462, 231, 0, 1305, 1307, 3, 480, 240, 0, 1306, 1308, 3, 278, 139, 0, + 1307, 1306, 1, 0, 0, 0, 1307, 1308, 1, 0, 0, 0, 1308, 1312, 1, 0, 0, 0, + 1309, 1310, 3, 374, 187, 0, 1310, 1311, 5, 10, 0, 0, 1311, 1313, 1, 0, + 0, 0, 1312, 1309, 1, 0, 0, 0, 1312, 1313, 1, 0, 0, 0, 1313, 1314, 1, 0, + 0, 0, 1314, 1315, 3, 400, 200, 0, 1315, 141, 1, 0, 0, 0, 1316, 1317, 3, + 462, 231, 0, 1317, 1319, 3, 580, 290, 0, 1318, 1320, 3, 278, 139, 0, 1319, + 1318, 1, 0, 0, 0, 1319, 1320, 1, 0, 0, 0, 1320, 1321, 1, 0, 0, 0, 1321, + 1322, 3, 390, 195, 0, 1322, 1323, 3, 536, 268, 0, 1323, 1324, 3, 298, 149, + 0, 1324, 143, 1, 0, 0, 0, 1325, 1326, 3, 462, 231, 0, 1326, 1328, 3, 556, + 278, 0, 1327, 1329, 3, 278, 139, 0, 1328, 1327, 1, 0, 0, 0, 1328, 1329, + 1, 0, 0, 0, 1329, 1330, 1, 0, 0, 0, 1330, 1331, 3, 388, 194, 0, 1331, 145, + 1, 0, 0, 0, 1332, 1333, 3, 462, 231, 0, 1333, 1335, 3, 572, 286, 0, 1334, + 1336, 3, 278, 139, 0, 1335, 1334, 1, 0, 0, 0, 1335, 1336, 1, 0, 0, 0, 1336, + 1337, 1, 0, 0, 0, 1337, 1338, 3, 298, 149, 0, 1338, 147, 1, 0, 0, 0, 1339, + 1340, 3, 462, 231, 0, 1340, 1342, 3, 508, 254, 0, 1341, 1343, 3, 278, 139, + 0, 1342, 1341, 1, 0, 0, 0, 1342, 1343, 1, 0, 0, 0, 1343, 1344, 1, 0, 0, + 0, 1344, 1345, 3, 374, 187, 0, 1345, 149, 1, 0, 0, 0, 1346, 1347, 3, 462, + 231, 0, 1347, 1349, 3, 490, 245, 0, 1348, 1350, 3, 278, 139, 0, 1349, 1348, + 1, 0, 0, 0, 1349, 1350, 1, 0, 0, 0, 1350, 1354, 1, 0, 0, 0, 1351, 1352, + 3, 374, 187, 0, 1352, 1353, 5, 10, 0, 0, 1353, 1355, 1, 0, 0, 0, 1354, + 1351, 1, 0, 0, 0, 1354, 1355, 1, 0, 0, 0, 1355, 1356, 1, 0, 0, 0, 1356, + 1357, 3, 218, 109, 0, 1357, 151, 1, 0, 0, 0, 1358, 1359, 3, 452, 226, 0, + 1359, 1361, 3, 572, 286, 0, 1360, 1362, 3, 276, 138, 0, 1361, 1360, 1, + 0, 0, 0, 1361, 1362, 1, 0, 0, 0, 1362, 1363, 1, 0, 0, 0, 1363, 1364, 3, + 298, 149, 0, 1364, 1365, 3, 610, 305, 0, 1365, 1366, 3, 174, 87, 0, 1366, + 1368, 3, 612, 306, 0, 1367, 1369, 3, 154, 77, 0, 1368, 1367, 1, 0, 0, 0, + 1368, 1369, 1, 0, 0, 0, 1369, 153, 1, 0, 0, 0, 1370, 1372, 3, 604, 302, + 0, 1371, 1373, 3, 158, 79, 0, 1372, 1371, 1, 0, 0, 0, 1372, 1373, 1, 0, + 0, 0, 1373, 1375, 1, 0, 0, 0, 1374, 1376, 3, 156, 78, 0, 1375, 1374, 1, + 0, 0, 0, 1375, 1376, 1, 0, 0, 0, 1376, 155, 1, 0, 0, 0, 1377, 1378, 3, + 446, 223, 0, 1378, 1379, 3, 542, 271, 0, 1379, 1380, 3, 442, 221, 0, 1380, + 1381, 3, 610, 305, 0, 1381, 1383, 3, 378, 189, 0, 1382, 1384, 3, 386, 193, + 0, 1383, 1382, 1, 0, 0, 0, 1383, 1384, 1, 0, 0, 0, 1384, 1385, 1, 0, 0, + 0, 1385, 1386, 3, 612, 306, 0, 1386, 157, 1, 0, 0, 0, 1387, 1393, 3, 160, + 80, 0, 1388, 1389, 3, 426, 213, 0, 1389, 1390, 3, 160, 80, 0, 1390, 1392, + 1, 0, 0, 0, 1391, 1388, 1, 0, 0, 0, 1392, 1395, 1, 0, 0, 0, 1393, 1391, + 1, 0, 0, 0, 1393, 1394, 1, 0, 0, 0, 1394, 159, 1, 0, 0, 0, 1395, 1393, + 1, 0, 0, 0, 1396, 1397, 3, 162, 81, 0, 1397, 1398, 5, 19, 0, 0, 1398, 1399, + 3, 164, 82, 0, 1399, 1405, 1, 0, 0, 0, 1400, 1401, 3, 162, 81, 0, 1401, + 1402, 5, 19, 0, 0, 1402, 1403, 3, 166, 83, 0, 1403, 1405, 1, 0, 0, 0, 1404, + 1396, 1, 0, 0, 0, 1404, 1400, 1, 0, 0, 0, 1405, 161, 1, 0, 0, 0, 1406, + 1407, 5, 174, 0, 0, 1407, 163, 1, 0, 0, 0, 1408, 1411, 3, 368, 184, 0, + 1409, 1411, 3, 366, 183, 0, 1410, 1408, 1, 0, 0, 0, 1410, 1409, 1, 0, 0, + 0, 1411, 165, 1, 0, 0, 0, 1412, 1413, 3, 614, 307, 0, 1413, 1419, 3, 168, + 84, 0, 1414, 1415, 3, 626, 313, 0, 1415, 1416, 3, 168, 84, 0, 1416, 1418, + 1, 0, 0, 0, 1417, 1414, 1, 0, 0, 0, 1418, 1421, 1, 0, 0, 0, 1419, 1417, + 1, 0, 0, 0, 1419, 1420, 1, 0, 0, 0, 1420, 1422, 1, 0, 0, 0, 1421, 1419, + 1, 0, 0, 0, 1422, 1423, 3, 616, 308, 0, 1423, 167, 1, 0, 0, 0, 1424, 1425, + 3, 170, 85, 0, 1425, 1426, 5, 9, 0, 0, 1426, 1427, 3, 172, 86, 0, 1427, + 169, 1, 0, 0, 0, 1428, 1429, 3, 368, 184, 0, 1429, 171, 1, 0, 0, 0, 1430, + 1433, 3, 368, 184, 0, 1431, 1433, 3, 366, 183, 0, 1432, 1430, 1, 0, 0, + 0, 1432, 1431, 1, 0, 0, 0, 1433, 173, 1, 0, 0, 0, 1434, 1440, 3, 176, 88, + 0, 1435, 1436, 3, 626, 313, 0, 1436, 1437, 3, 176, 88, 0, 1437, 1439, 1, + 0, 0, 0, 1438, 1435, 1, 0, 0, 0, 1439, 1442, 1, 0, 0, 0, 1440, 1438, 1, + 0, 0, 0, 1440, 1441, 1, 0, 0, 0, 1441, 1446, 1, 0, 0, 0, 1442, 1440, 1, + 0, 0, 0, 1443, 1444, 3, 626, 313, 0, 1444, 1445, 3, 180, 90, 0, 1445, 1447, + 1, 0, 0, 0, 1446, 1443, 1, 0, 0, 0, 1446, 1447, 1, 0, 0, 0, 1447, 175, + 1, 0, 0, 0, 1448, 1449, 3, 378, 189, 0, 1449, 1451, 3, 380, 190, 0, 1450, + 1452, 3, 178, 89, 0, 1451, 1450, 1, 0, 0, 0, 1451, 1452, 1, 0, 0, 0, 1452, + 177, 1, 0, 0, 0, 1453, 1454, 3, 546, 273, 0, 1454, 1455, 3, 504, 252, 0, + 1455, 179, 1, 0, 0, 0, 1456, 1457, 3, 546, 273, 0, 1457, 1458, 3, 504, + 252, 0, 1458, 1459, 3, 610, 305, 0, 1459, 1460, 3, 182, 91, 0, 1460, 1461, + 3, 612, 306, 0, 1461, 181, 1, 0, 0, 0, 1462, 1466, 3, 184, 92, 0, 1463, + 1466, 3, 186, 93, 0, 1464, 1466, 3, 188, 94, 0, 1465, 1462, 1, 0, 0, 0, + 1465, 1463, 1, 0, 0, 0, 1465, 1464, 1, 0, 0, 0, 1466, 183, 1, 0, 0, 0, + 1467, 1468, 3, 378, 189, 0, 1468, 185, 1, 0, 0, 0, 1469, 1470, 3, 194, + 97, 0, 1470, 1471, 3, 626, 313, 0, 1471, 1472, 3, 192, 96, 0, 1472, 187, + 1, 0, 0, 0, 1473, 1474, 3, 610, 305, 0, 1474, 1475, 3, 190, 95, 0, 1475, + 1476, 3, 612, 306, 0, 1476, 1477, 3, 626, 313, 0, 1477, 1478, 3, 192, 96, + 0, 1478, 189, 1, 0, 0, 0, 1479, 1485, 3, 194, 97, 0, 1480, 1481, 3, 626, + 313, 0, 1481, 1482, 3, 194, 97, 0, 1482, 1484, 1, 0, 0, 0, 1483, 1480, + 1, 0, 0, 0, 1484, 1487, 1, 0, 0, 0, 1485, 1483, 1, 0, 0, 0, 1485, 1486, + 1, 0, 0, 0, 1486, 191, 1, 0, 0, 0, 1487, 1485, 1, 0, 0, 0, 1488, 1494, + 3, 196, 98, 0, 1489, 1490, 3, 626, 313, 0, 1490, 1491, 3, 196, 98, 0, 1491, + 1493, 1, 0, 0, 0, 1492, 1489, 1, 0, 0, 0, 1493, 1496, 1, 0, 0, 0, 1494, + 1492, 1, 0, 0, 0, 1494, 1495, 1, 0, 0, 0, 1495, 193, 1, 0, 0, 0, 1496, + 1494, 1, 0, 0, 0, 1497, 1498, 3, 378, 189, 0, 1498, 195, 1, 0, 0, 0, 1499, + 1500, 3, 378, 189, 0, 1500, 197, 1, 0, 0, 0, 1501, 1502, 3, 428, 214, 0, + 1502, 1503, 3, 436, 218, 0, 1503, 199, 1, 0, 0, 0, 1504, 1506, 3, 440, + 220, 0, 1505, 1507, 3, 202, 101, 0, 1506, 1505, 1, 0, 0, 0, 1506, 1507, + 1, 0, 0, 0, 1507, 1508, 1, 0, 0, 0, 1508, 1510, 3, 436, 218, 0, 1509, 1511, + 3, 274, 137, 0, 1510, 1509, 1, 0, 0, 0, 1510, 1511, 1, 0, 0, 0, 1511, 201, + 1, 0, 0, 0, 1512, 1515, 3, 518, 259, 0, 1513, 1515, 3, 588, 294, 0, 1514, + 1512, 1, 0, 0, 0, 1514, 1513, 1, 0, 0, 0, 1515, 203, 1, 0, 0, 0, 1516, + 1517, 3, 424, 212, 0, 1517, 1518, 3, 508, 254, 0, 1518, 1519, 3, 374, 187, + 0, 1519, 1520, 3, 604, 302, 0, 1520, 1521, 3, 552, 276, 0, 1521, 1522, + 5, 19, 0, 0, 1522, 1523, 3, 614, 307, 0, 1523, 1524, 3, 206, 103, 0, 1524, + 1528, 3, 616, 308, 0, 1525, 1526, 3, 426, 213, 0, 1526, 1527, 3, 210, 105, + 0, 1527, 1529, 1, 0, 0, 0, 1528, 1525, 1, 0, 0, 0, 1528, 1529, 1, 0, 0, + 0, 1529, 205, 1, 0, 0, 0, 1530, 1536, 3, 208, 104, 0, 1531, 1532, 3, 626, + 313, 0, 1532, 1533, 3, 208, 104, 0, 1533, 1535, 1, 0, 0, 0, 1534, 1531, + 1, 0, 0, 0, 1535, 1538, 1, 0, 0, 0, 1536, 1534, 1, 0, 0, 0, 1536, 1537, + 1, 0, 0, 0, 1537, 207, 1, 0, 0, 0, 1538, 1536, 1, 0, 0, 0, 1539, 1540, + 5, 169, 0, 0, 1540, 1541, 5, 9, 0, 0, 1541, 1546, 5, 169, 0, 0, 1542, 1543, + 5, 169, 0, 0, 1543, 1544, 5, 9, 0, 0, 1544, 1546, 5, 170, 0, 0, 1545, 1539, + 1, 0, 0, 0, 1545, 1542, 1, 0, 0, 0, 1546, 209, 1, 0, 0, 0, 1547, 1548, + 3, 464, 232, 0, 1548, 1549, 5, 19, 0, 0, 1549, 1550, 3, 370, 185, 0, 1550, + 211, 1, 0, 0, 0, 1551, 1552, 3, 592, 296, 0, 1552, 1553, 3, 374, 187, 0, + 1553, 213, 1, 0, 0, 0, 1554, 1556, 3, 582, 291, 0, 1555, 1557, 3, 572, + 286, 0, 1556, 1555, 1, 0, 0, 0, 1556, 1557, 1, 0, 0, 0, 1557, 1558, 1, + 0, 0, 0, 1558, 1559, 3, 298, 149, 0, 1559, 215, 1, 0, 0, 0, 1560, 1561, + 3, 452, 226, 0, 1561, 1563, 3, 490, 245, 0, 1562, 1564, 3, 276, 138, 0, + 1563, 1562, 1, 0, 0, 0, 1563, 1564, 1, 0, 0, 0, 1564, 1566, 1, 0, 0, 0, + 1565, 1567, 3, 218, 109, 0, 1566, 1565, 1, 0, 0, 0, 1566, 1567, 1, 0, 0, + 0, 1567, 1568, 1, 0, 0, 0, 1568, 1569, 3, 536, 268, 0, 1569, 1570, 3, 298, + 149, 0, 1570, 1571, 3, 610, 305, 0, 1571, 1572, 3, 220, 110, 0, 1572, 1573, + 3, 612, 306, 0, 1573, 217, 1, 0, 0, 0, 1574, 1577, 5, 174, 0, 0, 1575, + 1577, 3, 368, 184, 0, 1576, 1574, 1, 0, 0, 0, 1576, 1575, 1, 0, 0, 0, 1577, + 219, 1, 0, 0, 0, 1578, 1583, 3, 378, 189, 0, 1579, 1583, 3, 222, 111, 0, + 1580, 1583, 3, 224, 112, 0, 1581, 1583, 3, 226, 113, 0, 1582, 1578, 1, + 0, 0, 0, 1582, 1579, 1, 0, 0, 0, 1582, 1580, 1, 0, 0, 0, 1582, 1581, 1, + 0, 0, 0, 1583, 221, 1, 0, 0, 0, 1584, 1585, 3, 506, 253, 0, 1585, 1586, + 3, 610, 305, 0, 1586, 1587, 5, 174, 0, 0, 1587, 1588, 3, 612, 306, 0, 1588, + 223, 1, 0, 0, 0, 1589, 1590, 3, 466, 233, 0, 1590, 1591, 3, 610, 305, 0, + 1591, 1592, 5, 174, 0, 0, 1592, 1593, 3, 612, 306, 0, 1593, 225, 1, 0, + 0, 0, 1594, 1595, 3, 478, 239, 0, 1595, 1596, 3, 610, 305, 0, 1596, 1597, + 5, 174, 0, 0, 1597, 1598, 3, 612, 306, 0, 1598, 227, 1, 0, 0, 0, 1599, + 1601, 3, 200, 100, 0, 1600, 1599, 1, 0, 0, 0, 1600, 1601, 1, 0, 0, 0, 1601, + 1602, 1, 0, 0, 0, 1602, 1604, 3, 454, 227, 0, 1603, 1605, 3, 230, 115, + 0, 1604, 1603, 1, 0, 0, 0, 1604, 1605, 1, 0, 0, 0, 1605, 1606, 1, 0, 0, + 0, 1606, 1608, 3, 300, 150, 0, 1607, 1609, 3, 274, 137, 0, 1608, 1607, + 1, 0, 0, 0, 1608, 1609, 1, 0, 0, 0, 1609, 1610, 1, 0, 0, 0, 1610, 1613, + 3, 306, 153, 0, 1611, 1614, 3, 278, 139, 0, 1612, 1614, 3, 236, 118, 0, + 1613, 1611, 1, 0, 0, 0, 1613, 1612, 1, 0, 0, 0, 1613, 1614, 1, 0, 0, 0, + 1614, 1616, 1, 0, 0, 0, 1615, 1617, 3, 4, 2, 0, 1616, 1615, 1, 0, 0, 0, + 1616, 1617, 1, 0, 0, 0, 1617, 229, 1, 0, 0, 0, 1618, 1624, 3, 232, 116, + 0, 1619, 1620, 3, 626, 313, 0, 1620, 1621, 3, 232, 116, 0, 1621, 1623, + 1, 0, 0, 0, 1622, 1619, 1, 0, 0, 0, 1623, 1626, 1, 0, 0, 0, 1624, 1622, + 1, 0, 0, 0, 1624, 1625, 1, 0, 0, 0, 1625, 231, 1, 0, 0, 0, 1626, 1624, + 1, 0, 0, 0, 1627, 1629, 3, 314, 157, 0, 1628, 1630, 3, 320, 160, 0, 1629, + 1628, 1, 0, 0, 0, 1629, 1630, 1, 0, 0, 0, 1630, 1636, 1, 0, 0, 0, 1631, + 1633, 3, 318, 159, 0, 1632, 1634, 3, 320, 160, 0, 1633, 1632, 1, 0, 0, + 0, 1633, 1634, 1, 0, 0, 0, 1634, 1636, 1, 0, 0, 0, 1635, 1627, 1, 0, 0, + 0, 1635, 1631, 1, 0, 0, 0, 1636, 233, 1, 0, 0, 0, 1637, 1639, 3, 200, 100, + 0, 1638, 1637, 1, 0, 0, 0, 1638, 1639, 1, 0, 0, 0, 1639, 1640, 1, 0, 0, + 0, 1640, 1641, 3, 590, 295, 0, 1641, 1643, 3, 298, 149, 0, 1642, 1644, + 3, 268, 134, 0, 1643, 1642, 1, 0, 0, 0, 1643, 1644, 1, 0, 0, 0, 1644, 1645, + 1, 0, 0, 0, 1645, 1646, 3, 562, 281, 0, 1646, 1647, 3, 242, 121, 0, 1647, + 1650, 3, 306, 153, 0, 1648, 1651, 3, 278, 139, 0, 1649, 1651, 3, 236, 118, + 0, 1650, 1648, 1, 0, 0, 0, 1650, 1649, 1, 0, 0, 0, 1650, 1651, 1, 0, 0, + 0, 1651, 1653, 1, 0, 0, 0, 1652, 1654, 3, 4, 2, 0, 1653, 1652, 1, 0, 0, + 0, 1653, 1654, 1, 0, 0, 0, 1654, 235, 1, 0, 0, 0, 1655, 1656, 3, 486, 243, + 0, 1656, 1657, 3, 238, 119, 0, 1657, 237, 1, 0, 0, 0, 1658, 1664, 3, 240, + 120, 0, 1659, 1660, 3, 426, 213, 0, 1660, 1661, 3, 240, 120, 0, 1661, 1663, + 1, 0, 0, 0, 1662, 1659, 1, 0, 0, 0, 1663, 1666, 1, 0, 0, 0, 1664, 1662, + 1, 0, 0, 0, 1664, 1665, 1, 0, 0, 0, 1665, 239, 1, 0, 0, 0, 1666, 1664, + 1, 0, 0, 0, 1667, 1668, 5, 174, 0, 0, 1668, 1669, 5, 19, 0, 0, 1669, 1670, + 3, 362, 181, 0, 1670, 241, 1, 0, 0, 0, 1671, 1677, 3, 244, 122, 0, 1672, + 1673, 3, 626, 313, 0, 1673, 1674, 3, 244, 122, 0, 1674, 1676, 1, 0, 0, + 0, 1675, 1672, 1, 0, 0, 0, 1676, 1679, 1, 0, 0, 0, 1677, 1675, 1, 0, 0, + 0, 1677, 1678, 1, 0, 0, 0, 1678, 243, 1, 0, 0, 0, 1679, 1677, 1, 0, 0, + 0, 1680, 1685, 3, 250, 125, 0, 1681, 1685, 3, 248, 124, 0, 1682, 1685, + 3, 246, 123, 0, 1683, 1685, 3, 254, 127, 0, 1684, 1680, 1, 0, 0, 0, 1684, + 1681, 1, 0, 0, 0, 1684, 1682, 1, 0, 0, 0, 1684, 1683, 1, 0, 0, 0, 1685, + 245, 1, 0, 0, 0, 1686, 1687, 3, 378, 189, 0, 1687, 1688, 5, 19, 0, 0, 1688, + 1689, 3, 360, 180, 0, 1689, 247, 1, 0, 0, 0, 1690, 1691, 3, 378, 189, 0, + 1691, 1692, 5, 19, 0, 0, 1692, 1693, 3, 360, 180, 0, 1693, 1694, 3, 262, + 131, 0, 1694, 1695, 5, 174, 0, 0, 1695, 249, 1, 0, 0, 0, 1696, 1697, 3, + 378, 189, 0, 1697, 1698, 5, 19, 0, 0, 1698, 1699, 5, 174, 0, 0, 1699, 1700, + 3, 262, 131, 0, 1700, 1701, 3, 360, 180, 0, 1701, 251, 1, 0, 0, 0, 1702, + 1703, 3, 622, 311, 0, 1703, 1704, 3, 362, 181, 0, 1704, 1705, 3, 624, 312, + 0, 1705, 253, 1, 0, 0, 0, 1706, 1707, 3, 378, 189, 0, 1707, 1708, 3, 252, + 126, 0, 1708, 1709, 5, 19, 0, 0, 1709, 1710, 3, 362, 181, 0, 1710, 255, + 1, 0, 0, 0, 1711, 1721, 3, 614, 307, 0, 1712, 1718, 3, 362, 181, 0, 1713, + 1714, 3, 626, 313, 0, 1714, 1715, 3, 362, 181, 0, 1715, 1717, 1, 0, 0, + 0, 1716, 1713, 1, 0, 0, 0, 1717, 1720, 1, 0, 0, 0, 1718, 1716, 1, 0, 0, + 0, 1718, 1719, 1, 0, 0, 0, 1719, 1722, 1, 0, 0, 0, 1720, 1718, 1, 0, 0, + 0, 1721, 1712, 1, 0, 0, 0, 1721, 1722, 1, 0, 0, 0, 1722, 1723, 1, 0, 0, + 0, 1723, 1724, 3, 616, 308, 0, 1724, 257, 1, 0, 0, 0, 1725, 1726, 3, 614, + 307, 0, 1726, 1727, 3, 362, 181, 0, 1727, 1728, 3, 628, 314, 0, 1728, 1729, + 3, 362, 181, 0, 1729, 1737, 1, 0, 0, 0, 1730, 1731, 3, 626, 313, 0, 1731, + 1732, 3, 362, 181, 0, 1732, 1733, 3, 628, 314, 0, 1733, 1734, 3, 362, 181, + 0, 1734, 1736, 1, 0, 0, 0, 1735, 1730, 1, 0, 0, 0, 1736, 1739, 1, 0, 0, + 0, 1737, 1735, 1, 0, 0, 0, 1737, 1738, 1, 0, 0, 0, 1738, 1740, 1, 0, 0, + 0, 1739, 1737, 1, 0, 0, 0, 1740, 1741, 3, 616, 308, 0, 1741, 259, 1, 0, + 0, 0, 1742, 1752, 3, 622, 311, 0, 1743, 1749, 3, 362, 181, 0, 1744, 1745, + 3, 626, 313, 0, 1745, 1746, 3, 362, 181, 0, 1746, 1748, 1, 0, 0, 0, 1747, + 1744, 1, 0, 0, 0, 1748, 1751, 1, 0, 0, 0, 1749, 1747, 1, 0, 0, 0, 1749, + 1750, 1, 0, 0, 0, 1750, 1753, 1, 0, 0, 0, 1751, 1749, 1, 0, 0, 0, 1752, + 1743, 1, 0, 0, 0, 1752, 1753, 1, 0, 0, 0, 1753, 1754, 1, 0, 0, 0, 1754, + 1755, 3, 624, 312, 0, 1755, 261, 1, 0, 0, 0, 1756, 1757, 7, 1, 0, 0, 1757, + 263, 1, 0, 0, 0, 1758, 1759, 3, 610, 305, 0, 1759, 1765, 3, 288, 144, 0, + 1760, 1761, 3, 626, 313, 0, 1761, 1762, 3, 288, 144, 0, 1762, 1764, 1, + 0, 0, 0, 1763, 1760, 1, 0, 0, 0, 1764, 1767, 1, 0, 0, 0, 1765, 1763, 1, + 0, 0, 0, 1765, 1766, 1, 0, 0, 0, 1766, 1768, 1, 0, 0, 0, 1767, 1765, 1, + 0, 0, 0, 1768, 1769, 3, 612, 306, 0, 1769, 265, 1, 0, 0, 0, 1770, 1772, + 3, 200, 100, 0, 1771, 1770, 1, 0, 0, 0, 1771, 1772, 1, 0, 0, 0, 1772, 1773, + 1, 0, 0, 0, 1773, 1774, 3, 496, 248, 0, 1774, 1775, 3, 498, 249, 0, 1775, + 1777, 3, 298, 149, 0, 1776, 1778, 3, 282, 141, 0, 1777, 1776, 1, 0, 0, + 0, 1777, 1778, 1, 0, 0, 0, 1778, 1779, 1, 0, 0, 0, 1779, 1781, 3, 280, + 140, 0, 1780, 1782, 3, 276, 138, 0, 1781, 1780, 1, 0, 0, 0, 1781, 1782, + 1, 0, 0, 0, 1782, 1784, 1, 0, 0, 0, 1783, 1785, 3, 268, 134, 0, 1784, 1783, + 1, 0, 0, 0, 1784, 1785, 1, 0, 0, 0, 1785, 1787, 1, 0, 0, 0, 1786, 1788, + 3, 4, 2, 0, 1787, 1786, 1, 0, 0, 0, 1787, 1788, 1, 0, 0, 0, 1788, 267, + 1, 0, 0, 0, 1789, 1790, 3, 596, 298, 0, 1790, 1791, 3, 272, 136, 0, 1791, + 1806, 1, 0, 0, 0, 1792, 1793, 3, 596, 298, 0, 1793, 1794, 3, 272, 136, + 0, 1794, 1795, 3, 426, 213, 0, 1795, 1796, 3, 270, 135, 0, 1796, 1806, + 1, 0, 0, 0, 1797, 1798, 3, 596, 298, 0, 1798, 1799, 3, 270, 135, 0, 1799, + 1806, 1, 0, 0, 0, 1800, 1801, 3, 596, 298, 0, 1801, 1802, 3, 270, 135, + 0, 1802, 1803, 3, 426, 213, 0, 1803, 1804, 3, 272, 136, 0, 1804, 1806, + 1, 0, 0, 0, 1805, 1789, 1, 0, 0, 0, 1805, 1792, 1, 0, 0, 0, 1805, 1797, + 1, 0, 0, 0, 1805, 1800, 1, 0, 0, 0, 1806, 269, 1, 0, 0, 0, 1807, 1810, + 3, 576, 288, 0, 1808, 1811, 3, 342, 171, 0, 1809, 1811, 3, 364, 182, 0, + 1810, 1808, 1, 0, 0, 0, 1810, 1809, 1, 0, 0, 0, 1811, 271, 1, 0, 0, 0, + 1812, 1813, 3, 584, 292, 0, 1813, 1814, 3, 364, 182, 0, 1814, 273, 1, 0, + 0, 0, 1815, 1816, 3, 596, 298, 0, 1816, 1817, 3, 270, 135, 0, 1817, 275, + 1, 0, 0, 0, 1818, 1819, 3, 486, 243, 0, 1819, 1820, 3, 530, 265, 0, 1820, + 1821, 3, 470, 235, 0, 1821, 277, 1, 0, 0, 0, 1822, 1823, 3, 486, 243, 0, + 1823, 1824, 3, 470, 235, 0, 1824, 279, 1, 0, 0, 0, 1825, 1826, 3, 598, + 299, 0, 1826, 1827, 5, 1, 0, 0, 1827, 1828, 3, 286, 143, 0, 1828, 1829, + 5, 2, 0, 0, 1829, 1834, 1, 0, 0, 0, 1830, 1831, 3, 502, 251, 0, 1831, 1832, + 3, 362, 181, 0, 1832, 1834, 1, 0, 0, 0, 1833, 1825, 1, 0, 0, 0, 1833, 1830, + 1, 0, 0, 0, 1834, 281, 1, 0, 0, 0, 1835, 1836, 5, 1, 0, 0, 1836, 1837, + 3, 284, 142, 0, 1837, 1838, 5, 2, 0, 0, 1838, 283, 1, 0, 0, 0, 1839, 1845, + 3, 378, 189, 0, 1840, 1841, 3, 626, 313, 0, 1841, 1842, 3, 378, 189, 0, + 1842, 1844, 1, 0, 0, 0, 1843, 1840, 1, 0, 0, 0, 1844, 1847, 1, 0, 0, 0, + 1845, 1843, 1, 0, 0, 0, 1845, 1846, 1, 0, 0, 0, 1846, 285, 1, 0, 0, 0, + 1847, 1845, 1, 0, 0, 0, 1848, 1854, 3, 360, 180, 0, 1849, 1850, 3, 626, + 313, 0, 1850, 1851, 3, 360, 180, 0, 1851, 1853, 1, 0, 0, 0, 1852, 1849, + 1, 0, 0, 0, 1853, 1856, 1, 0, 0, 0, 1854, 1852, 1, 0, 0, 0, 1854, 1855, + 1, 0, 0, 0, 1855, 287, 1, 0, 0, 0, 1856, 1854, 1, 0, 0, 0, 1857, 1864, + 3, 362, 181, 0, 1858, 1864, 3, 352, 176, 0, 1859, 1864, 3, 258, 129, 0, + 1860, 1864, 3, 256, 128, 0, 1861, 1864, 3, 260, 130, 0, 1862, 1864, 3, + 264, 132, 0, 1863, 1857, 1, 0, 0, 0, 1863, 1858, 1, 0, 0, 0, 1863, 1859, + 1, 0, 0, 0, 1863, 1860, 1, 0, 0, 0, 1863, 1861, 1, 0, 0, 0, 1863, 1862, + 1, 0, 0, 0, 1864, 289, 1, 0, 0, 0, 1865, 1867, 3, 560, 280, 0, 1866, 1868, + 3, 308, 154, 0, 1867, 1866, 1, 0, 0, 0, 1867, 1868, 1, 0, 0, 0, 1868, 1870, + 1, 0, 0, 0, 1869, 1871, 3, 502, 251, 0, 1870, 1869, 1, 0, 0, 0, 1870, 1871, + 1, 0, 0, 0, 1871, 1872, 1, 0, 0, 0, 1872, 1873, 3, 310, 155, 0, 1873, 1875, + 3, 300, 150, 0, 1874, 1876, 3, 306, 153, 0, 1875, 1874, 1, 0, 0, 0, 1875, + 1876, 1, 0, 0, 0, 1876, 1878, 1, 0, 0, 0, 1877, 1879, 3, 630, 315, 0, 1878, + 1877, 1, 0, 0, 0, 1878, 1879, 1, 0, 0, 0, 1879, 1881, 1, 0, 0, 0, 1880, + 1882, 3, 302, 151, 0, 1881, 1880, 1, 0, 0, 0, 1881, 1882, 1, 0, 0, 0, 1882, + 1884, 1, 0, 0, 0, 1883, 1885, 3, 294, 147, 0, 1884, 1883, 1, 0, 0, 0, 1884, + 1885, 1, 0, 0, 0, 1885, 1887, 1, 0, 0, 0, 1886, 1888, 3, 292, 146, 0, 1887, + 1886, 1, 0, 0, 0, 1887, 1888, 1, 0, 0, 0, 1888, 1890, 1, 0, 0, 0, 1889, + 1891, 3, 4, 2, 0, 1890, 1889, 1, 0, 0, 0, 1890, 1891, 1, 0, 0, 0, 1891, + 291, 1, 0, 0, 0, 1892, 1893, 3, 422, 211, 0, 1893, 1894, 3, 472, 236, 0, + 1894, 293, 1, 0, 0, 0, 1895, 1898, 3, 514, 257, 0, 1896, 1899, 3, 342, + 171, 0, 1897, 1899, 3, 364, 182, 0, 1898, 1896, 1, 0, 0, 0, 1898, 1897, + 1, 0, 0, 0, 1899, 295, 1, 0, 0, 0, 1900, 1901, 5, 83, 0, 0, 1901, 297, + 1, 0, 0, 0, 1902, 1903, 3, 374, 187, 0, 1903, 1904, 5, 10, 0, 0, 1904, + 1906, 1, 0, 0, 0, 1905, 1902, 1, 0, 0, 0, 1905, 1906, 1, 0, 0, 0, 1906, + 1907, 1, 0, 0, 0, 1907, 1908, 3, 376, 188, 0, 1908, 299, 1, 0, 0, 0, 1909, + 1910, 3, 476, 238, 0, 1910, 1911, 3, 298, 149, 0, 1911, 301, 1, 0, 0, 0, + 1912, 1913, 3, 542, 271, 0, 1913, 1914, 3, 442, 221, 0, 1914, 1920, 3, + 304, 152, 0, 1915, 1916, 3, 626, 313, 0, 1916, 1917, 3, 304, 152, 0, 1917, + 1919, 1, 0, 0, 0, 1918, 1915, 1, 0, 0, 0, 1919, 1922, 1, 0, 0, 0, 1920, + 1918, 1, 0, 0, 0, 1920, 1921, 1, 0, 0, 0, 1921, 303, 1, 0, 0, 0, 1922, + 1920, 1, 0, 0, 0, 1923, 1926, 5, 174, 0, 0, 1924, 1927, 3, 432, 216, 0, + 1925, 1927, 3, 456, 228, 0, 1926, 1924, 1, 0, 0, 0, 1926, 1925, 1, 0, 0, + 0, 1926, 1927, 1, 0, 0, 0, 1927, 305, 1, 0, 0, 0, 1928, 1929, 3, 602, 301, + 0, 1929, 1930, 3, 322, 161, 0, 1930, 307, 1, 0, 0, 0, 1931, 1932, 3, 460, + 230, 0, 1932, 309, 1, 0, 0, 0, 1933, 1936, 5, 11, 0, 0, 1934, 1936, 3, + 312, 156, 0, 1935, 1933, 1, 0, 0, 0, 1935, 1934, 1, 0, 0, 0, 1936, 1942, + 1, 0, 0, 0, 1937, 1938, 3, 626, 313, 0, 1938, 1939, 3, 312, 156, 0, 1939, + 1941, 1, 0, 0, 0, 1940, 1937, 1, 0, 0, 0, 1941, 1944, 1, 0, 0, 0, 1942, + 1940, 1, 0, 0, 0, 1942, 1943, 1, 0, 0, 0, 1943, 311, 1, 0, 0, 0, 1944, + 1942, 1, 0, 0, 0, 1945, 1947, 3, 314, 157, 0, 1946, 1948, 3, 320, 160, + 0, 1947, 1946, 1, 0, 0, 0, 1947, 1948, 1, 0, 0, 0, 1948, 1958, 1, 0, 0, + 0, 1949, 1951, 3, 316, 158, 0, 1950, 1952, 3, 320, 160, 0, 1951, 1950, + 1, 0, 0, 0, 1951, 1952, 1, 0, 0, 0, 1952, 1958, 1, 0, 0, 0, 1953, 1955, + 3, 318, 159, 0, 1954, 1956, 3, 320, 160, 0, 1955, 1954, 1, 0, 0, 0, 1955, + 1956, 1, 0, 0, 0, 1956, 1958, 1, 0, 0, 0, 1957, 1945, 1, 0, 0, 0, 1957, + 1949, 1, 0, 0, 0, 1957, 1953, 1, 0, 0, 0, 1958, 313, 1, 0, 0, 0, 1959, + 1960, 3, 378, 189, 0, 1960, 315, 1, 0, 0, 0, 1961, 1962, 3, 352, 176, 0, + 1962, 317, 1, 0, 0, 0, 1963, 1964, 3, 378, 189, 0, 1964, 1965, 3, 622, + 311, 0, 1965, 1966, 3, 362, 181, 0, 1966, 1967, 3, 624, 312, 0, 1967, 319, + 1, 0, 0, 0, 1968, 1969, 3, 430, 215, 0, 1969, 1970, 5, 174, 0, 0, 1970, + 321, 1, 0, 0, 0, 1971, 1977, 3, 324, 162, 0, 1972, 1973, 3, 426, 213, 0, + 1973, 1974, 3, 324, 162, 0, 1974, 1976, 1, 0, 0, 0, 1975, 1972, 1, 0, 0, + 0, 1976, 1979, 1, 0, 0, 0, 1977, 1975, 1, 0, 0, 0, 1977, 1978, 1, 0, 0, + 0, 1978, 323, 1, 0, 0, 0, 1979, 1977, 1, 0, 0, 0, 1980, 2050, 3, 338, 169, + 0, 1981, 2050, 3, 340, 170, 0, 1982, 2050, 3, 336, 168, 0, 1983, 2050, + 3, 328, 164, 0, 1984, 2050, 3, 330, 165, 0, 1985, 2050, 3, 332, 166, 0, + 1986, 2050, 3, 334, 167, 0, 1987, 2050, 3, 350, 175, 0, 1988, 2050, 3, + 348, 174, 0, 1989, 2050, 3, 346, 173, 0, 1990, 1991, 5, 174, 0, 0, 1991, + 1992, 5, 10, 0, 0, 1992, 1993, 5, 174, 0, 0, 1993, 1994, 3, 296, 148, 0, + 1994, 1995, 3, 362, 181, 0, 1995, 2050, 1, 0, 0, 0, 1996, 1997, 5, 174, + 0, 0, 1997, 1998, 5, 10, 0, 0, 1998, 1999, 5, 174, 0, 0, 1999, 2000, 3, + 438, 219, 0, 2000, 2001, 3, 362, 181, 0, 2001, 2002, 3, 426, 213, 0, 2002, + 2003, 3, 362, 181, 0, 2003, 2050, 1, 0, 0, 0, 2004, 2005, 5, 1, 0, 0, 2005, + 2011, 5, 174, 0, 0, 2006, 2007, 3, 626, 313, 0, 2007, 2008, 5, 174, 0, + 0, 2008, 2010, 1, 0, 0, 0, 2009, 2006, 1, 0, 0, 0, 2010, 2013, 1, 0, 0, + 0, 2011, 2009, 1, 0, 0, 0, 2011, 2012, 1, 0, 0, 0, 2012, 2014, 1, 0, 0, + 0, 2013, 2011, 1, 0, 0, 0, 2014, 2015, 5, 2, 0, 0, 2015, 2016, 3, 488, + 244, 0, 2016, 2017, 5, 1, 0, 0, 2017, 2023, 3, 264, 132, 0, 2018, 2019, + 3, 626, 313, 0, 2019, 2020, 3, 264, 132, 0, 2020, 2022, 1, 0, 0, 0, 2021, + 2018, 1, 0, 0, 0, 2022, 2025, 1, 0, 0, 0, 2023, 2021, 1, 0, 0, 0, 2023, + 2024, 1, 0, 0, 0, 2024, 2026, 1, 0, 0, 0, 2025, 2023, 1, 0, 0, 0, 2026, + 2027, 5, 2, 0, 0, 2027, 2050, 1, 0, 0, 0, 2028, 2029, 5, 1, 0, 0, 2029, + 2035, 5, 174, 0, 0, 2030, 2031, 3, 626, 313, 0, 2031, 2032, 5, 174, 0, + 0, 2032, 2034, 1, 0, 0, 0, 2033, 2030, 1, 0, 0, 0, 2034, 2037, 1, 0, 0, + 0, 2035, 2033, 1, 0, 0, 0, 2035, 2036, 1, 0, 0, 0, 2036, 2038, 1, 0, 0, + 0, 2037, 2035, 1, 0, 0, 0, 2038, 2039, 5, 2, 0, 0, 2039, 2040, 3, 326, + 163, 0, 2040, 2046, 3, 264, 132, 0, 2041, 2042, 3, 626, 313, 0, 2042, 2043, + 3, 264, 132, 0, 2043, 2045, 1, 0, 0, 0, 2044, 2041, 1, 0, 0, 0, 2045, 2048, + 1, 0, 0, 0, 2046, 2044, 1, 0, 0, 0, 2046, 2047, 1, 0, 0, 0, 2047, 2050, + 1, 0, 0, 0, 2048, 2046, 1, 0, 0, 0, 2049, 1980, 1, 0, 0, 0, 2049, 1981, + 1, 0, 0, 0, 2049, 1982, 1, 0, 0, 0, 2049, 1983, 1, 0, 0, 0, 2049, 1984, + 1, 0, 0, 0, 2049, 1985, 1, 0, 0, 0, 2049, 1986, 1, 0, 0, 0, 2049, 1987, + 1, 0, 0, 0, 2049, 1988, 1, 0, 0, 0, 2049, 1989, 1, 0, 0, 0, 2049, 1990, + 1, 0, 0, 0, 2049, 1996, 1, 0, 0, 0, 2049, 2004, 1, 0, 0, 0, 2049, 2028, + 1, 0, 0, 0, 2050, 325, 1, 0, 0, 0, 2051, 2052, 7, 2, 0, 0, 2052, 327, 1, + 0, 0, 0, 2053, 2054, 3, 352, 176, 0, 2054, 2055, 3, 326, 163, 0, 2055, + 2056, 3, 362, 181, 0, 2056, 329, 1, 0, 0, 0, 2057, 2058, 3, 352, 176, 0, + 2058, 2059, 3, 326, 163, 0, 2059, 2060, 3, 352, 176, 0, 2060, 331, 1, 0, + 0, 0, 2061, 2062, 3, 378, 189, 0, 2062, 2063, 3, 326, 163, 0, 2063, 2064, + 3, 352, 176, 0, 2064, 333, 1, 0, 0, 0, 2065, 2066, 3, 352, 176, 0, 2066, + 2067, 3, 326, 163, 0, 2067, 2068, 3, 378, 189, 0, 2068, 335, 1, 0, 0, 0, + 2069, 2070, 3, 378, 189, 0, 2070, 2071, 3, 438, 219, 0, 2071, 2072, 3, + 360, 180, 0, 2072, 2073, 3, 426, 213, 0, 2073, 2074, 3, 360, 180, 0, 2074, + 337, 1, 0, 0, 0, 2075, 2076, 3, 378, 189, 0, 2076, 2077, 3, 326, 163, 0, + 2077, 2078, 3, 362, 181, 0, 2078, 339, 1, 0, 0, 0, 2079, 2080, 3, 378, + 189, 0, 2080, 2081, 3, 296, 148, 0, 2081, 2082, 3, 362, 181, 0, 2082, 341, + 1, 0, 0, 0, 2083, 2084, 7, 3, 0, 0, 2084, 343, 1, 0, 0, 0, 2085, 2091, + 3, 342, 171, 0, 2086, 2087, 5, 1, 0, 0, 2087, 2088, 3, 356, 178, 0, 2088, + 2089, 5, 2, 0, 0, 2089, 2091, 1, 0, 0, 0, 2090, 2085, 1, 0, 0, 0, 2090, + 2086, 1, 0, 0, 0, 2091, 345, 1, 0, 0, 0, 2092, 2093, 3, 378, 189, 0, 2093, + 2094, 3, 488, 244, 0, 2094, 2095, 3, 344, 172, 0, 2095, 347, 1, 0, 0, 0, + 2096, 2097, 3, 378, 189, 0, 2097, 2098, 3, 450, 225, 0, 2098, 2099, 3, + 362, 181, 0, 2099, 349, 1, 0, 0, 0, 2100, 2101, 3, 378, 189, 0, 2101, 2102, + 3, 450, 225, 0, 2102, 2103, 3, 504, 252, 0, 2103, 2104, 1, 0, 0, 0, 2104, + 2105, 3, 362, 181, 0, 2105, 351, 1, 0, 0, 0, 2106, 2107, 3, 354, 177, 0, + 2107, 2109, 5, 1, 0, 0, 2108, 2110, 3, 356, 178, 0, 2109, 2108, 1, 0, 0, + 0, 2109, 2110, 1, 0, 0, 0, 2110, 2111, 1, 0, 0, 0, 2111, 2112, 5, 2, 0, + 0, 2112, 353, 1, 0, 0, 0, 2113, 2114, 7, 4, 0, 0, 2114, 355, 1, 0, 0, 0, + 2115, 2121, 3, 358, 179, 0, 2116, 2117, 3, 626, 313, 0, 2117, 2118, 3, + 358, 179, 0, 2118, 2120, 1, 0, 0, 0, 2119, 2116, 1, 0, 0, 0, 2120, 2123, + 1, 0, 0, 0, 2121, 2119, 1, 0, 0, 0, 2121, 2122, 1, 0, 0, 0, 2122, 357, + 1, 0, 0, 0, 2123, 2121, 1, 0, 0, 0, 2124, 2128, 3, 360, 180, 0, 2125, 2128, + 3, 378, 189, 0, 2126, 2128, 5, 11, 0, 0, 2127, 2124, 1, 0, 0, 0, 2127, + 2125, 1, 0, 0, 0, 2127, 2126, 1, 0, 0, 0, 2128, 359, 1, 0, 0, 0, 2129, + 2137, 3, 342, 171, 0, 2130, 2137, 3, 362, 181, 0, 2131, 2137, 3, 352, 176, + 0, 2132, 2137, 3, 258, 129, 0, 2133, 2137, 3, 256, 128, 0, 2134, 2137, + 3, 260, 130, 0, 2135, 2137, 3, 264, 132, 0, 2136, 2129, 1, 0, 0, 0, 2136, + 2130, 1, 0, 0, 0, 2136, 2131, 1, 0, 0, 0, 2136, 2132, 1, 0, 0, 0, 2136, + 2133, 1, 0, 0, 0, 2136, 2134, 1, 0, 0, 0, 2136, 2135, 1, 0, 0, 0, 2137, + 361, 1, 0, 0, 0, 2138, 2148, 3, 342, 171, 0, 2139, 2148, 3, 532, 266, 0, + 2140, 2148, 5, 175, 0, 0, 2141, 2148, 3, 368, 184, 0, 2142, 2148, 3, 364, + 182, 0, 2143, 2148, 3, 366, 183, 0, 2144, 2148, 3, 372, 186, 0, 2145, 2148, + 3, 370, 185, 0, 2146, 2148, 3, 58, 29, 0, 2147, 2138, 1, 0, 0, 0, 2147, + 2139, 1, 0, 0, 0, 2147, 2140, 1, 0, 0, 0, 2147, 2141, 1, 0, 0, 0, 2147, + 2142, 1, 0, 0, 0, 2147, 2143, 1, 0, 0, 0, 2147, 2144, 1, 0, 0, 0, 2147, + 2145, 1, 0, 0, 0, 2147, 2146, 1, 0, 0, 0, 2148, 363, 1, 0, 0, 0, 2149, + 2150, 5, 170, 0, 0, 2150, 365, 1, 0, 0, 0, 2151, 2152, 7, 5, 0, 0, 2152, + 367, 1, 0, 0, 0, 2153, 2154, 5, 169, 0, 0, 2154, 369, 1, 0, 0, 0, 2155, + 2156, 7, 6, 0, 0, 2156, 371, 1, 0, 0, 0, 2157, 2158, 5, 172, 0, 0, 2158, + 373, 1, 0, 0, 0, 2159, 2164, 5, 174, 0, 0, 2160, 2161, 5, 17, 0, 0, 2161, + 2162, 5, 174, 0, 0, 2162, 2164, 5, 17, 0, 0, 2163, 2159, 1, 0, 0, 0, 2163, + 2160, 1, 0, 0, 0, 2164, 375, 1, 0, 0, 0, 2165, 2173, 5, 174, 0, 0, 2166, + 2173, 5, 79, 0, 0, 2167, 2173, 5, 125, 0, 0, 2168, 2173, 5, 63, 0, 0, 2169, + 2170, 5, 17, 0, 0, 2170, 2171, 5, 174, 0, 0, 2171, 2173, 5, 17, 0, 0, 2172, + 2165, 1, 0, 0, 0, 2172, 2166, 1, 0, 0, 0, 2172, 2167, 1, 0, 0, 0, 2172, + 2168, 1, 0, 0, 0, 2172, 2169, 1, 0, 0, 0, 2173, 377, 1, 0, 0, 0, 2174, + 2181, 5, 174, 0, 0, 2175, 2181, 3, 586, 293, 0, 2176, 2181, 5, 76, 0, 0, + 2177, 2178, 5, 17, 0, 0, 2178, 2179, 5, 174, 0, 0, 2179, 2181, 5, 17, 0, + 0, 2180, 2174, 1, 0, 0, 0, 2180, 2175, 1, 0, 0, 0, 2180, 2176, 1, 0, 0, + 0, 2180, 2177, 1, 0, 0, 0, 2181, 379, 1, 0, 0, 0, 2182, 2184, 3, 382, 191, + 0, 2183, 2185, 3, 384, 192, 0, 2184, 2183, 1, 0, 0, 0, 2184, 2185, 1, 0, + 0, 0, 2185, 381, 1, 0, 0, 0, 2186, 2187, 7, 7, 0, 0, 2187, 383, 1, 0, 0, + 0, 2188, 2189, 3, 618, 309, 0, 2189, 2195, 3, 380, 190, 0, 2190, 2191, + 3, 626, 313, 0, 2191, 2192, 3, 380, 190, 0, 2192, 2194, 1, 0, 0, 0, 2193, + 2190, 1, 0, 0, 0, 2194, 2197, 1, 0, 0, 0, 2195, 2193, 1, 0, 0, 0, 2195, + 2196, 1, 0, 0, 0, 2196, 2198, 1, 0, 0, 0, 2197, 2195, 1, 0, 0, 0, 2198, + 2199, 3, 620, 310, 0, 2199, 385, 1, 0, 0, 0, 2200, 2203, 3, 432, 216, 0, + 2201, 2203, 3, 456, 228, 0, 2202, 2200, 1, 0, 0, 0, 2202, 2201, 1, 0, 0, + 0, 2203, 387, 1, 0, 0, 0, 2204, 2205, 5, 174, 0, 0, 2205, 389, 1, 0, 0, + 0, 2206, 2207, 5, 174, 0, 0, 2207, 391, 1, 0, 0, 0, 2208, 2209, 3, 368, + 184, 0, 2209, 393, 1, 0, 0, 0, 2210, 2211, 5, 174, 0, 0, 2211, 395, 1, + 0, 0, 0, 2212, 2213, 5, 174, 0, 0, 2213, 397, 1, 0, 0, 0, 2214, 2215, 5, + 174, 0, 0, 2215, 399, 1, 0, 0, 0, 2216, 2217, 5, 174, 0, 0, 2217, 401, + 1, 0, 0, 0, 2218, 2219, 5, 174, 0, 0, 2219, 403, 1, 0, 0, 0, 2220, 2221, + 5, 174, 0, 0, 2221, 405, 1, 0, 0, 0, 2222, 2223, 3, 368, 184, 0, 2223, + 407, 1, 0, 0, 0, 2224, 2225, 5, 174, 0, 0, 2225, 409, 1, 0, 0, 0, 2226, + 2227, 3, 412, 206, 0, 2227, 2228, 3, 380, 190, 0, 2228, 411, 1, 0, 0, 0, + 2229, 2230, 7, 8, 0, 0, 2230, 413, 1, 0, 0, 0, 2231, 2232, 5, 24, 0, 0, + 2232, 415, 1, 0, 0, 0, 2233, 2234, 5, 25, 0, 0, 2234, 417, 1, 0, 0, 0, + 2235, 2236, 5, 26, 0, 0, 2236, 419, 1, 0, 0, 0, 2237, 2238, 5, 26, 0, 0, + 2238, 2239, 5, 106, 0, 0, 2239, 421, 1, 0, 0, 0, 2240, 2241, 5, 27, 0, + 0, 2241, 423, 1, 0, 0, 0, 2242, 2243, 5, 28, 0, 0, 2243, 425, 1, 0, 0, + 0, 2244, 2245, 5, 29, 0, 0, 2245, 427, 1, 0, 0, 0, 2246, 2247, 5, 31, 0, + 0, 2247, 429, 1, 0, 0, 0, 2248, 2249, 5, 32, 0, 0, 2249, 431, 1, 0, 0, + 0, 2250, 2251, 5, 33, 0, 0, 2251, 433, 1, 0, 0, 0, 2252, 2253, 5, 34, 0, + 0, 2253, 435, 1, 0, 0, 0, 2254, 2255, 5, 35, 0, 0, 2255, 437, 1, 0, 0, + 0, 2256, 2257, 5, 37, 0, 0, 2257, 439, 1, 0, 0, 0, 2258, 2259, 5, 36, 0, + 0, 2259, 441, 1, 0, 0, 0, 2260, 2261, 5, 38, 0, 0, 2261, 443, 1, 0, 0, + 0, 2262, 2263, 5, 39, 0, 0, 2263, 445, 1, 0, 0, 0, 2264, 2265, 5, 40, 0, + 0, 2265, 447, 1, 0, 0, 0, 2266, 2267, 5, 42, 0, 0, 2267, 449, 1, 0, 0, + 0, 2268, 2269, 5, 44, 0, 0, 2269, 451, 1, 0, 0, 0, 2270, 2271, 5, 45, 0, + 0, 2271, 453, 1, 0, 0, 0, 2272, 2273, 5, 47, 0, 0, 2273, 455, 1, 0, 0, + 0, 2274, 2275, 5, 48, 0, 0, 2275, 457, 1, 0, 0, 0, 2276, 2277, 5, 49, 0, + 0, 2277, 459, 1, 0, 0, 0, 2278, 2279, 5, 50, 0, 0, 2279, 461, 1, 0, 0, + 0, 2280, 2281, 5, 51, 0, 0, 2281, 463, 1, 0, 0, 0, 2282, 2283, 5, 52, 0, + 0, 2283, 465, 1, 0, 0, 0, 2284, 2285, 5, 54, 0, 0, 2285, 467, 1, 0, 0, + 0, 2286, 2287, 5, 55, 0, 0, 2287, 469, 1, 0, 0, 0, 2288, 2289, 5, 56, 0, + 0, 2289, 471, 1, 0, 0, 0, 2290, 2291, 5, 58, 0, 0, 2291, 473, 1, 0, 0, + 0, 2292, 2293, 5, 59, 0, 0, 2293, 475, 1, 0, 0, 0, 2294, 2295, 5, 60, 0, + 0, 2295, 477, 1, 0, 0, 0, 2296, 2297, 5, 61, 0, 0, 2297, 479, 1, 0, 0, + 0, 2298, 2299, 5, 62, 0, 0, 2299, 481, 1, 0, 0, 0, 2300, 2301, 5, 63, 0, + 0, 2301, 483, 1, 0, 0, 0, 2302, 2303, 5, 64, 0, 0, 2303, 485, 1, 0, 0, + 0, 2304, 2305, 5, 66, 0, 0, 2305, 487, 1, 0, 0, 0, 2306, 2307, 5, 67, 0, + 0, 2307, 489, 1, 0, 0, 0, 2308, 2309, 5, 68, 0, 0, 2309, 491, 1, 0, 0, + 0, 2310, 2311, 5, 70, 0, 0, 2311, 493, 1, 0, 0, 0, 2312, 2313, 5, 71, 0, + 0, 2313, 495, 1, 0, 0, 0, 2314, 2315, 5, 72, 0, 0, 2315, 497, 1, 0, 0, + 0, 2316, 2317, 5, 73, 0, 0, 2317, 499, 1, 0, 0, 0, 2318, 2319, 5, 74, 0, + 0, 2319, 501, 1, 0, 0, 0, 2320, 2321, 5, 75, 0, 0, 2321, 503, 1, 0, 0, + 0, 2322, 2323, 5, 76, 0, 0, 2323, 505, 1, 0, 0, 0, 2324, 2325, 5, 77, 0, + 0, 2325, 507, 1, 0, 0, 0, 2326, 2327, 5, 78, 0, 0, 2327, 509, 1, 0, 0, + 0, 2328, 2329, 5, 79, 0, 0, 2329, 511, 1, 0, 0, 0, 2330, 2331, 5, 80, 0, + 0, 2331, 513, 1, 0, 0, 0, 2332, 2333, 5, 82, 0, 0, 2333, 515, 1, 0, 0, + 0, 2334, 2335, 5, 84, 0, 0, 2335, 517, 1, 0, 0, 0, 2336, 2337, 5, 87, 0, + 0, 2337, 519, 1, 0, 0, 0, 2338, 2339, 5, 88, 0, 0, 2339, 521, 1, 0, 0, + 0, 2340, 2341, 5, 89, 0, 0, 2341, 523, 1, 0, 0, 0, 2342, 2343, 5, 90, 0, + 0, 2343, 525, 1, 0, 0, 0, 2344, 2345, 5, 93, 0, 0, 2345, 527, 1, 0, 0, + 0, 2346, 2347, 5, 92, 0, 0, 2347, 529, 1, 0, 0, 0, 2348, 2349, 5, 94, 0, + 0, 2349, 531, 1, 0, 0, 0, 2350, 2351, 5, 95, 0, 0, 2351, 533, 1, 0, 0, + 0, 2352, 2353, 5, 96, 0, 0, 2353, 535, 1, 0, 0, 0, 2354, 2355, 5, 97, 0, + 0, 2355, 537, 1, 0, 0, 0, 2356, 2357, 5, 99, 0, 0, 2357, 539, 1, 0, 0, + 0, 2358, 2359, 5, 100, 0, 0, 2359, 541, 1, 0, 0, 0, 2360, 2361, 5, 101, + 0, 0, 2361, 543, 1, 0, 0, 0, 2362, 2363, 5, 103, 0, 0, 2363, 545, 1, 0, + 0, 0, 2364, 2365, 5, 107, 0, 0, 2365, 547, 1, 0, 0, 0, 2366, 2367, 5, 109, + 0, 0, 2367, 549, 1, 0, 0, 0, 2368, 2369, 5, 110, 0, 0, 2369, 551, 1, 0, + 0, 0, 2370, 2371, 5, 111, 0, 0, 2371, 553, 1, 0, 0, 0, 2372, 2373, 5, 112, + 0, 0, 2373, 555, 1, 0, 0, 0, 2374, 2375, 5, 114, 0, 0, 2375, 557, 1, 0, + 0, 0, 2376, 2377, 5, 115, 0, 0, 2377, 559, 1, 0, 0, 0, 2378, 2379, 5, 117, + 0, 0, 2379, 561, 1, 0, 0, 0, 2380, 2381, 5, 118, 0, 0, 2381, 563, 1, 0, + 0, 0, 2382, 2383, 5, 119, 0, 0, 2383, 565, 1, 0, 0, 0, 2384, 2385, 5, 121, + 0, 0, 2385, 567, 1, 0, 0, 0, 2386, 2387, 5, 122, 0, 0, 2387, 569, 1, 0, + 0, 0, 2388, 2389, 5, 123, 0, 0, 2389, 571, 1, 0, 0, 0, 2390, 2391, 5, 124, + 0, 0, 2391, 573, 1, 0, 0, 0, 2392, 2393, 5, 125, 0, 0, 2393, 575, 1, 0, + 0, 0, 2394, 2395, 5, 127, 0, 0, 2395, 577, 1, 0, 0, 0, 2396, 2397, 5, 128, + 0, 0, 2397, 579, 1, 0, 0, 0, 2398, 2399, 5, 130, 0, 0, 2399, 581, 1, 0, + 0, 0, 2400, 2401, 5, 132, 0, 0, 2401, 583, 1, 0, 0, 0, 2402, 2403, 5, 133, + 0, 0, 2403, 585, 1, 0, 0, 0, 2404, 2405, 5, 135, 0, 0, 2405, 587, 1, 0, + 0, 0, 2406, 2407, 5, 136, 0, 0, 2407, 589, 1, 0, 0, 0, 2408, 2409, 5, 137, + 0, 0, 2409, 591, 1, 0, 0, 0, 2410, 2411, 5, 138, 0, 0, 2411, 593, 1, 0, + 0, 0, 2412, 2413, 5, 139, 0, 0, 2413, 595, 1, 0, 0, 0, 2414, 2415, 5, 140, + 0, 0, 2415, 597, 1, 0, 0, 0, 2416, 2417, 5, 142, 0, 0, 2417, 599, 1, 0, + 0, 0, 2418, 2419, 5, 143, 0, 0, 2419, 601, 1, 0, 0, 0, 2420, 2421, 5, 144, + 0, 0, 2421, 603, 1, 0, 0, 0, 2422, 2423, 5, 145, 0, 0, 2423, 605, 1, 0, + 0, 0, 2424, 2425, 5, 113, 0, 0, 2425, 607, 1, 0, 0, 0, 2426, 2427, 5, 65, + 0, 0, 2427, 609, 1, 0, 0, 0, 2428, 2429, 5, 1, 0, 0, 2429, 611, 1, 0, 0, + 0, 2430, 2431, 5, 2, 0, 0, 2431, 613, 1, 0, 0, 0, 2432, 2433, 5, 3, 0, + 0, 2433, 615, 1, 0, 0, 0, 2434, 2435, 5, 4, 0, 0, 2435, 617, 1, 0, 0, 0, + 2436, 2437, 5, 20, 0, 0, 2437, 619, 1, 0, 0, 0, 2438, 2439, 5, 21, 0, 0, + 2439, 621, 1, 0, 0, 0, 2440, 2441, 5, 5, 0, 0, 2441, 623, 1, 0, 0, 0, 2442, + 2443, 5, 6, 0, 0, 2443, 625, 1, 0, 0, 0, 2444, 2445, 5, 7, 0, 0, 2445, + 627, 1, 0, 0, 0, 2446, 2447, 5, 9, 0, 0, 2447, 629, 1, 0, 0, 0, 2448, 2449, + 3, 608, 304, 0, 2449, 2450, 3, 442, 221, 0, 2450, 2456, 3, 632, 316, 0, + 2451, 2452, 3, 626, 313, 0, 2452, 2453, 3, 632, 316, 0, 2453, 2455, 1, + 0, 0, 0, 2454, 2451, 1, 0, 0, 0, 2455, 2458, 1, 0, 0, 0, 2456, 2454, 1, + 0, 0, 0, 2456, 2457, 1, 0, 0, 0, 2457, 631, 1, 0, 0, 0, 2458, 2456, 1, + 0, 0, 0, 2459, 2460, 5, 174, 0, 0, 2460, 633, 1, 0, 0, 0, 180, 637, 640, + 646, 651, 653, 658, 661, 664, 708, 712, 720, 727, 732, 748, 751, 758, 763, + 774, 784, 799, 810, 819, 824, 832, 837, 841, 846, 851, 866, 872, 877, 887, + 892, 909, 916, 924, 938, 943, 955, 959, 963, 968, 973, 992, 999, 1007, + 1011, 1016, 1035, 1044, 1059, 1061, 1073, 1087, 1094, 1101, 1109, 1120, + 1136, 1155, 1178, 1190, 1206, 1216, 1225, 1244, 1252, 1258, 1263, 1270, + 1275, 1283, 1288, 1295, 1300, 1307, 1312, 1319, 1328, 1335, 1342, 1349, + 1354, 1361, 1368, 1372, 1375, 1383, 1393, 1404, 1410, 1419, 1432, 1440, + 1446, 1451, 1465, 1485, 1494, 1506, 1510, 1514, 1528, 1536, 1545, 1556, + 1563, 1566, 1576, 1582, 1600, 1604, 1608, 1613, 1616, 1624, 1629, 1633, + 1635, 1638, 1643, 1650, 1653, 1664, 1677, 1684, 1718, 1721, 1737, 1749, + 1752, 1765, 1771, 1777, 1781, 1784, 1787, 1805, 1810, 1833, 1845, 1854, + 1863, 1867, 1870, 1875, 1878, 1881, 1884, 1887, 1890, 1898, 1905, 1920, + 1926, 1935, 1942, 1947, 1951, 1955, 1957, 1977, 2011, 2023, 2035, 2046, + 2049, 2090, 2109, 2121, 2127, 2136, 2147, 2163, 2172, 2180, 2184, 2195, + 2202, 2456, } deserializer := antlr.NewATNDeserializer(nil) staticData.atn = deserializer.Deserialize(staticData.serializedATN) @@ -1685,153 +1686,157 @@ const ( CqlParserRULE_compareOperator = 163 CqlParserRULE_relationFunctionCompareConstant = 164 CqlParserRULE_relationFunctionCompareFunction = 165 - CqlParserRULE_relationBetween = 166 - CqlParserRULE_relationCompare = 167 - CqlParserRULE_relationLike = 168 - CqlParserRULE_marker = 169 - CqlParserRULE_tupleValue = 170 - CqlParserRULE_relationIn = 171 - CqlParserRULE_relationContains = 172 - CqlParserRULE_relationContainsKey = 173 - CqlParserRULE_functionCall = 174 - CqlParserRULE_functionArgs = 175 - CqlParserRULE_valueAny = 176 - CqlParserRULE_constant = 177 - CqlParserRULE_decimalLiteral = 178 - CqlParserRULE_floatLiteral = 179 - CqlParserRULE_stringLiteral = 180 - CqlParserRULE_booleanLiteral = 181 - CqlParserRULE_hexadecimalLiteral = 182 - CqlParserRULE_keyspace = 183 - CqlParserRULE_table = 184 - CqlParserRULE_column = 185 - CqlParserRULE_dataType = 186 - CqlParserRULE_dataTypeName = 187 - CqlParserRULE_dataTypeDefinition = 188 - CqlParserRULE_orderDirection = 189 - CqlParserRULE_role = 190 - CqlParserRULE_trigger = 191 - CqlParserRULE_triggerClass = 192 - CqlParserRULE_materializedView = 193 - CqlParserRULE_type_ = 194 - CqlParserRULE_aggregate = 195 - CqlParserRULE_function_ = 196 - CqlParserRULE_language = 197 - CqlParserRULE_user = 198 - CqlParserRULE_password = 199 - CqlParserRULE_hashKey = 200 - CqlParserRULE_param = 201 - CqlParserRULE_paramName = 202 - CqlParserRULE_kwAdd = 203 - CqlParserRULE_kwAggregate = 204 - CqlParserRULE_kwAll = 205 - CqlParserRULE_kwAllPermissions = 206 - CqlParserRULE_kwAllow = 207 - CqlParserRULE_kwAlter = 208 - CqlParserRULE_kwAnd = 209 - CqlParserRULE_kwApply = 210 - CqlParserRULE_kwAs = 211 - CqlParserRULE_kwAsc = 212 - CqlParserRULE_kwAuthorize = 213 - CqlParserRULE_kwBatch = 214 - CqlParserRULE_kwBetween = 215 - CqlParserRULE_kwBegin = 216 - CqlParserRULE_kwBy = 217 - CqlParserRULE_kwCalled = 218 - CqlParserRULE_kwClustering = 219 - CqlParserRULE_kwCompact = 220 - CqlParserRULE_kwContains = 221 - CqlParserRULE_kwCreate = 222 - CqlParserRULE_kwDelete = 223 - CqlParserRULE_kwDesc = 224 - CqlParserRULE_kwDescibe = 225 - CqlParserRULE_kwDistinct = 226 - CqlParserRULE_kwDrop = 227 - CqlParserRULE_kwDurableWrites = 228 - CqlParserRULE_kwEntries = 229 - CqlParserRULE_kwExecute = 230 - CqlParserRULE_kwExists = 231 - CqlParserRULE_kwFiltering = 232 - CqlParserRULE_kwFinalfunc = 233 - CqlParserRULE_kwFrom = 234 - CqlParserRULE_kwFull = 235 - CqlParserRULE_kwFunction = 236 - CqlParserRULE_kwFunctions = 237 - CqlParserRULE_kwGrant = 238 - CqlParserRULE_kwIf = 239 - CqlParserRULE_kwIn = 240 - CqlParserRULE_kwIndex = 241 - CqlParserRULE_kwInitcond = 242 - CqlParserRULE_kwInput = 243 - CqlParserRULE_kwInsert = 244 - CqlParserRULE_kwInto = 245 - CqlParserRULE_kwIs = 246 - CqlParserRULE_kwJson = 247 - CqlParserRULE_kwKey = 248 - CqlParserRULE_kwKeys = 249 - CqlParserRULE_kwKeyspace = 250 - CqlParserRULE_kwKeyspaces = 251 - CqlParserRULE_kwLanguage = 252 - CqlParserRULE_kwLimit = 253 - CqlParserRULE_kwList = 254 - CqlParserRULE_kwLogged = 255 - CqlParserRULE_kwLogin = 256 - CqlParserRULE_kwMaterialized = 257 - CqlParserRULE_kwModify = 258 - CqlParserRULE_kwNosuperuser = 259 - CqlParserRULE_kwNorecursive = 260 - CqlParserRULE_kwNot = 261 - CqlParserRULE_kwNull = 262 - CqlParserRULE_kwOf = 263 - CqlParserRULE_kwOn = 264 - CqlParserRULE_kwOptions = 265 - CqlParserRULE_kwOr = 266 - CqlParserRULE_kwOrder = 267 - CqlParserRULE_kwPassword = 268 - CqlParserRULE_kwPrimary = 269 - CqlParserRULE_kwRename = 270 - CqlParserRULE_kwReplace = 271 - CqlParserRULE_kwReplication = 272 - CqlParserRULE_kwReturns = 273 - CqlParserRULE_kwRole = 274 - CqlParserRULE_kwRoles = 275 - CqlParserRULE_kwSelect = 276 - CqlParserRULE_kwSet = 277 - CqlParserRULE_kwSfunc = 278 - CqlParserRULE_kwStorage = 279 - CqlParserRULE_kwStype = 280 - CqlParserRULE_kwSuperuser = 281 - CqlParserRULE_kwTable = 282 - CqlParserRULE_kwTables = 283 - CqlParserRULE_kwTimestamp = 284 - CqlParserRULE_kwTo = 285 - CqlParserRULE_kwTrigger = 286 - CqlParserRULE_kwTruncate = 287 - CqlParserRULE_kwTtl = 288 - CqlParserRULE_kwType = 289 - CqlParserRULE_kwUnlogged = 290 - CqlParserRULE_kwUpdate = 291 - CqlParserRULE_kwUse = 292 - CqlParserRULE_kwUser = 293 - CqlParserRULE_kwUsing = 294 - CqlParserRULE_kwValues = 295 - CqlParserRULE_kwView = 296 - CqlParserRULE_kwWhere = 297 - CqlParserRULE_kwWith = 298 - CqlParserRULE_kwRevoke = 299 - CqlParserRULE_kwGroup = 300 - CqlParserRULE_syntaxBracketLr = 301 - CqlParserRULE_syntaxBracketRr = 302 - CqlParserRULE_syntaxBracketLc = 303 - CqlParserRULE_syntaxBracketRc = 304 - CqlParserRULE_syntaxBracketLa = 305 - CqlParserRULE_syntaxBracketRa = 306 - CqlParserRULE_syntaxBracketLs = 307 - CqlParserRULE_syntaxBracketRs = 308 - CqlParserRULE_syntaxComma = 309 - CqlParserRULE_syntaxColon = 310 - CqlParserRULE_groupSpec = 311 - CqlParserRULE_groupSpecElement = 312 + CqlParserRULE_relationColumnCompareFunction = 166 + CqlParserRULE_relationFunctionCompareColumn = 167 + CqlParserRULE_relationBetween = 168 + CqlParserRULE_relationCompare = 169 + CqlParserRULE_relationLike = 170 + CqlParserRULE_marker = 171 + CqlParserRULE_tupleValue = 172 + CqlParserRULE_relationIn = 173 + CqlParserRULE_relationContains = 174 + CqlParserRULE_relationContainsKey = 175 + CqlParserRULE_functionCall = 176 + CqlParserRULE_functionName = 177 + CqlParserRULE_functionArgs = 178 + CqlParserRULE_functionArg = 179 + CqlParserRULE_valueAny = 180 + CqlParserRULE_constant = 181 + CqlParserRULE_decimalLiteral = 182 + CqlParserRULE_floatLiteral = 183 + CqlParserRULE_stringLiteral = 184 + CqlParserRULE_booleanLiteral = 185 + CqlParserRULE_hexadecimalLiteral = 186 + CqlParserRULE_keyspace = 187 + CqlParserRULE_table = 188 + CqlParserRULE_column = 189 + CqlParserRULE_dataType = 190 + CqlParserRULE_dataTypeName = 191 + CqlParserRULE_dataTypeDefinition = 192 + CqlParserRULE_orderDirection = 193 + CqlParserRULE_role = 194 + CqlParserRULE_trigger = 195 + CqlParserRULE_triggerClass = 196 + CqlParserRULE_materializedView = 197 + CqlParserRULE_type_ = 198 + CqlParserRULE_aggregate = 199 + CqlParserRULE_function_ = 200 + CqlParserRULE_language = 201 + CqlParserRULE_user = 202 + CqlParserRULE_password = 203 + CqlParserRULE_hashKey = 204 + CqlParserRULE_param = 205 + CqlParserRULE_paramName = 206 + CqlParserRULE_kwAdd = 207 + CqlParserRULE_kwAggregate = 208 + CqlParserRULE_kwAll = 209 + CqlParserRULE_kwAllPermissions = 210 + CqlParserRULE_kwAllow = 211 + CqlParserRULE_kwAlter = 212 + CqlParserRULE_kwAnd = 213 + CqlParserRULE_kwApply = 214 + CqlParserRULE_kwAs = 215 + CqlParserRULE_kwAsc = 216 + CqlParserRULE_kwAuthorize = 217 + CqlParserRULE_kwBatch = 218 + CqlParserRULE_kwBetween = 219 + CqlParserRULE_kwBegin = 220 + CqlParserRULE_kwBy = 221 + CqlParserRULE_kwCalled = 222 + CqlParserRULE_kwClustering = 223 + CqlParserRULE_kwCompact = 224 + CqlParserRULE_kwContains = 225 + CqlParserRULE_kwCreate = 226 + CqlParserRULE_kwDelete = 227 + CqlParserRULE_kwDesc = 228 + CqlParserRULE_kwDescibe = 229 + CqlParserRULE_kwDistinct = 230 + CqlParserRULE_kwDrop = 231 + CqlParserRULE_kwDurableWrites = 232 + CqlParserRULE_kwEntries = 233 + CqlParserRULE_kwExecute = 234 + CqlParserRULE_kwExists = 235 + CqlParserRULE_kwFiltering = 236 + CqlParserRULE_kwFinalfunc = 237 + CqlParserRULE_kwFrom = 238 + CqlParserRULE_kwFull = 239 + CqlParserRULE_kwFunction = 240 + CqlParserRULE_kwFunctions = 241 + CqlParserRULE_kwGrant = 242 + CqlParserRULE_kwIf = 243 + CqlParserRULE_kwIn = 244 + CqlParserRULE_kwIndex = 245 + CqlParserRULE_kwInitcond = 246 + CqlParserRULE_kwInput = 247 + CqlParserRULE_kwInsert = 248 + CqlParserRULE_kwInto = 249 + CqlParserRULE_kwIs = 250 + CqlParserRULE_kwJson = 251 + CqlParserRULE_kwKey = 252 + CqlParserRULE_kwKeys = 253 + CqlParserRULE_kwKeyspace = 254 + CqlParserRULE_kwKeyspaces = 255 + CqlParserRULE_kwLanguage = 256 + CqlParserRULE_kwLimit = 257 + CqlParserRULE_kwList = 258 + CqlParserRULE_kwLogged = 259 + CqlParserRULE_kwLogin = 260 + CqlParserRULE_kwMaterialized = 261 + CqlParserRULE_kwModify = 262 + CqlParserRULE_kwNosuperuser = 263 + CqlParserRULE_kwNorecursive = 264 + CqlParserRULE_kwNot = 265 + CqlParserRULE_kwNull = 266 + CqlParserRULE_kwOf = 267 + CqlParserRULE_kwOn = 268 + CqlParserRULE_kwOptions = 269 + CqlParserRULE_kwOr = 270 + CqlParserRULE_kwOrder = 271 + CqlParserRULE_kwPassword = 272 + CqlParserRULE_kwPrimary = 273 + CqlParserRULE_kwRename = 274 + CqlParserRULE_kwReplace = 275 + CqlParserRULE_kwReplication = 276 + CqlParserRULE_kwReturns = 277 + CqlParserRULE_kwRole = 278 + CqlParserRULE_kwRoles = 279 + CqlParserRULE_kwSelect = 280 + CqlParserRULE_kwSet = 281 + CqlParserRULE_kwSfunc = 282 + CqlParserRULE_kwStorage = 283 + CqlParserRULE_kwStype = 284 + CqlParserRULE_kwSuperuser = 285 + CqlParserRULE_kwTable = 286 + CqlParserRULE_kwTables = 287 + CqlParserRULE_kwTimestamp = 288 + CqlParserRULE_kwTo = 289 + CqlParserRULE_kwTrigger = 290 + CqlParserRULE_kwTruncate = 291 + CqlParserRULE_kwTtl = 292 + CqlParserRULE_kwType = 293 + CqlParserRULE_kwUnlogged = 294 + CqlParserRULE_kwUpdate = 295 + CqlParserRULE_kwUse = 296 + CqlParserRULE_kwUser = 297 + CqlParserRULE_kwUsing = 298 + CqlParserRULE_kwValues = 299 + CqlParserRULE_kwView = 300 + CqlParserRULE_kwWhere = 301 + CqlParserRULE_kwWith = 302 + CqlParserRULE_kwRevoke = 303 + CqlParserRULE_kwGroup = 304 + CqlParserRULE_syntaxBracketLr = 305 + CqlParserRULE_syntaxBracketRr = 306 + CqlParserRULE_syntaxBracketLc = 307 + CqlParserRULE_syntaxBracketRc = 308 + CqlParserRULE_syntaxBracketLa = 309 + CqlParserRULE_syntaxBracketRa = 310 + CqlParserRULE_syntaxBracketLs = 311 + CqlParserRULE_syntaxBracketRs = 312 + CqlParserRULE_syntaxComma = 313 + CqlParserRULE_syntaxColon = 314 + CqlParserRULE_groupSpec = 315 + CqlParserRULE_groupSpecElement = 316 ) // IRootContext is an interface to support dynamic dispatch. @@ -1958,7 +1963,7 @@ func (p *CqlParser) Root() (localctx IRootContext) { var _la int p.EnterOuterAlt(localctx, 1) - p.SetState(627) + p.SetState(635) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -1967,18 +1972,18 @@ func (p *CqlParser) Root() (localctx IRootContext) { for ok := true; ok; ok = ((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&3272217739657472) != 0) || ((int64((_la-64)) & ^0x3f) == 0 && ((int64(1)<<(_la-64))&9570149209211137) != 0) || ((int64((_la-132)) & ^0x3f) == 0 && ((int64(1)<<(_la-132))&97) != 0) { { - p.SetState(626) + p.SetState(634) p.Cqls() } - p.SetState(629) + p.SetState(637) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit } _la = p.GetTokenStream().LA(1) } - p.SetState(632) + p.SetState(640) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -1987,7 +1992,7 @@ func (p *CqlParser) Root() (localctx IRootContext) { if _la == CqlParserMINUSMINUS { { - p.SetState(631) + p.SetState(639) p.Match(CqlParserMINUSMINUS) if p.HasError() { // Recognition error - abort rule @@ -1997,7 +2002,7 @@ func (p *CqlParser) Root() (localctx IRootContext) { } { - p.SetState(634) + p.SetState(642) p.Match(CqlParserEOF) if p.HasError() { // Recognition error - abort rule @@ -2230,7 +2235,7 @@ func (p *CqlParser) Cqls() (localctx ICqlsContext) { var _alt int p.EnterOuterAlt(localctx, 1) - p.SetState(645) + p.SetState(653) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -2241,7 +2246,7 @@ func (p *CqlParser) Cqls() (localctx ICqlsContext) { } for _alt != 2 && _alt != antlr.ATNInvalidAltNumber { if _alt == 1 { - p.SetState(643) + p.SetState(651) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -2250,10 +2255,10 @@ func (p *CqlParser) Cqls() (localctx ICqlsContext) { switch p.GetTokenStream().LA(1) { case CqlParserK_ALTER, CqlParserK_APPLY, CqlParserK_BEGIN, CqlParserK_CREATE, CqlParserK_DELETE, CqlParserK_DESC, CqlParserK_DESCRIBE, CqlParserK_DROP, CqlParserK_GRANT, CqlParserK_INSERT, CqlParserK_LIST, CqlParserK_REVOKE, CqlParserK_SELECT, CqlParserK_TRUNCATE, CqlParserK_UPDATE, CqlParserK_USE: { - p.SetState(636) + p.SetState(644) p.Cql() } - p.SetState(638) + p.SetState(646) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -2262,7 +2267,7 @@ func (p *CqlParser) Cqls() (localctx ICqlsContext) { if _la == CqlParserMINUSMINUS { { - p.SetState(637) + p.SetState(645) p.Match(CqlParserMINUSMINUS) if p.HasError() { // Recognition error - abort rule @@ -2272,13 +2277,13 @@ func (p *CqlParser) Cqls() (localctx ICqlsContext) { } { - p.SetState(640) + p.SetState(648) p.StatementSeparator() } case CqlParserSEMI: { - p.SetState(642) + p.SetState(650) p.Empty_() } @@ -2288,7 +2293,7 @@ func (p *CqlParser) Cqls() (localctx ICqlsContext) { } } - p.SetState(647) + p.SetState(655) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -2298,7 +2303,7 @@ func (p *CqlParser) Cqls() (localctx ICqlsContext) { goto errorExit } } - p.SetState(656) + p.SetState(664) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -2307,14 +2312,14 @@ func (p *CqlParser) Cqls() (localctx ICqlsContext) { switch p.GetTokenStream().LA(1) { case CqlParserK_ALTER, CqlParserK_APPLY, CqlParserK_BEGIN, CqlParserK_CREATE, CqlParserK_DELETE, CqlParserK_DESC, CqlParserK_DESCRIBE, CqlParserK_DROP, CqlParserK_GRANT, CqlParserK_INSERT, CqlParserK_LIST, CqlParserK_REVOKE, CqlParserK_SELECT, CqlParserK_TRUNCATE, CqlParserK_UPDATE, CqlParserK_USE: { - p.SetState(648) + p.SetState(656) p.Cql() } - p.SetState(653) + p.SetState(661) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 6, p.GetParserRuleContext()) == 1 { - p.SetState(650) + p.SetState(658) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -2323,7 +2328,7 @@ func (p *CqlParser) Cqls() (localctx ICqlsContext) { if _la == CqlParserMINUSMINUS { { - p.SetState(649) + p.SetState(657) p.Match(CqlParserMINUSMINUS) if p.HasError() { // Recognition error - abort rule @@ -2333,7 +2338,7 @@ func (p *CqlParser) Cqls() (localctx ICqlsContext) { } { - p.SetState(652) + p.SetState(660) p.StatementSeparator() } @@ -2343,7 +2348,7 @@ func (p *CqlParser) Cqls() (localctx ICqlsContext) { case CqlParserSEMI: { - p.SetState(655) + p.SetState(663) p.Empty_() } @@ -2440,7 +2445,7 @@ func (p *CqlParser) StatementSeparator() (localctx IStatementSeparatorContext) { p.EnterRule(localctx, 4, CqlParserRULE_statementSeparator) p.EnterOuterAlt(localctx, 1) { - p.SetState(658) + p.SetState(666) p.Match(CqlParserSEMI) if p.HasError() { // Recognition error - abort rule @@ -2548,7 +2553,7 @@ func (p *CqlParser) Empty_() (localctx IEmpty_Context) { p.EnterRule(localctx, 6, CqlParserRULE_empty_) p.EnterOuterAlt(localctx, 1) { - p.SetState(660) + p.SetState(668) p.StatementSeparator() } @@ -3279,7 +3284,7 @@ func (s *CqlContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Cql() (localctx ICqlContext) { localctx = NewCqlContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 8, CqlParserRULE_cql) - p.SetState(700) + p.SetState(708) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -3289,266 +3294,266 @@ func (p *CqlParser) Cql() (localctx ICqlContext) { case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(662) + p.SetState(670) p.AlterKeyspace() } case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(663) + p.SetState(671) p.AlterMaterializedView() } case 3: p.EnterOuterAlt(localctx, 3) { - p.SetState(664) + p.SetState(672) p.AlterRole() } case 4: p.EnterOuterAlt(localctx, 4) { - p.SetState(665) + p.SetState(673) p.AlterTable() } case 5: p.EnterOuterAlt(localctx, 5) { - p.SetState(666) + p.SetState(674) p.AlterType() } case 6: p.EnterOuterAlt(localctx, 6) { - p.SetState(667) + p.SetState(675) p.AlterUser() } case 7: p.EnterOuterAlt(localctx, 7) { - p.SetState(668) + p.SetState(676) p.ApplyBatch() } case 8: p.EnterOuterAlt(localctx, 8) { - p.SetState(669) + p.SetState(677) p.CreateAggregate() } case 9: p.EnterOuterAlt(localctx, 9) { - p.SetState(670) + p.SetState(678) p.CreateFunction() } case 10: p.EnterOuterAlt(localctx, 10) { - p.SetState(671) + p.SetState(679) p.CreateIndex() } case 11: p.EnterOuterAlt(localctx, 11) { - p.SetState(672) + p.SetState(680) p.CreateKeyspace() } case 12: p.EnterOuterAlt(localctx, 12) { - p.SetState(673) + p.SetState(681) p.CreateMaterializedView() } case 13: p.EnterOuterAlt(localctx, 13) { - p.SetState(674) + p.SetState(682) p.CreateRole() } case 14: p.EnterOuterAlt(localctx, 14) { - p.SetState(675) + p.SetState(683) p.CreateTable() } case 15: p.EnterOuterAlt(localctx, 15) { - p.SetState(676) + p.SetState(684) p.CreateTrigger() } case 16: p.EnterOuterAlt(localctx, 16) { - p.SetState(677) + p.SetState(685) p.CreateType() } case 17: p.EnterOuterAlt(localctx, 17) { - p.SetState(678) + p.SetState(686) p.CreateUser() } case 18: p.EnterOuterAlt(localctx, 18) { - p.SetState(679) + p.SetState(687) p.Delete_() } case 19: p.EnterOuterAlt(localctx, 19) { - p.SetState(680) + p.SetState(688) p.DropAggregate() } case 20: p.EnterOuterAlt(localctx, 20) { - p.SetState(681) + p.SetState(689) p.DropFunction() } case 21: p.EnterOuterAlt(localctx, 21) { - p.SetState(682) + p.SetState(690) p.DropIndex() } case 22: p.EnterOuterAlt(localctx, 22) { - p.SetState(683) + p.SetState(691) p.DropKeyspace() } case 23: p.EnterOuterAlt(localctx, 23) { - p.SetState(684) + p.SetState(692) p.DropMaterializedView() } case 24: p.EnterOuterAlt(localctx, 24) { - p.SetState(685) + p.SetState(693) p.DropRole() } case 25: p.EnterOuterAlt(localctx, 25) { - p.SetState(686) + p.SetState(694) p.DropTable() } case 26: p.EnterOuterAlt(localctx, 26) { - p.SetState(687) + p.SetState(695) p.DropTrigger() } case 27: p.EnterOuterAlt(localctx, 27) { - p.SetState(688) + p.SetState(696) p.DropType() } case 28: p.EnterOuterAlt(localctx, 28) { - p.SetState(689) + p.SetState(697) p.DropUser() } case 29: p.EnterOuterAlt(localctx, 29) { - p.SetState(690) + p.SetState(698) p.Grant() } case 30: p.EnterOuterAlt(localctx, 30) { - p.SetState(691) + p.SetState(699) p.Insert() } case 31: p.EnterOuterAlt(localctx, 31) { - p.SetState(692) + p.SetState(700) p.ListPermissions() } case 32: p.EnterOuterAlt(localctx, 32) { - p.SetState(693) + p.SetState(701) p.ListRoles() } case 33: p.EnterOuterAlt(localctx, 33) { - p.SetState(694) + p.SetState(702) p.Revoke() } case 34: p.EnterOuterAlt(localctx, 34) { - p.SetState(695) + p.SetState(703) p.Select_() } case 35: p.EnterOuterAlt(localctx, 35) { - p.SetState(696) + p.SetState(704) p.Truncate() } case 36: p.EnterOuterAlt(localctx, 36) { - p.SetState(697) + p.SetState(705) p.Update() } case 37: p.EnterOuterAlt(localctx, 37) { - p.SetState(698) + p.SetState(706) p.Use_() } case 38: p.EnterOuterAlt(localctx, 38) { - p.SetState(699) + p.SetState(707) p.DescribeStatement() } @@ -3689,7 +3694,7 @@ func (p *CqlParser) DescribeStatement() (localctx IDescribeStatementContext) { localctx = NewDescribeStatementContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 10, CqlParserRULE_describeStatement) p.EnterOuterAlt(localctx, 1) - p.SetState(704) + p.SetState(712) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -3698,13 +3703,13 @@ func (p *CqlParser) DescribeStatement() (localctx IDescribeStatementContext) { switch p.GetTokenStream().LA(1) { case CqlParserK_DESC: { - p.SetState(702) + p.SetState(710) p.KwDesc() } case CqlParserK_DESCRIBE: { - p.SetState(703) + p.SetState(711) p.KwDescibe() } @@ -3713,7 +3718,7 @@ func (p *CqlParser) DescribeStatement() (localctx IDescribeStatementContext) { goto errorExit } { - p.SetState(706) + p.SetState(714) p.DescribeTarget() } @@ -3866,7 +3871,7 @@ func (s *DescribeTargetContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) DescribeTarget() (localctx IDescribeTargetContext) { localctx = NewDescribeTargetContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 12, CqlParserRULE_describeTarget) - p.SetState(712) + p.SetState(720) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -3876,28 +3881,28 @@ func (p *CqlParser) DescribeTarget() (localctx IDescribeTargetContext) { case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(708) + p.SetState(716) p.DescribeTargetKeyspaces() } case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(709) + p.SetState(717) p.DescribeTargetTables() } case 3: p.EnterOuterAlt(localctx, 3) { - p.SetState(710) + p.SetState(718) p.DescribeTargetTable() } case 4: p.EnterOuterAlt(localctx, 4) { - p.SetState(711) + p.SetState(719) p.DescribeTargetKeyspace() } @@ -4005,7 +4010,7 @@ func (p *CqlParser) DescribeTargetKeyspaces() (localctx IDescribeTargetKeyspaces p.EnterRule(localctx, 14, CqlParserRULE_describeTargetKeyspaces) p.EnterOuterAlt(localctx, 1) { - p.SetState(714) + p.SetState(722) p.KwKeyspaces() } @@ -4109,7 +4114,7 @@ func (p *CqlParser) DescribeTargetTables() (localctx IDescribeTargetTablesContex p.EnterRule(localctx, 16, CqlParserRULE_describeTargetTables) p.EnterOuterAlt(localctx, 1) { - p.SetState(716) + p.SetState(724) p.KwTables() } @@ -4231,7 +4236,7 @@ func (p *CqlParser) DescribeTargetTable() (localctx IDescribeTargetTableContext) var _la int p.EnterOuterAlt(localctx, 1) - p.SetState(719) + p.SetState(727) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -4240,13 +4245,13 @@ func (p *CqlParser) DescribeTargetTable() (localctx IDescribeTargetTableContext) if _la == CqlParserK_TABLE { { - p.SetState(718) + p.SetState(726) p.KwTable() } } { - p.SetState(721) + p.SetState(729) p.TableSpec() } @@ -4368,7 +4373,7 @@ func (p *CqlParser) DescribeTargetKeyspace() (localctx IDescribeTargetKeyspaceCo var _la int p.EnterOuterAlt(localctx, 1) - p.SetState(724) + p.SetState(732) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -4377,13 +4382,13 @@ func (p *CqlParser) DescribeTargetKeyspace() (localctx IDescribeTargetKeyspaceCo if _la == CqlParserK_KEYSPACE { { - p.SetState(723) + p.SetState(731) p.KwKeyspace() } } { - p.SetState(726) + p.SetState(734) p.Keyspace() } @@ -4572,27 +4577,27 @@ func (p *CqlParser) Revoke() (localctx IRevokeContext) { p.EnterRule(localctx, 22, CqlParserRULE_revoke) p.EnterOuterAlt(localctx, 1) { - p.SetState(728) + p.SetState(736) p.KwRevoke() } { - p.SetState(729) + p.SetState(737) p.Priviledge() } { - p.SetState(730) + p.SetState(738) p.KwOn() } { - p.SetState(731) + p.SetState(739) p.Resource() } { - p.SetState(732) + p.SetState(740) p.KwFrom() } { - p.SetState(733) + p.SetState(741) p.Role() } @@ -4766,14 +4771,14 @@ func (p *CqlParser) ListRoles() (localctx IListRolesContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(735) + p.SetState(743) p.KwList() } { - p.SetState(736) + p.SetState(744) p.KwRoles() } - p.SetState(740) + p.SetState(748) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -4782,16 +4787,16 @@ func (p *CqlParser) ListRoles() (localctx IListRolesContext) { if _la == CqlParserK_OF { { - p.SetState(737) + p.SetState(745) p.KwOf() } { - p.SetState(738) + p.SetState(746) p.Role() } } - p.SetState(743) + p.SetState(751) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -4800,7 +4805,7 @@ func (p *CqlParser) ListRoles() (localctx IListRolesContext) { if _la == CqlParserK_NORECURSIVE { { - p.SetState(742) + p.SetState(750) p.KwNorecursive() } @@ -4993,14 +4998,14 @@ func (p *CqlParser) ListPermissions() (localctx IListPermissionsContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(745) + p.SetState(753) p.KwList() } { - p.SetState(746) + p.SetState(754) p.Priviledge() } - p.SetState(750) + p.SetState(758) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -5009,16 +5014,16 @@ func (p *CqlParser) ListPermissions() (localctx IListPermissionsContext) { if _la == CqlParserK_ON { { - p.SetState(747) + p.SetState(755) p.KwOn() } { - p.SetState(748) + p.SetState(756) p.Resource() } } - p.SetState(755) + p.SetState(763) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -5027,11 +5032,11 @@ func (p *CqlParser) ListPermissions() (localctx IListPermissionsContext) { if _la == CqlParserK_OF { { - p.SetState(752) + p.SetState(760) p.KwOf() } { - p.SetState(753) + p.SetState(761) p.Role() } @@ -5222,27 +5227,27 @@ func (p *CqlParser) Grant() (localctx IGrantContext) { p.EnterRule(localctx, 28, CqlParserRULE_grant) p.EnterOuterAlt(localctx, 1) { - p.SetState(757) + p.SetState(765) p.KwGrant() } { - p.SetState(758) + p.SetState(766) p.Priviledge() } { - p.SetState(759) + p.SetState(767) p.KwOn() } { - p.SetState(760) + p.SetState(768) p.Resource() } { - p.SetState(761) + p.SetState(769) p.KwTo() } { - p.SetState(762) + p.SetState(770) p.Role() } @@ -5497,7 +5502,7 @@ func (s *PriviledgeContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Priviledge() (localctx IPriviledgeContext) { localctx = NewPriviledgeContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 30, CqlParserRULE_priviledge) - p.SetState(776) + p.SetState(784) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -5506,7 +5511,7 @@ func (p *CqlParser) Priviledge() (localctx IPriviledgeContext) { switch p.GetTokenStream().LA(1) { case CqlParserK_ALL: p.EnterOuterAlt(localctx, 1) - p.SetState(766) + p.SetState(774) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -5515,13 +5520,13 @@ func (p *CqlParser) Priviledge() (localctx IPriviledgeContext) { switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 17, p.GetParserRuleContext()) { case 1: { - p.SetState(764) + p.SetState(772) p.KwAll() } case 2: { - p.SetState(765) + p.SetState(773) p.KwAllPermissions() } @@ -5532,56 +5537,56 @@ func (p *CqlParser) Priviledge() (localctx IPriviledgeContext) { case CqlParserK_ALTER: p.EnterOuterAlt(localctx, 2) { - p.SetState(768) + p.SetState(776) p.KwAlter() } case CqlParserK_AUTHORIZE: p.EnterOuterAlt(localctx, 3) { - p.SetState(769) + p.SetState(777) p.KwAuthorize() } case CqlParserK_DESCRIBE: p.EnterOuterAlt(localctx, 4) { - p.SetState(770) + p.SetState(778) p.KwDescibe() } case CqlParserK_EXECUTE: p.EnterOuterAlt(localctx, 5) { - p.SetState(771) + p.SetState(779) p.KwExecute() } case CqlParserK_CREATE: p.EnterOuterAlt(localctx, 6) { - p.SetState(772) + p.SetState(780) p.KwCreate() } case CqlParserK_DROP: p.EnterOuterAlt(localctx, 7) { - p.SetState(773) + p.SetState(781) p.KwDrop() } case CqlParserK_MODIFY: p.EnterOuterAlt(localctx, 8) { - p.SetState(774) + p.SetState(782) p.KwModify() } case CqlParserK_SELECT: p.EnterOuterAlt(localctx, 9) { - p.SetState(775) + p.SetState(783) p.KwSelect() } @@ -5899,7 +5904,7 @@ func (p *CqlParser) Resource() (localctx IResourceContext) { p.EnterRule(localctx, 32, CqlParserRULE_resource) var _la int - p.SetState(811) + p.SetState(819) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -5909,53 +5914,53 @@ func (p *CqlParser) Resource() (localctx IResourceContext) { case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(778) + p.SetState(786) p.KwAll() } { - p.SetState(779) + p.SetState(787) p.KwFunctions() } case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(781) + p.SetState(789) p.KwAll() } { - p.SetState(782) + p.SetState(790) p.KwFunctions() } { - p.SetState(783) + p.SetState(791) p.KwIn() } { - p.SetState(784) + p.SetState(792) p.KwKeyspace() } { - p.SetState(785) + p.SetState(793) p.Keyspace() } case 3: p.EnterOuterAlt(localctx, 3) { - p.SetState(787) + p.SetState(795) p.KwFunction() } - p.SetState(791) + p.SetState(799) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 19, p.GetParserRuleContext()) == 1 { { - p.SetState(788) + p.SetState(796) p.Keyspace() } { - p.SetState(789) + p.SetState(797) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -5967,35 +5972,35 @@ func (p *CqlParser) Resource() (localctx IResourceContext) { goto errorExit } { - p.SetState(793) + p.SetState(801) p.Function_() } case 4: p.EnterOuterAlt(localctx, 4) { - p.SetState(795) + p.SetState(803) p.KwAll() } { - p.SetState(796) + p.SetState(804) p.KwKeyspaces() } case 5: p.EnterOuterAlt(localctx, 5) { - p.SetState(798) + p.SetState(806) p.KwKeyspace() } { - p.SetState(799) + p.SetState(807) p.Keyspace() } case 6: p.EnterOuterAlt(localctx, 6) - p.SetState(802) + p.SetState(810) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -6004,35 +6009,35 @@ func (p *CqlParser) Resource() (localctx IResourceContext) { if _la == CqlParserK_TABLE { { - p.SetState(801) + p.SetState(809) p.KwTable() } } { - p.SetState(804) + p.SetState(812) p.TableSpec() } case 7: p.EnterOuterAlt(localctx, 7) { - p.SetState(805) + p.SetState(813) p.KwAll() } { - p.SetState(806) + p.SetState(814) p.KwRoles() } case 8: p.EnterOuterAlt(localctx, 8) { - p.SetState(808) + p.SetState(816) p.KwRole() } { - p.SetState(809) + p.SetState(817) p.Role() } @@ -6278,14 +6283,14 @@ func (p *CqlParser) CreateUser() (localctx ICreateUserContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(813) + p.SetState(821) p.KwCreate() } { - p.SetState(814) + p.SetState(822) p.KwUser() } - p.SetState(816) + p.SetState(824) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -6294,28 +6299,28 @@ func (p *CqlParser) CreateUser() (localctx ICreateUserContext) { if _la == CqlParserK_IF { { - p.SetState(815) + p.SetState(823) p.IfNotExist() } } { - p.SetState(818) + p.SetState(826) p.User() } { - p.SetState(819) + p.SetState(827) p.KwWith() } { - p.SetState(820) + p.SetState(828) p.KwPassword() } { - p.SetState(821) + p.SetState(829) p.StringLiteral() } - p.SetState(824) + p.SetState(832) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -6323,13 +6328,13 @@ func (p *CqlParser) CreateUser() (localctx ICreateUserContext) { switch p.GetTokenStream().LA(1) { case CqlParserK_SUPERUSER: { - p.SetState(822) + p.SetState(830) p.KwSuperuser() } case CqlParserK_NOSUPERUSER: { - p.SetState(823) + p.SetState(831) p.KwNosuperuser() } @@ -6508,14 +6513,14 @@ func (p *CqlParser) CreateRole() (localctx ICreateRoleContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(826) + p.SetState(834) p.KwCreate() } { - p.SetState(827) + p.SetState(835) p.KwRole() } - p.SetState(829) + p.SetState(837) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -6524,16 +6529,16 @@ func (p *CqlParser) CreateRole() (localctx ICreateRoleContext) { if _la == CqlParserK_IF { { - p.SetState(828) + p.SetState(836) p.IfNotExist() } } { - p.SetState(831) + p.SetState(839) p.Role() } - p.SetState(833) + p.SetState(841) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -6542,7 +6547,7 @@ func (p *CqlParser) CreateRole() (localctx ICreateRoleContext) { if _la == CqlParserK_WITH { { - p.SetState(832) + p.SetState(840) p.RoleWith() } @@ -6774,14 +6779,14 @@ func (p *CqlParser) CreateType() (localctx ICreateTypeContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(835) + p.SetState(843) p.KwCreate() } { - p.SetState(836) + p.SetState(844) p.KwType() } - p.SetState(838) + p.SetState(846) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -6790,21 +6795,21 @@ func (p *CqlParser) CreateType() (localctx ICreateTypeContext) { if _la == CqlParserK_IF { { - p.SetState(837) + p.SetState(845) p.IfNotExist() } } - p.SetState(843) + p.SetState(851) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 27, p.GetParserRuleContext()) == 1 { { - p.SetState(840) + p.SetState(848) p.Keyspace() } { - p.SetState(841) + p.SetState(849) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -6816,19 +6821,19 @@ func (p *CqlParser) CreateType() (localctx ICreateTypeContext) { goto errorExit } { - p.SetState(845) + p.SetState(853) p.Type_() } { - p.SetState(846) + p.SetState(854) p.SyntaxBracketLr() } { - p.SetState(847) + p.SetState(855) p.TypeMemberColumnList() } { - p.SetState(848) + p.SetState(856) p.SyntaxBracketRr() } @@ -7046,14 +7051,14 @@ func (p *CqlParser) TypeMemberColumnList() (localctx ITypeMemberColumnListContex p.EnterOuterAlt(localctx, 1) { - p.SetState(850) + p.SetState(858) p.Column() } { - p.SetState(851) + p.SetState(859) p.DataType() } - p.SetState(858) + p.SetState(866) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -7062,19 +7067,19 @@ func (p *CqlParser) TypeMemberColumnList() (localctx ITypeMemberColumnListContex for _la == CqlParserCOMMA { { - p.SetState(852) + p.SetState(860) p.SyntaxComma() } { - p.SetState(853) + p.SetState(861) p.Column() } { - p.SetState(854) + p.SetState(862) p.DataType() } - p.SetState(860) + p.SetState(868) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -7291,14 +7296,14 @@ func (p *CqlParser) CreateTrigger() (localctx ICreateTriggerContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(861) + p.SetState(869) p.KwCreate() } { - p.SetState(862) + p.SetState(870) p.KwTrigger() } - p.SetState(864) + p.SetState(872) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -7307,21 +7312,21 @@ func (p *CqlParser) CreateTrigger() (localctx ICreateTriggerContext) { if _la == CqlParserK_IF { { - p.SetState(863) + p.SetState(871) p.IfNotExist() } } - p.SetState(869) + p.SetState(877) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 30, p.GetParserRuleContext()) == 1 { { - p.SetState(866) + p.SetState(874) p.Keyspace() } { - p.SetState(867) + p.SetState(875) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -7333,15 +7338,15 @@ func (p *CqlParser) CreateTrigger() (localctx ICreateTriggerContext) { goto errorExit } { - p.SetState(871) + p.SetState(879) p.Trigger() } { - p.SetState(872) + p.SetState(880) p.KwUsing() } { - p.SetState(873) + p.SetState(881) p.TriggerClass() } @@ -7767,18 +7772,18 @@ func (p *CqlParser) CreateMaterializedView() (localctx ICreateMaterializedViewCo p.EnterOuterAlt(localctx, 1) { - p.SetState(875) + p.SetState(883) p.KwCreate() } { - p.SetState(876) + p.SetState(884) p.KwMaterialized() } { - p.SetState(877) + p.SetState(885) p.KwView() } - p.SetState(879) + p.SetState(887) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -7787,21 +7792,21 @@ func (p *CqlParser) CreateMaterializedView() (localctx ICreateMaterializedViewCo if _la == CqlParserK_IF { { - p.SetState(878) + p.SetState(886) p.IfNotExist() } } - p.SetState(884) + p.SetState(892) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 32, p.GetParserRuleContext()) == 1 { { - p.SetState(881) + p.SetState(889) p.Keyspace() } { - p.SetState(882) + p.SetState(890) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -7813,54 +7818,54 @@ func (p *CqlParser) CreateMaterializedView() (localctx ICreateMaterializedViewCo goto errorExit } { - p.SetState(886) + p.SetState(894) p.MaterializedView() } { - p.SetState(887) + p.SetState(895) p.KwAs() } { - p.SetState(888) + p.SetState(896) p.KwSelect() } { - p.SetState(889) + p.SetState(897) p.ColumnList() } { - p.SetState(890) + p.SetState(898) p.KwFrom() } { - p.SetState(891) + p.SetState(899) p.TableSpec() } { - p.SetState(892) + p.SetState(900) p.MaterializedViewWhere() } { - p.SetState(893) + p.SetState(901) p.KwPrimary() } { - p.SetState(894) + p.SetState(902) p.KwKey() } { - p.SetState(895) + p.SetState(903) p.SyntaxBracketLr() } { - p.SetState(896) + p.SetState(904) p.ColumnList() } { - p.SetState(897) + p.SetState(905) p.SyntaxBracketRr() } - p.SetState(901) + p.SetState(909) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -7869,11 +7874,11 @@ func (p *CqlParser) CreateMaterializedView() (localctx ICreateMaterializedViewCo if _la == CqlParserK_WITH { { - p.SetState(898) + p.SetState(906) p.KwWith() } { - p.SetState(899) + p.SetState(907) p.MaterializedViewOptions() } @@ -8032,14 +8037,14 @@ func (p *CqlParser) MaterializedViewWhere() (localctx IMaterializedViewWhereCont p.EnterOuterAlt(localctx, 1) { - p.SetState(903) + p.SetState(911) p.KwWhere() } { - p.SetState(904) + p.SetState(912) p.ColumnNotNullList() } - p.SetState(908) + p.SetState(916) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -8048,11 +8053,11 @@ func (p *CqlParser) MaterializedViewWhere() (localctx IMaterializedViewWhereCont if _la == CqlParserK_AND { { - p.SetState(905) + p.SetState(913) p.KwAnd() } { - p.SetState(906) + p.SetState(914) p.RelationElements() } @@ -8229,10 +8234,10 @@ func (p *CqlParser) ColumnNotNullList() (localctx IColumnNotNullListContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(910) + p.SetState(918) p.ColumnNotNull() } - p.SetState(916) + p.SetState(924) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -8244,16 +8249,16 @@ func (p *CqlParser) ColumnNotNullList() (localctx IColumnNotNullListContext) { for _alt != 2 && _alt != antlr.ATNInvalidAltNumber { if _alt == 1 { { - p.SetState(911) + p.SetState(919) p.KwAnd() } { - p.SetState(912) + p.SetState(920) p.ColumnNotNull() } } - p.SetState(918) + p.SetState(926) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -8415,19 +8420,19 @@ func (p *CqlParser) ColumnNotNull() (localctx IColumnNotNullContext) { p.EnterRule(localctx, 50, CqlParserRULE_columnNotNull) p.EnterOuterAlt(localctx, 1) { - p.SetState(919) + p.SetState(927) p.Column() } { - p.SetState(920) + p.SetState(928) p.KwIs() } { - p.SetState(921) + p.SetState(929) p.KwNot() } { - p.SetState(922) + p.SetState(930) p.KwNull() } @@ -8563,7 +8568,7 @@ func (s *MaterializedViewOptionsContext) ExitRule(listener antlr.ParseTreeListen func (p *CqlParser) MaterializedViewOptions() (localctx IMaterializedViewOptionsContext) { localctx = NewMaterializedViewOptionsContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 52, CqlParserRULE_materializedViewOptions) - p.SetState(930) + p.SetState(938) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -8573,29 +8578,29 @@ func (p *CqlParser) MaterializedViewOptions() (localctx IMaterializedViewOptions case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(924) + p.SetState(932) p.TableOptions() } case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(925) + p.SetState(933) p.TableOptions() } { - p.SetState(926) + p.SetState(934) p.KwAnd() } { - p.SetState(927) + p.SetState(935) p.ClusteringOrder() } case 3: p.EnterOuterAlt(localctx, 3) { - p.SetState(929) + p.SetState(937) p.ClusteringOrder() } @@ -8880,14 +8885,14 @@ func (p *CqlParser) CreateKeyspace() (localctx ICreateKeyspaceContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(932) + p.SetState(940) p.KwCreate() } { - p.SetState(933) + p.SetState(941) p.KwKeyspace() } - p.SetState(935) + p.SetState(943) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -8896,25 +8901,25 @@ func (p *CqlParser) CreateKeyspace() (localctx ICreateKeyspaceContext) { if _la == CqlParserK_IF { { - p.SetState(934) + p.SetState(942) p.IfNotExist() } } { - p.SetState(937) + p.SetState(945) p.Keyspace() } { - p.SetState(938) + p.SetState(946) p.KwWith() } { - p.SetState(939) + p.SetState(947) p.KwReplication() } { - p.SetState(940) + p.SetState(948) p.Match(CqlParserOPERATOR_EQ) if p.HasError() { // Recognition error - abort rule @@ -8922,18 +8927,18 @@ func (p *CqlParser) CreateKeyspace() (localctx ICreateKeyspaceContext) { } } { - p.SetState(941) + p.SetState(949) p.SyntaxBracketLc() } { - p.SetState(942) + p.SetState(950) p.ReplicationList() } { - p.SetState(943) + p.SetState(951) p.SyntaxBracketRc() } - p.SetState(947) + p.SetState(955) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -8942,11 +8947,11 @@ func (p *CqlParser) CreateKeyspace() (localctx ICreateKeyspaceContext) { if _la == CqlParserK_AND { { - p.SetState(944) + p.SetState(952) p.KwAnd() } { - p.SetState(945) + p.SetState(953) p.DurableWrites() } @@ -9314,10 +9319,10 @@ func (p *CqlParser) CreateFunction() (localctx ICreateFunctionContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(949) + p.SetState(957) p.KwCreate() } - p.SetState(951) + p.SetState(959) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -9326,16 +9331,16 @@ func (p *CqlParser) CreateFunction() (localctx ICreateFunctionContext) { if _la == CqlParserK_OR { { - p.SetState(950) + p.SetState(958) p.OrReplace() } } { - p.SetState(953) + p.SetState(961) p.KwFunction() } - p.SetState(955) + p.SetState(963) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -9344,21 +9349,21 @@ func (p *CqlParser) CreateFunction() (localctx ICreateFunctionContext) { if _la == CqlParserK_IF { { - p.SetState(954) + p.SetState(962) p.IfNotExist() } } - p.SetState(960) + p.SetState(968) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 41, p.GetParserRuleContext()) == 1 { { - p.SetState(957) + p.SetState(965) p.Keyspace() } { - p.SetState(958) + p.SetState(966) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -9370,14 +9375,14 @@ func (p *CqlParser) CreateFunction() (localctx ICreateFunctionContext) { goto errorExit } { - p.SetState(962) + p.SetState(970) p.Function_() } { - p.SetState(963) + p.SetState(971) p.SyntaxBracketLr() } - p.SetState(965) + p.SetState(973) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -9386,41 +9391,41 @@ func (p *CqlParser) CreateFunction() (localctx ICreateFunctionContext) { if _la == CqlParserK_INPUT || _la == CqlParserOBJECT_NAME { { - p.SetState(964) + p.SetState(972) p.ParamList() } } { - p.SetState(967) + p.SetState(975) p.SyntaxBracketRr() } { - p.SetState(968) + p.SetState(976) p.ReturnMode() } { - p.SetState(969) + p.SetState(977) p.KwReturns() } { - p.SetState(970) + p.SetState(978) p.DataType() } { - p.SetState(971) + p.SetState(979) p.KwLanguage() } { - p.SetState(972) + p.SetState(980) p.Language() } { - p.SetState(973) + p.SetState(981) p.KwAs() } { - p.SetState(974) + p.SetState(982) p.CodeBlock() } @@ -9519,7 +9524,7 @@ func (p *CqlParser) CodeBlock() (localctx ICodeBlockContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(976) + p.SetState(984) _la = p.GetTokenStream().LA(1) if !(_la == CqlParserCODE_BLOCK || _la == CqlParserSTRING_LITERAL) { @@ -9701,10 +9706,10 @@ func (p *CqlParser) ParamList() (localctx IParamListContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(978) + p.SetState(986) p.Param() } - p.SetState(984) + p.SetState(992) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -9713,15 +9718,15 @@ func (p *CqlParser) ParamList() (localctx IParamListContext) { for _la == CqlParserCOMMA { { - p.SetState(979) + p.SetState(987) p.SyntaxComma() } { - p.SetState(980) + p.SetState(988) p.Param() } - p.SetState(986) + p.SetState(994) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -9922,7 +9927,7 @@ func (p *CqlParser) ReturnMode() (localctx IReturnModeContext) { localctx = NewReturnModeContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 62, CqlParserRULE_returnMode) p.EnterOuterAlt(localctx, 1) - p.SetState(991) + p.SetState(999) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -9931,17 +9936,17 @@ func (p *CqlParser) ReturnMode() (localctx IReturnModeContext) { switch p.GetTokenStream().LA(1) { case CqlParserK_CALLED: { - p.SetState(987) + p.SetState(995) p.KwCalled() } case CqlParserK_RETURNS: { - p.SetState(988) + p.SetState(996) p.KwReturns() } { - p.SetState(989) + p.SetState(997) p.KwNull() } @@ -9950,15 +9955,15 @@ func (p *CqlParser) ReturnMode() (localctx IReturnModeContext) { goto errorExit } { - p.SetState(993) + p.SetState(1001) p.KwOn() } { - p.SetState(994) + p.SetState(1002) p.KwNull() } { - p.SetState(995) + p.SetState(1003) p.KwInput() } @@ -10359,10 +10364,10 @@ func (p *CqlParser) CreateAggregate() (localctx ICreateAggregateContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(997) + p.SetState(1005) p.KwCreate() } - p.SetState(999) + p.SetState(1007) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -10371,16 +10376,16 @@ func (p *CqlParser) CreateAggregate() (localctx ICreateAggregateContext) { if _la == CqlParserK_OR { { - p.SetState(998) + p.SetState(1006) p.OrReplace() } } { - p.SetState(1001) + p.SetState(1009) p.KwAggregate() } - p.SetState(1003) + p.SetState(1011) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -10389,21 +10394,21 @@ func (p *CqlParser) CreateAggregate() (localctx ICreateAggregateContext) { if _la == CqlParserK_IF { { - p.SetState(1002) + p.SetState(1010) p.IfNotExist() } } - p.SetState(1008) + p.SetState(1016) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 47, p.GetParserRuleContext()) == 1 { { - p.SetState(1005) + p.SetState(1013) p.Keyspace() } { - p.SetState(1006) + p.SetState(1014) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -10415,51 +10420,51 @@ func (p *CqlParser) CreateAggregate() (localctx ICreateAggregateContext) { goto errorExit } { - p.SetState(1010) + p.SetState(1018) p.Aggregate() } { - p.SetState(1011) + p.SetState(1019) p.SyntaxBracketLr() } { - p.SetState(1012) + p.SetState(1020) p.DataType() } { - p.SetState(1013) + p.SetState(1021) p.SyntaxBracketRr() } { - p.SetState(1014) + p.SetState(1022) p.KwSfunc() } { - p.SetState(1015) + p.SetState(1023) p.Function_() } { - p.SetState(1016) + p.SetState(1024) p.KwStype() } { - p.SetState(1017) + p.SetState(1025) p.DataType() } { - p.SetState(1018) + p.SetState(1026) p.KwFinalfunc() } { - p.SetState(1019) + p.SetState(1027) p.Function_() } { - p.SetState(1020) + p.SetState(1028) p.KwInitcond() } { - p.SetState(1021) + p.SetState(1029) p.InitCondDefinition() } @@ -10612,7 +10617,7 @@ func (s *InitCondDefinitionContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) InitCondDefinition() (localctx IInitCondDefinitionContext) { localctx = NewInitCondDefinitionContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 66, CqlParserRULE_initCondDefinition) - p.SetState(1027) + p.SetState(1035) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -10622,28 +10627,28 @@ func (p *CqlParser) InitCondDefinition() (localctx IInitCondDefinitionContext) { case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(1023) + p.SetState(1031) p.Constant() } case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(1024) + p.SetState(1032) p.InitCondList() } case 3: p.EnterOuterAlt(localctx, 3) { - p.SetState(1025) + p.SetState(1033) p.InitCondListNested() } case 4: p.EnterOuterAlt(localctx, 4) { - p.SetState(1026) + p.SetState(1034) p.InitCondHash() } @@ -10856,14 +10861,14 @@ func (p *CqlParser) InitCondHash() (localctx IInitCondHashContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1029) + p.SetState(1037) p.SyntaxBracketLc() } { - p.SetState(1030) + p.SetState(1038) p.InitCondHashItem() } - p.SetState(1036) + p.SetState(1044) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -10872,15 +10877,15 @@ func (p *CqlParser) InitCondHash() (localctx IInitCondHashContext) { for _la == CqlParserCOMMA { { - p.SetState(1031) + p.SetState(1039) p.SyntaxComma() } { - p.SetState(1032) + p.SetState(1040) p.InitCondHashItem() } - p.SetState(1038) + p.SetState(1046) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -10888,7 +10893,7 @@ func (p *CqlParser) InitCondHash() (localctx IInitCondHashContext) { _la = p.GetTokenStream().LA(1) } { - p.SetState(1039) + p.SetState(1047) p.SyntaxBracketRc() } @@ -11014,11 +11019,11 @@ func (p *CqlParser) InitCondHashItem() (localctx IInitCondHashItemContext) { p.EnterRule(localctx, 70, CqlParserRULE_initCondHashItem) p.EnterOuterAlt(localctx, 1) { - p.SetState(1041) + p.SetState(1049) p.HashKey() } { - p.SetState(1042) + p.SetState(1050) p.Match(CqlParserCOLON) if p.HasError() { // Recognition error - abort rule @@ -11026,7 +11031,7 @@ func (p *CqlParser) InitCondHashItem() (localctx IInitCondHashItemContext) { } } { - p.SetState(1043) + p.SetState(1051) p.InitCondDefinition() } @@ -11278,14 +11283,14 @@ func (p *CqlParser) InitCondListNested() (localctx IInitCondListNestedContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1045) + p.SetState(1053) p.SyntaxBracketLr() } { - p.SetState(1046) + p.SetState(1054) p.InitCondList() } - p.SetState(1053) + p.SetState(1061) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -11293,7 +11298,7 @@ func (p *CqlParser) InitCondListNested() (localctx IInitCondListNestedContext) { _la = p.GetTokenStream().LA(1) for _la == CqlParserLR_BRACKET || _la == CqlParserCOMMA { - p.SetState(1051) + p.SetState(1059) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -11302,17 +11307,17 @@ func (p *CqlParser) InitCondListNested() (localctx IInitCondListNestedContext) { switch p.GetTokenStream().LA(1) { case CqlParserCOMMA: { - p.SetState(1047) + p.SetState(1055) p.SyntaxComma() } { - p.SetState(1048) + p.SetState(1056) p.Constant() } case CqlParserLR_BRACKET: { - p.SetState(1050) + p.SetState(1058) p.InitCondList() } @@ -11321,7 +11326,7 @@ func (p *CqlParser) InitCondListNested() (localctx IInitCondListNestedContext) { goto errorExit } - p.SetState(1055) + p.SetState(1063) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -11329,7 +11334,7 @@ func (p *CqlParser) InitCondListNested() (localctx IInitCondListNestedContext) { _la = p.GetTokenStream().LA(1) } { - p.SetState(1056) + p.SetState(1064) p.SyntaxBracketRr() } @@ -11538,14 +11543,14 @@ func (p *CqlParser) InitCondList() (localctx IInitCondListContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1058) + p.SetState(1066) p.SyntaxBracketLr() } { - p.SetState(1059) + p.SetState(1067) p.Constant() } - p.SetState(1065) + p.SetState(1073) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -11554,15 +11559,15 @@ func (p *CqlParser) InitCondList() (localctx IInitCondListContext) { for _la == CqlParserCOMMA { { - p.SetState(1060) + p.SetState(1068) p.SyntaxComma() } { - p.SetState(1061) + p.SetState(1069) p.Constant() } - p.SetState(1067) + p.SetState(1075) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -11570,7 +11575,7 @@ func (p *CqlParser) InitCondList() (localctx IInitCondListContext) { _la = p.GetTokenStream().LA(1) } { - p.SetState(1068) + p.SetState(1076) p.SyntaxBracketRr() } @@ -11691,11 +11696,11 @@ func (p *CqlParser) OrReplace() (localctx IOrReplaceContext) { p.EnterRule(localctx, 76, CqlParserRULE_orReplace) p.EnterOuterAlt(localctx, 1) { - p.SetState(1070) + p.SetState(1078) p.KwOr() } { - p.SetState(1071) + p.SetState(1079) p.KwReplace() } @@ -11886,26 +11891,26 @@ func (p *CqlParser) AlterUser() (localctx IAlterUserContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1073) + p.SetState(1081) p.KwAlter() } { - p.SetState(1074) + p.SetState(1082) p.KwUser() } { - p.SetState(1075) + p.SetState(1083) p.User() } { - p.SetState(1076) + p.SetState(1084) p.KwWith() } { - p.SetState(1077) + p.SetState(1085) p.UserPassword() } - p.SetState(1079) + p.SetState(1087) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -11914,7 +11919,7 @@ func (p *CqlParser) AlterUser() (localctx IAlterUserContext) { if _la == CqlParserK_NOSUPERUSER || _la == CqlParserK_SUPERUSER { { - p.SetState(1078) + p.SetState(1086) p.UserSuperUser() } @@ -12037,11 +12042,11 @@ func (p *CqlParser) UserPassword() (localctx IUserPasswordContext) { p.EnterRule(localctx, 80, CqlParserRULE_userPassword) p.EnterOuterAlt(localctx, 1) { - p.SetState(1081) + p.SetState(1089) p.KwPassword() } { - p.SetState(1082) + p.SetState(1090) p.StringLiteral() } @@ -12160,7 +12165,7 @@ func (s *UserSuperUserContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) UserSuperUser() (localctx IUserSuperUserContext) { localctx = NewUserSuperUserContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 82, CqlParserRULE_userSuperUser) - p.SetState(1086) + p.SetState(1094) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -12170,14 +12175,14 @@ func (p *CqlParser) UserSuperUser() (localctx IUserSuperUserContext) { case CqlParserK_SUPERUSER: p.EnterOuterAlt(localctx, 1) { - p.SetState(1084) + p.SetState(1092) p.KwSuperuser() } case CqlParserK_NOSUPERUSER: p.EnterOuterAlt(localctx, 2) { - p.SetState(1085) + p.SetState(1093) p.KwNosuperuser() } @@ -12359,23 +12364,23 @@ func (p *CqlParser) AlterType() (localctx IAlterTypeContext) { p.EnterRule(localctx, 84, CqlParserRULE_alterType) p.EnterOuterAlt(localctx, 1) { - p.SetState(1088) + p.SetState(1096) p.KwAlter() } { - p.SetState(1089) + p.SetState(1097) p.KwType() } - p.SetState(1093) + p.SetState(1101) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 55, p.GetParserRuleContext()) == 1 { { - p.SetState(1090) + p.SetState(1098) p.Keyspace() } { - p.SetState(1091) + p.SetState(1099) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -12387,11 +12392,11 @@ func (p *CqlParser) AlterType() (localctx IAlterTypeContext) { goto errorExit } { - p.SetState(1095) + p.SetState(1103) p.Type_() } { - p.SetState(1096) + p.SetState(1104) p.AlterTypeOperation() } @@ -12527,7 +12532,7 @@ func (s *AlterTypeOperationContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) AlterTypeOperation() (localctx IAlterTypeOperationContext) { localctx = NewAlterTypeOperationContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 86, CqlParserRULE_alterTypeOperation) - p.SetState(1101) + p.SetState(1109) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -12537,21 +12542,21 @@ func (p *CqlParser) AlterTypeOperation() (localctx IAlterTypeOperationContext) { case CqlParserK_ALTER: p.EnterOuterAlt(localctx, 1) { - p.SetState(1098) + p.SetState(1106) p.AlterTypeAlterType() } case CqlParserK_ADD: p.EnterOuterAlt(localctx, 2) { - p.SetState(1099) + p.SetState(1107) p.AlterTypeAdd() } case CqlParserK_RENAME: p.EnterOuterAlt(localctx, 3) { - p.SetState(1100) + p.SetState(1108) p.AlterTypeRename() } @@ -12677,11 +12682,11 @@ func (p *CqlParser) AlterTypeRename() (localctx IAlterTypeRenameContext) { p.EnterRule(localctx, 88, CqlParserRULE_alterTypeRename) p.EnterOuterAlt(localctx, 1) { - p.SetState(1103) + p.SetState(1111) p.KwRename() } { - p.SetState(1104) + p.SetState(1112) p.AlterTypeRenameList() } @@ -12856,10 +12861,10 @@ func (p *CqlParser) AlterTypeRenameList() (localctx IAlterTypeRenameListContext) p.EnterOuterAlt(localctx, 1) { - p.SetState(1106) + p.SetState(1114) p.AlterTypeRenameItem() } - p.SetState(1112) + p.SetState(1120) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -12868,15 +12873,15 @@ func (p *CqlParser) AlterTypeRenameList() (localctx IAlterTypeRenameListContext) for _la == CqlParserK_AND { { - p.SetState(1107) + p.SetState(1115) p.KwAnd() } { - p.SetState(1108) + p.SetState(1116) p.AlterTypeRenameItem() } - p.SetState(1114) + p.SetState(1122) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -13027,15 +13032,15 @@ func (p *CqlParser) AlterTypeRenameItem() (localctx IAlterTypeRenameItemContext) p.EnterRule(localctx, 92, CqlParserRULE_alterTypeRenameItem) p.EnterOuterAlt(localctx, 1) { - p.SetState(1115) + p.SetState(1123) p.Column() } { - p.SetState(1116) + p.SetState(1124) p.KwTo() } { - p.SetState(1117) + p.SetState(1125) p.Column() } @@ -13270,18 +13275,18 @@ func (p *CqlParser) AlterTypeAdd() (localctx IAlterTypeAddContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1119) + p.SetState(1127) p.KwAdd() } { - p.SetState(1120) + p.SetState(1128) p.Column() } { - p.SetState(1121) + p.SetState(1129) p.DataType() } - p.SetState(1128) + p.SetState(1136) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -13290,19 +13295,19 @@ func (p *CqlParser) AlterTypeAdd() (localctx IAlterTypeAddContext) { for _la == CqlParserCOMMA { { - p.SetState(1122) + p.SetState(1130) p.SyntaxComma() } { - p.SetState(1123) + p.SetState(1131) p.Column() } { - p.SetState(1124) + p.SetState(1132) p.DataType() } - p.SetState(1130) + p.SetState(1138) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -13461,19 +13466,19 @@ func (p *CqlParser) AlterTypeAlterType() (localctx IAlterTypeAlterTypeContext) { p.EnterRule(localctx, 96, CqlParserRULE_alterTypeAlterType) p.EnterOuterAlt(localctx, 1) { - p.SetState(1131) + p.SetState(1139) p.KwAlter() } { - p.SetState(1132) + p.SetState(1140) p.Column() } { - p.SetState(1133) + p.SetState(1141) p.KwType() } { - p.SetState(1134) + p.SetState(1142) p.DataType() } @@ -13628,19 +13633,19 @@ func (p *CqlParser) AlterTable() (localctx IAlterTableContext) { p.EnterRule(localctx, 98, CqlParserRULE_alterTable) p.EnterOuterAlt(localctx, 1) { - p.SetState(1136) + p.SetState(1144) p.KwAlter() } { - p.SetState(1137) + p.SetState(1145) p.KwTable() } { - p.SetState(1138) + p.SetState(1146) p.TableSpec() } { - p.SetState(1139) + p.SetState(1147) p.AlterTableOperation() } @@ -13827,7 +13832,7 @@ func (s *AlterTableOperationContext) ExitRule(listener antlr.ParseTreeListener) func (p *CqlParser) AlterTableOperation() (localctx IAlterTableOperationContext) { localctx = NewAlterTableOperationContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 100, CqlParserRULE_alterTableOperation) - p.SetState(1147) + p.SetState(1155) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -13837,42 +13842,42 @@ func (p *CqlParser) AlterTableOperation() (localctx IAlterTableOperationContext) case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(1141) + p.SetState(1149) p.AlterTableAdd() } case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(1142) + p.SetState(1150) p.AlterTableDropColumns() } case 3: p.EnterOuterAlt(localctx, 3) { - p.SetState(1143) + p.SetState(1151) p.AlterTableDropCompactStorage() } case 4: p.EnterOuterAlt(localctx, 4) { - p.SetState(1144) + p.SetState(1152) p.AlterTableAlterColumnTypes() } case 5: p.EnterOuterAlt(localctx, 5) { - p.SetState(1145) + p.SetState(1153) p.AlterTableRename() } case 6: p.EnterOuterAlt(localctx, 6) { - p.SetState(1146) + p.SetState(1154) p.AlterTableWith() } @@ -13997,11 +14002,11 @@ func (p *CqlParser) AlterTableWith() (localctx IAlterTableWithContext) { p.EnterRule(localctx, 102, CqlParserRULE_alterTableWith) p.EnterOuterAlt(localctx, 1) { - p.SetState(1149) + p.SetState(1157) p.KwWith() } { - p.SetState(1150) + p.SetState(1158) p.TableOptions() } @@ -14165,19 +14170,19 @@ func (p *CqlParser) AlterTableRename() (localctx IAlterTableRenameContext) { p.EnterRule(localctx, 104, CqlParserRULE_alterTableRename) p.EnterOuterAlt(localctx, 1) { - p.SetState(1152) + p.SetState(1160) p.KwRename() } { - p.SetState(1153) + p.SetState(1161) p.Column() } { - p.SetState(1154) + p.SetState(1162) p.KwTo() } { - p.SetState(1155) + p.SetState(1163) p.Column() } @@ -14315,15 +14320,15 @@ func (p *CqlParser) AlterTableDropCompactStorage() (localctx IAlterTableDropComp p.EnterRule(localctx, 106, CqlParserRULE_alterTableDropCompactStorage) p.EnterOuterAlt(localctx, 1) { - p.SetState(1157) + p.SetState(1165) p.KwDrop() } { - p.SetState(1158) + p.SetState(1166) p.KwCompact() } { - p.SetState(1159) + p.SetState(1167) p.KwStorage() } @@ -14444,11 +14449,11 @@ func (p *CqlParser) AlterTableDropColumns() (localctx IAlterTableDropColumnsCont p.EnterRule(localctx, 108, CqlParserRULE_alterTableDropColumns) p.EnterOuterAlt(localctx, 1) { - p.SetState(1161) + p.SetState(1169) p.KwDrop() } { - p.SetState(1162) + p.SetState(1170) p.AlterTableDropColumnList() } @@ -14623,10 +14628,10 @@ func (p *CqlParser) AlterTableDropColumnList() (localctx IAlterTableDropColumnLi p.EnterOuterAlt(localctx, 1) { - p.SetState(1164) + p.SetState(1172) p.Column() } - p.SetState(1170) + p.SetState(1178) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -14635,15 +14640,15 @@ func (p *CqlParser) AlterTableDropColumnList() (localctx IAlterTableDropColumnLi for _la == CqlParserCOMMA { { - p.SetState(1165) + p.SetState(1173) p.SyntaxComma() } { - p.SetState(1166) + p.SetState(1174) p.Column() } - p.SetState(1172) + p.SetState(1180) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -14768,11 +14773,11 @@ func (p *CqlParser) AlterTableAlterColumnTypes() (localctx IAlterTableAlterColum p.EnterRule(localctx, 112, CqlParserRULE_alterTableAlterColumnTypes) p.EnterOuterAlt(localctx, 1) { - p.SetState(1173) + p.SetState(1181) p.KwAlter() } { - p.SetState(1174) + p.SetState(1182) p.AlterTableAlterColumnTypeList() } @@ -14947,10 +14952,10 @@ func (p *CqlParser) AlterTableAlterColumnTypeList() (localctx IAlterTableAlterCo p.EnterOuterAlt(localctx, 1) { - p.SetState(1176) + p.SetState(1184) p.AlterTableAlterColumnType() } - p.SetState(1182) + p.SetState(1190) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -14959,15 +14964,15 @@ func (p *CqlParser) AlterTableAlterColumnTypeList() (localctx IAlterTableAlterCo for _la == CqlParserCOMMA { { - p.SetState(1177) + p.SetState(1185) p.SyntaxComma() } { - p.SetState(1178) + p.SetState(1186) p.AlterTableAlterColumnType() } - p.SetState(1184) + p.SetState(1192) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -15109,15 +15114,15 @@ func (p *CqlParser) AlterTableAlterColumnType() (localctx IAlterTableAlterColumn p.EnterRule(localctx, 116, CqlParserRULE_alterTableAlterColumnType) p.EnterOuterAlt(localctx, 1) { - p.SetState(1185) + p.SetState(1193) p.Column() } { - p.SetState(1186) + p.SetState(1194) p.KwType() } { - p.SetState(1187) + p.SetState(1195) p.DataType() } @@ -15238,11 +15243,11 @@ func (p *CqlParser) AlterTableAdd() (localctx IAlterTableAddContext) { p.EnterRule(localctx, 118, CqlParserRULE_alterTableAdd) p.EnterOuterAlt(localctx, 1) { - p.SetState(1189) + p.SetState(1197) p.KwAdd() } { - p.SetState(1190) + p.SetState(1198) p.AlterTableColumnDefinition() } @@ -15417,10 +15422,10 @@ func (p *CqlParser) AlterTableColumnDefinition() (localctx IAlterTableColumnDefi p.EnterOuterAlt(localctx, 1) { - p.SetState(1192) + p.SetState(1200) p.AlterTableAddColumn() } - p.SetState(1198) + p.SetState(1206) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -15429,15 +15434,15 @@ func (p *CqlParser) AlterTableColumnDefinition() (localctx IAlterTableColumnDefi for _la == CqlParserCOMMA { { - p.SetState(1193) + p.SetState(1201) p.SyntaxComma() } { - p.SetState(1194) + p.SetState(1202) p.AlterTableAddColumn() } - p.SetState(1200) + p.SetState(1208) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -15562,11 +15567,11 @@ func (p *CqlParser) AlterTableAddColumn() (localctx IAlterTableAddColumnContext) p.EnterRule(localctx, 122, CqlParserRULE_alterTableAddColumn) p.EnterOuterAlt(localctx, 1) { - p.SetState(1201) + p.SetState(1209) p.Column() } { - p.SetState(1202) + p.SetState(1210) p.DataType() } @@ -15723,18 +15728,18 @@ func (p *CqlParser) AlterRole() (localctx IAlterRoleContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1204) + p.SetState(1212) p.KwAlter() } { - p.SetState(1205) + p.SetState(1213) p.KwRole() } { - p.SetState(1206) + p.SetState(1214) p.Role() } - p.SetState(1208) + p.SetState(1216) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -15743,7 +15748,7 @@ func (p *CqlParser) AlterRole() (localctx IAlterRoleContext) { if _la == CqlParserK_WITH { { - p.SetState(1207) + p.SetState(1215) p.RoleWith() } @@ -15937,15 +15942,15 @@ func (p *CqlParser) RoleWith() (localctx IRoleWithContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1210) + p.SetState(1218) p.KwWith() } { - p.SetState(1211) + p.SetState(1219) p.RoleWithOptions() } - p.SetState(1217) + p.SetState(1225) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -15954,15 +15959,15 @@ func (p *CqlParser) RoleWith() (localctx IRoleWithContext) { for _la == CqlParserK_AND { { - p.SetState(1212) + p.SetState(1220) p.KwAnd() } { - p.SetState(1213) + p.SetState(1221) p.RoleWithOptions() } - p.SetState(1219) + p.SetState(1227) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -16175,7 +16180,7 @@ func (s *RoleWithOptionsContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) RoleWithOptions() (localctx IRoleWithOptionsContext) { localctx = NewRoleWithOptionsContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 128, CqlParserRULE_roleWithOptions) - p.SetState(1236) + p.SetState(1244) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -16185,11 +16190,11 @@ func (p *CqlParser) RoleWithOptions() (localctx IRoleWithOptionsContext) { case CqlParserK_PASSWORD: p.EnterOuterAlt(localctx, 1) { - p.SetState(1220) + p.SetState(1228) p.KwPassword() } { - p.SetState(1221) + p.SetState(1229) p.Match(CqlParserOPERATOR_EQ) if p.HasError() { // Recognition error - abort rule @@ -16197,18 +16202,18 @@ func (p *CqlParser) RoleWithOptions() (localctx IRoleWithOptionsContext) { } } { - p.SetState(1222) + p.SetState(1230) p.StringLiteral() } case CqlParserK_LOGIN: p.EnterOuterAlt(localctx, 2) { - p.SetState(1224) + p.SetState(1232) p.KwLogin() } { - p.SetState(1225) + p.SetState(1233) p.Match(CqlParserOPERATOR_EQ) if p.HasError() { // Recognition error - abort rule @@ -16216,18 +16221,18 @@ func (p *CqlParser) RoleWithOptions() (localctx IRoleWithOptionsContext) { } } { - p.SetState(1226) + p.SetState(1234) p.BooleanLiteral() } case CqlParserK_SUPERUSER: p.EnterOuterAlt(localctx, 3) { - p.SetState(1228) + p.SetState(1236) p.KwSuperuser() } { - p.SetState(1229) + p.SetState(1237) p.Match(CqlParserOPERATOR_EQ) if p.HasError() { // Recognition error - abort rule @@ -16235,18 +16240,18 @@ func (p *CqlParser) RoleWithOptions() (localctx IRoleWithOptionsContext) { } } { - p.SetState(1230) + p.SetState(1238) p.BooleanLiteral() } case CqlParserK_OPTIONS: p.EnterOuterAlt(localctx, 4) { - p.SetState(1232) + p.SetState(1240) p.KwOptions() } { - p.SetState(1233) + p.SetState(1241) p.Match(CqlParserOPERATOR_EQ) if p.HasError() { // Recognition error - abort rule @@ -16254,7 +16259,7 @@ func (p *CqlParser) RoleWithOptions() (localctx IRoleWithOptionsContext) { } } { - p.SetState(1234) + p.SetState(1242) p.OptionHash() } @@ -16472,27 +16477,27 @@ func (p *CqlParser) AlterMaterializedView() (localctx IAlterMaterializedViewCont p.EnterOuterAlt(localctx, 1) { - p.SetState(1238) + p.SetState(1246) p.KwAlter() } { - p.SetState(1239) + p.SetState(1247) p.KwMaterialized() } { - p.SetState(1240) + p.SetState(1248) p.KwView() } - p.SetState(1244) + p.SetState(1252) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 66, p.GetParserRuleContext()) == 1 { { - p.SetState(1241) + p.SetState(1249) p.Keyspace() } { - p.SetState(1242) + p.SetState(1250) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -16504,10 +16509,10 @@ func (p *CqlParser) AlterMaterializedView() (localctx IAlterMaterializedViewCont goto errorExit } { - p.SetState(1246) + p.SetState(1254) p.MaterializedView() } - p.SetState(1250) + p.SetState(1258) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -16516,11 +16521,11 @@ func (p *CqlParser) AlterMaterializedView() (localctx IAlterMaterializedViewCont if _la == CqlParserK_WITH { { - p.SetState(1247) + p.SetState(1255) p.KwWith() } { - p.SetState(1248) + p.SetState(1256) p.TableOptions() } @@ -16679,14 +16684,14 @@ func (p *CqlParser) DropUser() (localctx IDropUserContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1252) + p.SetState(1260) p.KwDrop() } { - p.SetState(1253) + p.SetState(1261) p.KwUser() } - p.SetState(1255) + p.SetState(1263) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -16695,13 +16700,13 @@ func (p *CqlParser) DropUser() (localctx IDropUserContext) { if _la == CqlParserK_IF { { - p.SetState(1254) + p.SetState(1262) p.IfExist() } } { - p.SetState(1257) + p.SetState(1265) p.User() } @@ -16880,14 +16885,14 @@ func (p *CqlParser) DropType() (localctx IDropTypeContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1259) + p.SetState(1267) p.KwDrop() } { - p.SetState(1260) + p.SetState(1268) p.KwType() } - p.SetState(1262) + p.SetState(1270) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -16896,21 +16901,21 @@ func (p *CqlParser) DropType() (localctx IDropTypeContext) { if _la == CqlParserK_IF { { - p.SetState(1261) + p.SetState(1269) p.IfExist() } } - p.SetState(1267) + p.SetState(1275) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 70, p.GetParserRuleContext()) == 1 { { - p.SetState(1264) + p.SetState(1272) p.Keyspace() } { - p.SetState(1265) + p.SetState(1273) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -16922,7 +16927,7 @@ func (p *CqlParser) DropType() (localctx IDropTypeContext) { goto errorExit } { - p.SetState(1269) + p.SetState(1277) p.Type_() } @@ -17118,18 +17123,18 @@ func (p *CqlParser) DropMaterializedView() (localctx IDropMaterializedViewContex p.EnterOuterAlt(localctx, 1) { - p.SetState(1271) + p.SetState(1279) p.KwDrop() } { - p.SetState(1272) + p.SetState(1280) p.KwMaterialized() } { - p.SetState(1273) + p.SetState(1281) p.KwView() } - p.SetState(1275) + p.SetState(1283) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -17138,21 +17143,21 @@ func (p *CqlParser) DropMaterializedView() (localctx IDropMaterializedViewContex if _la == CqlParserK_IF { { - p.SetState(1274) + p.SetState(1282) p.IfExist() } } - p.SetState(1280) + p.SetState(1288) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 72, p.GetParserRuleContext()) == 1 { { - p.SetState(1277) + p.SetState(1285) p.Keyspace() } { - p.SetState(1278) + p.SetState(1286) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -17164,7 +17169,7 @@ func (p *CqlParser) DropMaterializedView() (localctx IDropMaterializedViewContex goto errorExit } { - p.SetState(1282) + p.SetState(1290) p.MaterializedView() } @@ -17343,14 +17348,14 @@ func (p *CqlParser) DropAggregate() (localctx IDropAggregateContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1284) + p.SetState(1292) p.KwDrop() } { - p.SetState(1285) + p.SetState(1293) p.KwAggregate() } - p.SetState(1287) + p.SetState(1295) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -17359,21 +17364,21 @@ func (p *CqlParser) DropAggregate() (localctx IDropAggregateContext) { if _la == CqlParserK_IF { { - p.SetState(1286) + p.SetState(1294) p.IfExist() } } - p.SetState(1292) + p.SetState(1300) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 74, p.GetParserRuleContext()) == 1 { { - p.SetState(1289) + p.SetState(1297) p.Keyspace() } { - p.SetState(1290) + p.SetState(1298) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -17385,7 +17390,7 @@ func (p *CqlParser) DropAggregate() (localctx IDropAggregateContext) { goto errorExit } { - p.SetState(1294) + p.SetState(1302) p.Aggregate() } @@ -17564,14 +17569,14 @@ func (p *CqlParser) DropFunction() (localctx IDropFunctionContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1296) + p.SetState(1304) p.KwDrop() } { - p.SetState(1297) + p.SetState(1305) p.KwFunction() } - p.SetState(1299) + p.SetState(1307) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -17580,21 +17585,21 @@ func (p *CqlParser) DropFunction() (localctx IDropFunctionContext) { if _la == CqlParserK_IF { { - p.SetState(1298) + p.SetState(1306) p.IfExist() } } - p.SetState(1304) + p.SetState(1312) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 76, p.GetParserRuleContext()) == 1 { { - p.SetState(1301) + p.SetState(1309) p.Keyspace() } { - p.SetState(1302) + p.SetState(1310) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -17606,7 +17611,7 @@ func (p *CqlParser) DropFunction() (localctx IDropFunctionContext) { goto errorExit } { - p.SetState(1306) + p.SetState(1314) p.Function_() } @@ -17797,14 +17802,14 @@ func (p *CqlParser) DropTrigger() (localctx IDropTriggerContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1308) + p.SetState(1316) p.KwDrop() } { - p.SetState(1309) + p.SetState(1317) p.KwTrigger() } - p.SetState(1311) + p.SetState(1319) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -17813,21 +17818,21 @@ func (p *CqlParser) DropTrigger() (localctx IDropTriggerContext) { if _la == CqlParserK_IF { { - p.SetState(1310) + p.SetState(1318) p.IfExist() } } { - p.SetState(1313) + p.SetState(1321) p.Trigger() } { - p.SetState(1314) + p.SetState(1322) p.KwOn() } { - p.SetState(1315) + p.SetState(1323) p.TableSpec() } @@ -17984,14 +17989,14 @@ func (p *CqlParser) DropRole() (localctx IDropRoleContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1317) + p.SetState(1325) p.KwDrop() } { - p.SetState(1318) + p.SetState(1326) p.KwRole() } - p.SetState(1320) + p.SetState(1328) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -18000,13 +18005,13 @@ func (p *CqlParser) DropRole() (localctx IDropRoleContext) { if _la == CqlParserK_IF { { - p.SetState(1319) + p.SetState(1327) p.IfExist() } } { - p.SetState(1322) + p.SetState(1330) p.Role() } @@ -18163,14 +18168,14 @@ func (p *CqlParser) DropTable() (localctx IDropTableContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1324) + p.SetState(1332) p.KwDrop() } { - p.SetState(1325) + p.SetState(1333) p.KwTable() } - p.SetState(1327) + p.SetState(1335) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -18179,13 +18184,13 @@ func (p *CqlParser) DropTable() (localctx IDropTableContext) { if _la == CqlParserK_IF { { - p.SetState(1326) + p.SetState(1334) p.IfExist() } } { - p.SetState(1329) + p.SetState(1337) p.TableSpec() } @@ -18342,14 +18347,14 @@ func (p *CqlParser) DropKeyspace() (localctx IDropKeyspaceContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1331) + p.SetState(1339) p.KwDrop() } { - p.SetState(1332) + p.SetState(1340) p.KwKeyspace() } - p.SetState(1334) + p.SetState(1342) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -18358,13 +18363,13 @@ func (p *CqlParser) DropKeyspace() (localctx IDropKeyspaceContext) { if _la == CqlParserK_IF { { - p.SetState(1333) + p.SetState(1341) p.IfExist() } } { - p.SetState(1336) + p.SetState(1344) p.Keyspace() } @@ -18543,14 +18548,14 @@ func (p *CqlParser) DropIndex() (localctx IDropIndexContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1338) + p.SetState(1346) p.KwDrop() } { - p.SetState(1339) + p.SetState(1347) p.KwIndex() } - p.SetState(1341) + p.SetState(1349) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -18559,21 +18564,21 @@ func (p *CqlParser) DropIndex() (localctx IDropIndexContext) { if _la == CqlParserK_IF { { - p.SetState(1340) + p.SetState(1348) p.IfExist() } } - p.SetState(1346) + p.SetState(1354) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 82, p.GetParserRuleContext()) == 1 { { - p.SetState(1343) + p.SetState(1351) p.Keyspace() } { - p.SetState(1344) + p.SetState(1352) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -18585,7 +18590,7 @@ func (p *CqlParser) DropIndex() (localctx IDropIndexContext) { goto errorExit } { - p.SetState(1348) + p.SetState(1356) p.IndexName() } @@ -18810,14 +18815,14 @@ func (p *CqlParser) CreateTable() (localctx ICreateTableContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1350) + p.SetState(1358) p.KwCreate() } { - p.SetState(1351) + p.SetState(1359) p.KwTable() } - p.SetState(1353) + p.SetState(1361) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -18826,28 +18831,28 @@ func (p *CqlParser) CreateTable() (localctx ICreateTableContext) { if _la == CqlParserK_IF { { - p.SetState(1352) + p.SetState(1360) p.IfNotExist() } } { - p.SetState(1355) + p.SetState(1363) p.TableSpec() } { - p.SetState(1356) + p.SetState(1364) p.SyntaxBracketLr() } { - p.SetState(1357) + p.SetState(1365) p.ColumnDefinitionList() } { - p.SetState(1358) + p.SetState(1366) p.SyntaxBracketRr() } - p.SetState(1360) + p.SetState(1368) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -18856,7 +18861,7 @@ func (p *CqlParser) CreateTable() (localctx ICreateTableContext) { if _la == CqlParserK_WITH { { - p.SetState(1359) + p.SetState(1367) p.WithElement() } @@ -18998,10 +19003,10 @@ func (p *CqlParser) WithElement() (localctx IWithElementContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1362) + p.SetState(1370) p.KwWith() } - p.SetState(1364) + p.SetState(1372) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -19010,12 +19015,12 @@ func (p *CqlParser) WithElement() (localctx IWithElementContext) { if _la == CqlParserOBJECT_NAME { { - p.SetState(1363) + p.SetState(1371) p.TableOptions() } } - p.SetState(1367) + p.SetState(1375) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -19024,7 +19029,7 @@ func (p *CqlParser) WithElement() (localctx IWithElementContext) { if _la == CqlParserK_CLUSTERING { { - p.SetState(1366) + p.SetState(1374) p.ClusteringOrder() } @@ -19234,26 +19239,26 @@ func (p *CqlParser) ClusteringOrder() (localctx IClusteringOrderContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1369) + p.SetState(1377) p.KwClustering() } { - p.SetState(1370) + p.SetState(1378) p.KwOrder() } { - p.SetState(1371) + p.SetState(1379) p.KwBy() } { - p.SetState(1372) + p.SetState(1380) p.SyntaxBracketLr() } { - p.SetState(1373) + p.SetState(1381) p.Column() } - p.SetState(1375) + p.SetState(1383) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -19262,13 +19267,13 @@ func (p *CqlParser) ClusteringOrder() (localctx IClusteringOrderContext) { if _la == CqlParserK_ASC || _la == CqlParserK_DESC { { - p.SetState(1374) + p.SetState(1382) p.OrderDirection() } } { - p.SetState(1377) + p.SetState(1385) p.SyntaxBracketRr() } @@ -19443,10 +19448,10 @@ func (p *CqlParser) TableOptions() (localctx ITableOptionsContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1379) + p.SetState(1387) p.TableOptionItem() } - p.SetState(1385) + p.SetState(1393) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -19458,16 +19463,16 @@ func (p *CqlParser) TableOptions() (localctx ITableOptionsContext) { for _alt != 2 && _alt != antlr.ATNInvalidAltNumber { if _alt == 1 { { - p.SetState(1380) + p.SetState(1388) p.KwAnd() } { - p.SetState(1381) + p.SetState(1389) p.TableOptionItem() } } - p.SetState(1387) + p.SetState(1395) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -19615,7 +19620,7 @@ func (s *TableOptionItemContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) TableOptionItem() (localctx ITableOptionItemContext) { localctx = NewTableOptionItemContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 160, CqlParserRULE_tableOptionItem) - p.SetState(1396) + p.SetState(1404) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -19625,11 +19630,11 @@ func (p *CqlParser) TableOptionItem() (localctx ITableOptionItemContext) { case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(1388) + p.SetState(1396) p.TableOptionName() } { - p.SetState(1389) + p.SetState(1397) p.Match(CqlParserOPERATOR_EQ) if p.HasError() { // Recognition error - abort rule @@ -19637,18 +19642,18 @@ func (p *CqlParser) TableOptionItem() (localctx ITableOptionItemContext) { } } { - p.SetState(1390) + p.SetState(1398) p.TableOptionValue() } case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(1392) + p.SetState(1400) p.TableOptionName() } { - p.SetState(1393) + p.SetState(1401) p.Match(CqlParserOPERATOR_EQ) if p.HasError() { // Recognition error - abort rule @@ -19656,7 +19661,7 @@ func (p *CqlParser) TableOptionItem() (localctx ITableOptionItemContext) { } } { - p.SetState(1394) + p.SetState(1402) p.OptionHash() } @@ -19752,7 +19757,7 @@ func (p *CqlParser) TableOptionName() (localctx ITableOptionNameContext) { p.EnterRule(localctx, 162, CqlParserRULE_tableOptionName) p.EnterOuterAlt(localctx, 1) { - p.SetState(1398) + p.SetState(1406) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -19875,7 +19880,7 @@ func (s *TableOptionValueContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) TableOptionValue() (localctx ITableOptionValueContext) { localctx = NewTableOptionValueContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 164, CqlParserRULE_tableOptionValue) - p.SetState(1402) + p.SetState(1410) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -19885,14 +19890,14 @@ func (p *CqlParser) TableOptionValue() (localctx ITableOptionValueContext) { case CqlParserSTRING_LITERAL: p.EnterOuterAlt(localctx, 1) { - p.SetState(1400) + p.SetState(1408) p.StringLiteral() } case CqlParserDECIMAL_LITERAL, CqlParserFLOAT_LITERAL: p.EnterOuterAlt(localctx, 2) { - p.SetState(1401) + p.SetState(1409) p.FloatLiteral() } @@ -20106,14 +20111,14 @@ func (p *CqlParser) OptionHash() (localctx IOptionHashContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1404) + p.SetState(1412) p.SyntaxBracketLc() } { - p.SetState(1405) + p.SetState(1413) p.OptionHashItem() } - p.SetState(1411) + p.SetState(1419) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -20122,15 +20127,15 @@ func (p *CqlParser) OptionHash() (localctx IOptionHashContext) { for _la == CqlParserCOMMA { { - p.SetState(1406) + p.SetState(1414) p.SyntaxComma() } { - p.SetState(1407) + p.SetState(1415) p.OptionHashItem() } - p.SetState(1413) + p.SetState(1421) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -20138,7 +20143,7 @@ func (p *CqlParser) OptionHash() (localctx IOptionHashContext) { _la = p.GetTokenStream().LA(1) } { - p.SetState(1414) + p.SetState(1422) p.SyntaxBracketRc() } @@ -20264,11 +20269,11 @@ func (p *CqlParser) OptionHashItem() (localctx IOptionHashItemContext) { p.EnterRule(localctx, 168, CqlParserRULE_optionHashItem) p.EnterOuterAlt(localctx, 1) { - p.SetState(1416) + p.SetState(1424) p.OptionHashKey() } { - p.SetState(1417) + p.SetState(1425) p.Match(CqlParserCOLON) if p.HasError() { // Recognition error - abort rule @@ -20276,7 +20281,7 @@ func (p *CqlParser) OptionHashItem() (localctx IOptionHashItemContext) { } } { - p.SetState(1418) + p.SetState(1426) p.OptionHashValue() } @@ -20380,7 +20385,7 @@ func (p *CqlParser) OptionHashKey() (localctx IOptionHashKeyContext) { p.EnterRule(localctx, 170, CqlParserRULE_optionHashKey) p.EnterOuterAlt(localctx, 1) { - p.SetState(1420) + p.SetState(1428) p.StringLiteral() } @@ -20499,7 +20504,7 @@ func (s *OptionHashValueContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) OptionHashValue() (localctx IOptionHashValueContext) { localctx = NewOptionHashValueContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 172, CqlParserRULE_optionHashValue) - p.SetState(1424) + p.SetState(1432) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -20509,14 +20514,14 @@ func (p *CqlParser) OptionHashValue() (localctx IOptionHashValueContext) { case CqlParserSTRING_LITERAL: p.EnterOuterAlt(localctx, 1) { - p.SetState(1422) + p.SetState(1430) p.StringLiteral() } case CqlParserDECIMAL_LITERAL, CqlParserFLOAT_LITERAL: p.EnterOuterAlt(localctx, 2) { - p.SetState(1423) + p.SetState(1431) p.FloatLiteral() } @@ -20715,11 +20720,11 @@ func (p *CqlParser) ColumnDefinitionList() (localctx IColumnDefinitionListContex p.EnterOuterAlt(localctx, 1) { - p.SetState(1426) + p.SetState(1434) p.ColumnDefinition() } - p.SetState(1432) + p.SetState(1440) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -20731,16 +20736,16 @@ func (p *CqlParser) ColumnDefinitionList() (localctx IColumnDefinitionListContex for _alt != 2 && _alt != antlr.ATNInvalidAltNumber { if _alt == 1 { { - p.SetState(1427) + p.SetState(1435) p.SyntaxComma() } { - p.SetState(1428) + p.SetState(1436) p.ColumnDefinition() } } - p.SetState(1434) + p.SetState(1442) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -20750,7 +20755,7 @@ func (p *CqlParser) ColumnDefinitionList() (localctx IColumnDefinitionListContex goto errorExit } } - p.SetState(1438) + p.SetState(1446) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -20759,11 +20764,11 @@ func (p *CqlParser) ColumnDefinitionList() (localctx IColumnDefinitionListContex if _la == CqlParserCOMMA { { - p.SetState(1435) + p.SetState(1443) p.SyntaxComma() } { - p.SetState(1436) + p.SetState(1444) p.PrimaryKeyElement() } @@ -20905,14 +20910,14 @@ func (p *CqlParser) ColumnDefinition() (localctx IColumnDefinitionContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1440) + p.SetState(1448) p.Column() } { - p.SetState(1441) + p.SetState(1449) p.DataType() } - p.SetState(1443) + p.SetState(1451) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -20921,7 +20926,7 @@ func (p *CqlParser) ColumnDefinition() (localctx IColumnDefinitionContext) { if _la == CqlParserK_PRIMARY { { - p.SetState(1442) + p.SetState(1450) p.PrimaryKeyColumn() } @@ -21044,11 +21049,11 @@ func (p *CqlParser) PrimaryKeyColumn() (localctx IPrimaryKeyColumnContext) { p.EnterRule(localctx, 178, CqlParserRULE_primaryKeyColumn) p.EnterOuterAlt(localctx, 1) { - p.SetState(1445) + p.SetState(1453) p.KwPrimary() } { - p.SetState(1446) + p.SetState(1454) p.KwKey() } @@ -21220,23 +21225,23 @@ func (p *CqlParser) PrimaryKeyElement() (localctx IPrimaryKeyElementContext) { p.EnterRule(localctx, 180, CqlParserRULE_primaryKeyElement) p.EnterOuterAlt(localctx, 1) { - p.SetState(1448) + p.SetState(1456) p.KwPrimary() } { - p.SetState(1449) + p.SetState(1457) p.KwKey() } { - p.SetState(1450) + p.SetState(1458) p.SyntaxBracketLr() } { - p.SetState(1451) + p.SetState(1459) p.PrimaryKeyDefinition() } { - p.SetState(1452) + p.SetState(1460) p.SyntaxBracketRr() } @@ -21372,7 +21377,7 @@ func (s *PrimaryKeyDefinitionContext) ExitRule(listener antlr.ParseTreeListener) func (p *CqlParser) PrimaryKeyDefinition() (localctx IPrimaryKeyDefinitionContext) { localctx = NewPrimaryKeyDefinitionContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 182, CqlParserRULE_primaryKeyDefinition) - p.SetState(1457) + p.SetState(1465) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -21382,21 +21387,21 @@ func (p *CqlParser) PrimaryKeyDefinition() (localctx IPrimaryKeyDefinitionContex case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(1454) + p.SetState(1462) p.SinglePrimaryKey() } case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(1455) + p.SetState(1463) p.CompoundKey() } case 3: p.EnterOuterAlt(localctx, 3) { - p.SetState(1456) + p.SetState(1464) p.CompositeKey() } @@ -21504,7 +21509,7 @@ func (p *CqlParser) SinglePrimaryKey() (localctx ISinglePrimaryKeyContext) { p.EnterRule(localctx, 184, CqlParserRULE_singlePrimaryKey) p.EnterOuterAlt(localctx, 1) { - p.SetState(1459) + p.SetState(1467) p.Column() } @@ -21642,16 +21647,16 @@ func (p *CqlParser) CompoundKey() (localctx ICompoundKeyContext) { p.EnterRule(localctx, 186, CqlParserRULE_compoundKey) p.EnterOuterAlt(localctx, 1) { - p.SetState(1461) + p.SetState(1469) p.PartitionKey() } { - p.SetState(1462) + p.SetState(1470) p.SyntaxComma() } { - p.SetState(1463) + p.SetState(1471) p.ClusteringKeyList() } @@ -21823,24 +21828,24 @@ func (p *CqlParser) CompositeKey() (localctx ICompositeKeyContext) { p.EnterRule(localctx, 188, CqlParserRULE_compositeKey) p.EnterOuterAlt(localctx, 1) { - p.SetState(1465) + p.SetState(1473) p.SyntaxBracketLr() } { - p.SetState(1466) + p.SetState(1474) p.PartitionKeyList() } { - p.SetState(1467) + p.SetState(1475) p.SyntaxBracketRr() } { - p.SetState(1468) + p.SetState(1476) p.SyntaxComma() } { - p.SetState(1469) + p.SetState(1477) p.ClusteringKeyList() } @@ -22015,11 +22020,11 @@ func (p *CqlParser) PartitionKeyList() (localctx IPartitionKeyListContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1471) + p.SetState(1479) p.PartitionKey() } - p.SetState(1477) + p.SetState(1485) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -22028,15 +22033,15 @@ func (p *CqlParser) PartitionKeyList() (localctx IPartitionKeyListContext) { for _la == CqlParserCOMMA { { - p.SetState(1472) + p.SetState(1480) p.SyntaxComma() } { - p.SetState(1473) + p.SetState(1481) p.PartitionKey() } - p.SetState(1479) + p.SetState(1487) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -22215,11 +22220,11 @@ func (p *CqlParser) ClusteringKeyList() (localctx IClusteringKeyListContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1480) + p.SetState(1488) p.ClusteringKey() } - p.SetState(1486) + p.SetState(1494) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -22228,15 +22233,15 @@ func (p *CqlParser) ClusteringKeyList() (localctx IClusteringKeyListContext) { for _la == CqlParserCOMMA { { - p.SetState(1481) + p.SetState(1489) p.SyntaxComma() } { - p.SetState(1482) + p.SetState(1490) p.ClusteringKey() } - p.SetState(1488) + p.SetState(1496) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -22344,7 +22349,7 @@ func (p *CqlParser) PartitionKey() (localctx IPartitionKeyContext) { p.EnterRule(localctx, 194, CqlParserRULE_partitionKey) p.EnterOuterAlt(localctx, 1) { - p.SetState(1489) + p.SetState(1497) p.Column() } @@ -22448,7 +22453,7 @@ func (p *CqlParser) ClusteringKey() (localctx IClusteringKeyContext) { p.EnterRule(localctx, 196, CqlParserRULE_clusteringKey) p.EnterOuterAlt(localctx, 1) { - p.SetState(1491) + p.SetState(1499) p.Column() } @@ -22569,11 +22574,11 @@ func (p *CqlParser) ApplyBatch() (localctx IApplyBatchContext) { p.EnterRule(localctx, 198, CqlParserRULE_applyBatch) p.EnterOuterAlt(localctx, 1) { - p.SetState(1493) + p.SetState(1501) p.KwApply() } { - p.SetState(1494) + p.SetState(1502) p.KwBatch() } @@ -22730,10 +22735,10 @@ func (p *CqlParser) BeginBatch() (localctx IBeginBatchContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1496) + p.SetState(1504) p.KwBegin() } - p.SetState(1498) + p.SetState(1506) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -22742,16 +22747,16 @@ func (p *CqlParser) BeginBatch() (localctx IBeginBatchContext) { if _la == CqlParserK_LOGGED || _la == CqlParserK_UNLOGGED { { - p.SetState(1497) + p.SetState(1505) p.BatchType() } } { - p.SetState(1500) + p.SetState(1508) p.KwBatch() } - p.SetState(1502) + p.SetState(1510) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -22760,7 +22765,7 @@ func (p *CqlParser) BeginBatch() (localctx IBeginBatchContext) { if _la == CqlParserK_USING { { - p.SetState(1501) + p.SetState(1509) p.UsingTimestampSpec() } @@ -22881,7 +22886,7 @@ func (s *BatchTypeContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) BatchType() (localctx IBatchTypeContext) { localctx = NewBatchTypeContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 202, CqlParserRULE_batchType) - p.SetState(1506) + p.SetState(1514) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -22891,14 +22896,14 @@ func (p *CqlParser) BatchType() (localctx IBatchTypeContext) { case CqlParserK_LOGGED: p.EnterOuterAlt(localctx, 1) { - p.SetState(1504) + p.SetState(1512) p.KwLogged() } case CqlParserK_UNLOGGED: p.EnterOuterAlt(localctx, 2) { - p.SetState(1505) + p.SetState(1513) p.KwUnlogged() } @@ -23167,27 +23172,27 @@ func (p *CqlParser) AlterKeyspace() (localctx IAlterKeyspaceContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1508) + p.SetState(1516) p.KwAlter() } { - p.SetState(1509) + p.SetState(1517) p.KwKeyspace() } { - p.SetState(1510) + p.SetState(1518) p.Keyspace() } { - p.SetState(1511) + p.SetState(1519) p.KwWith() } { - p.SetState(1512) + p.SetState(1520) p.KwReplication() } { - p.SetState(1513) + p.SetState(1521) p.Match(CqlParserOPERATOR_EQ) if p.HasError() { // Recognition error - abort rule @@ -23195,18 +23200,18 @@ func (p *CqlParser) AlterKeyspace() (localctx IAlterKeyspaceContext) { } } { - p.SetState(1514) + p.SetState(1522) p.SyntaxBracketLc() } { - p.SetState(1515) + p.SetState(1523) p.ReplicationList() } { - p.SetState(1516) + p.SetState(1524) p.SyntaxBracketRc() } - p.SetState(1520) + p.SetState(1528) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -23215,11 +23220,11 @@ func (p *CqlParser) AlterKeyspace() (localctx IAlterKeyspaceContext) { if _la == CqlParserK_AND { { - p.SetState(1517) + p.SetState(1525) p.KwAnd() } { - p.SetState(1518) + p.SetState(1526) p.DurableWrites() } @@ -23396,11 +23401,11 @@ func (p *CqlParser) ReplicationList() (localctx IReplicationListContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1522) + p.SetState(1530) p.ReplicationListItem() } - p.SetState(1528) + p.SetState(1536) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -23409,15 +23414,15 @@ func (p *CqlParser) ReplicationList() (localctx IReplicationListContext) { for _la == CqlParserCOMMA { { - p.SetState(1523) + p.SetState(1531) p.SyntaxComma() } { - p.SetState(1524) + p.SetState(1532) p.ReplicationListItem() } - p.SetState(1530) + p.SetState(1538) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -23526,7 +23531,7 @@ func (s *ReplicationListItemContext) ExitRule(listener antlr.ParseTreeListener) func (p *CqlParser) ReplicationListItem() (localctx IReplicationListItemContext) { localctx = NewReplicationListItemContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 208, CqlParserRULE_replicationListItem) - p.SetState(1537) + p.SetState(1545) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -23536,7 +23541,7 @@ func (p *CqlParser) ReplicationListItem() (localctx IReplicationListItemContext) case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(1531) + p.SetState(1539) p.Match(CqlParserSTRING_LITERAL) if p.HasError() { // Recognition error - abort rule @@ -23544,7 +23549,7 @@ func (p *CqlParser) ReplicationListItem() (localctx IReplicationListItemContext) } } { - p.SetState(1532) + p.SetState(1540) p.Match(CqlParserCOLON) if p.HasError() { // Recognition error - abort rule @@ -23552,7 +23557,7 @@ func (p *CqlParser) ReplicationListItem() (localctx IReplicationListItemContext) } } { - p.SetState(1533) + p.SetState(1541) p.Match(CqlParserSTRING_LITERAL) if p.HasError() { // Recognition error - abort rule @@ -23563,7 +23568,7 @@ func (p *CqlParser) ReplicationListItem() (localctx IReplicationListItemContext) case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(1534) + p.SetState(1542) p.Match(CqlParserSTRING_LITERAL) if p.HasError() { // Recognition error - abort rule @@ -23571,7 +23576,7 @@ func (p *CqlParser) ReplicationListItem() (localctx IReplicationListItemContext) } } { - p.SetState(1535) + p.SetState(1543) p.Match(CqlParserCOLON) if p.HasError() { // Recognition error - abort rule @@ -23579,7 +23584,7 @@ func (p *CqlParser) ReplicationListItem() (localctx IReplicationListItemContext) } } { - p.SetState(1536) + p.SetState(1544) p.Match(CqlParserDECIMAL_LITERAL) if p.HasError() { // Recognition error - abort rule @@ -23713,11 +23718,11 @@ func (p *CqlParser) DurableWrites() (localctx IDurableWritesContext) { p.EnterRule(localctx, 210, CqlParserRULE_durableWrites) p.EnterOuterAlt(localctx, 1) { - p.SetState(1539) + p.SetState(1547) p.KwDurableWrites() } { - p.SetState(1540) + p.SetState(1548) p.Match(CqlParserOPERATOR_EQ) if p.HasError() { // Recognition error - abort rule @@ -23725,7 +23730,7 @@ func (p *CqlParser) DurableWrites() (localctx IDurableWritesContext) { } } { - p.SetState(1541) + p.SetState(1549) p.BooleanLiteral() } @@ -23846,11 +23851,11 @@ func (p *CqlParser) Use_() (localctx IUse_Context) { p.EnterRule(localctx, 212, CqlParserRULE_use_) p.EnterOuterAlt(localctx, 1) { - p.SetState(1543) + p.SetState(1551) p.KwUse() } { - p.SetState(1544) + p.SetState(1552) p.Keyspace() } @@ -23990,10 +23995,10 @@ func (p *CqlParser) Truncate() (localctx ITruncateContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1546) + p.SetState(1554) p.KwTruncate() } - p.SetState(1548) + p.SetState(1556) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -24002,13 +24007,13 @@ func (p *CqlParser) Truncate() (localctx ITruncateContext) { if _la == CqlParserK_TABLE { { - p.SetState(1547) + p.SetState(1555) p.KwTable() } } { - p.SetState(1550) + p.SetState(1558) p.TableSpec() } @@ -24250,14 +24255,14 @@ func (p *CqlParser) CreateIndex() (localctx ICreateIndexContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1552) + p.SetState(1560) p.KwCreate() } { - p.SetState(1553) + p.SetState(1561) p.KwIndex() } - p.SetState(1555) + p.SetState(1563) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -24266,12 +24271,12 @@ func (p *CqlParser) CreateIndex() (localctx ICreateIndexContext) { if _la == CqlParserK_IF { { - p.SetState(1554) + p.SetState(1562) p.IfNotExist() } } - p.SetState(1558) + p.SetState(1566) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -24280,29 +24285,29 @@ func (p *CqlParser) CreateIndex() (localctx ICreateIndexContext) { if _la == CqlParserSTRING_LITERAL || _la == CqlParserOBJECT_NAME { { - p.SetState(1557) + p.SetState(1565) p.IndexName() } } { - p.SetState(1560) + p.SetState(1568) p.KwOn() } { - p.SetState(1561) + p.SetState(1569) p.TableSpec() } { - p.SetState(1562) + p.SetState(1570) p.SyntaxBracketLr() } { - p.SetState(1563) + p.SetState(1571) p.IndexColumnSpec() } { - p.SetState(1564) + p.SetState(1572) p.SyntaxBracketRr() } @@ -24409,7 +24414,7 @@ func (s *IndexNameContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) IndexName() (localctx IIndexNameContext) { localctx = NewIndexNameContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 218, CqlParserRULE_indexName) - p.SetState(1568) + p.SetState(1576) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -24419,7 +24424,7 @@ func (p *CqlParser) IndexName() (localctx IIndexNameContext) { case CqlParserOBJECT_NAME: p.EnterOuterAlt(localctx, 1) { - p.SetState(1566) + p.SetState(1574) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -24430,7 +24435,7 @@ func (p *CqlParser) IndexName() (localctx IIndexNameContext) { case CqlParserSTRING_LITERAL: p.EnterOuterAlt(localctx, 2) { - p.SetState(1567) + p.SetState(1575) p.StringLiteral() } @@ -24588,7 +24593,7 @@ func (s *IndexColumnSpecContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) IndexColumnSpec() (localctx IIndexColumnSpecContext) { localctx = NewIndexColumnSpecContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 220, CqlParserRULE_indexColumnSpec) - p.SetState(1574) + p.SetState(1582) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -24598,28 +24603,28 @@ func (p *CqlParser) IndexColumnSpec() (localctx IIndexColumnSpecContext) { case CqlParserDQUOTE, CqlParserK_KEY, CqlParserK_TYPE, CqlParserOBJECT_NAME: p.EnterOuterAlt(localctx, 1) { - p.SetState(1570) + p.SetState(1578) p.Column() } case CqlParserK_KEYS: p.EnterOuterAlt(localctx, 2) { - p.SetState(1571) + p.SetState(1579) p.IndexKeysSpec() } case CqlParserK_ENTRIES: p.EnterOuterAlt(localctx, 3) { - p.SetState(1572) + p.SetState(1580) p.IndexEntriesSSpec() } case CqlParserK_FULL: p.EnterOuterAlt(localctx, 4) { - p.SetState(1573) + p.SetState(1581) p.IndexFullSpec() } @@ -24767,15 +24772,15 @@ func (p *CqlParser) IndexKeysSpec() (localctx IIndexKeysSpecContext) { p.EnterRule(localctx, 222, CqlParserRULE_indexKeysSpec) p.EnterOuterAlt(localctx, 1) { - p.SetState(1576) + p.SetState(1584) p.KwKeys() } { - p.SetState(1577) + p.SetState(1585) p.SyntaxBracketLr() } { - p.SetState(1578) + p.SetState(1586) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -24783,7 +24788,7 @@ func (p *CqlParser) IndexKeysSpec() (localctx IIndexKeysSpecContext) { } } { - p.SetState(1579) + p.SetState(1587) p.SyntaxBracketRr() } @@ -24926,15 +24931,15 @@ func (p *CqlParser) IndexEntriesSSpec() (localctx IIndexEntriesSSpecContext) { p.EnterRule(localctx, 224, CqlParserRULE_indexEntriesSSpec) p.EnterOuterAlt(localctx, 1) { - p.SetState(1581) + p.SetState(1589) p.KwEntries() } { - p.SetState(1582) + p.SetState(1590) p.SyntaxBracketLr() } { - p.SetState(1583) + p.SetState(1591) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -24942,7 +24947,7 @@ func (p *CqlParser) IndexEntriesSSpec() (localctx IIndexEntriesSSpecContext) { } } { - p.SetState(1584) + p.SetState(1592) p.SyntaxBracketRr() } @@ -25085,15 +25090,15 @@ func (p *CqlParser) IndexFullSpec() (localctx IIndexFullSpecContext) { p.EnterRule(localctx, 226, CqlParserRULE_indexFullSpec) p.EnterOuterAlt(localctx, 1) { - p.SetState(1586) + p.SetState(1594) p.KwFull() } { - p.SetState(1587) + p.SetState(1595) p.SyntaxBracketLr() } { - p.SetState(1588) + p.SetState(1596) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -25101,7 +25106,7 @@ func (p *CqlParser) IndexFullSpec() (localctx IIndexFullSpecContext) { } } { - p.SetState(1589) + p.SetState(1597) p.SyntaxBracketRr() } @@ -25342,7 +25347,7 @@ func (p *CqlParser) Delete_() (localctx IDelete_Context) { var _la int p.EnterOuterAlt(localctx, 1) - p.SetState(1592) + p.SetState(1600) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -25351,16 +25356,16 @@ func (p *CqlParser) Delete_() (localctx IDelete_Context) { if _la == CqlParserK_BEGIN { { - p.SetState(1591) + p.SetState(1599) p.BeginBatch() } } { - p.SetState(1594) + p.SetState(1602) p.KwDelete() } - p.SetState(1596) + p.SetState(1604) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -25369,16 +25374,16 @@ func (p *CqlParser) Delete_() (localctx IDelete_Context) { if _la == CqlParserDQUOTE || _la == CqlParserK_KEY || _la == CqlParserK_TYPE || _la == CqlParserOBJECT_NAME { { - p.SetState(1595) + p.SetState(1603) p.DeleteColumnList() } } { - p.SetState(1598) + p.SetState(1606) p.FromSpec() } - p.SetState(1600) + p.SetState(1608) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -25387,21 +25392,21 @@ func (p *CqlParser) Delete_() (localctx IDelete_Context) { if _la == CqlParserK_USING { { - p.SetState(1599) + p.SetState(1607) p.UsingTimestampSpec() } } { - p.SetState(1602) + p.SetState(1610) p.WhereSpec() } - p.SetState(1605) + p.SetState(1613) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 113, p.GetParserRuleContext()) == 1 { { - p.SetState(1603) + p.SetState(1611) p.IfExist() } @@ -25409,19 +25414,19 @@ func (p *CqlParser) Delete_() (localctx IDelete_Context) { goto errorExit } else if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 113, p.GetParserRuleContext()) == 2 { { - p.SetState(1604) + p.SetState(1612) p.IfSpec() } } else if p.HasError() { // JIM goto errorExit } - p.SetState(1608) + p.SetState(1616) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 114, p.GetParserRuleContext()) == 1 { { - p.SetState(1607) + p.SetState(1615) p.StatementSeparator() } @@ -25600,11 +25605,11 @@ func (p *CqlParser) DeleteColumnList() (localctx IDeleteColumnListContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1610) + p.SetState(1618) p.DeleteColumnItem() } - p.SetState(1616) + p.SetState(1624) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -25613,15 +25618,15 @@ func (p *CqlParser) DeleteColumnList() (localctx IDeleteColumnListContext) { for _la == CqlParserCOMMA { { - p.SetState(1611) + p.SetState(1619) p.SyntaxComma() } { - p.SetState(1612) + p.SetState(1620) p.DeleteColumnItem() } - p.SetState(1618) + p.SetState(1626) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -25763,7 +25768,7 @@ func (p *CqlParser) DeleteColumnItem() (localctx IDeleteColumnItemContext) { p.EnterRule(localctx, 232, CqlParserRULE_deleteColumnItem) var _la int - p.SetState(1627) + p.SetState(1635) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -25773,10 +25778,10 @@ func (p *CqlParser) DeleteColumnItem() (localctx IDeleteColumnItemContext) { case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(1619) + p.SetState(1627) p.SelectColumn() } - p.SetState(1621) + p.SetState(1629) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -25785,7 +25790,7 @@ func (p *CqlParser) DeleteColumnItem() (localctx IDeleteColumnItemContext) { if _la == CqlParserK_AS { { - p.SetState(1620) + p.SetState(1628) p.AsSpec() } @@ -25794,10 +25799,10 @@ func (p *CqlParser) DeleteColumnItem() (localctx IDeleteColumnItemContext) { case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(1623) + p.SetState(1631) p.SelectIndex() } - p.SetState(1625) + p.SetState(1633) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -25806,7 +25811,7 @@ func (p *CqlParser) DeleteColumnItem() (localctx IDeleteColumnItemContext) { if _la == CqlParserK_AS { { - p.SetState(1624) + p.SetState(1632) p.AsSpec() } @@ -26070,7 +26075,7 @@ func (p *CqlParser) Update() (localctx IUpdateContext) { var _la int p.EnterOuterAlt(localctx, 1) - p.SetState(1630) + p.SetState(1638) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -26079,20 +26084,20 @@ func (p *CqlParser) Update() (localctx IUpdateContext) { if _la == CqlParserK_BEGIN { { - p.SetState(1629) + p.SetState(1637) p.BeginBatch() } } { - p.SetState(1632) + p.SetState(1640) p.KwUpdate() } { - p.SetState(1633) + p.SetState(1641) p.TableSpec() } - p.SetState(1635) + p.SetState(1643) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -26101,29 +26106,29 @@ func (p *CqlParser) Update() (localctx IUpdateContext) { if _la == CqlParserK_USING { { - p.SetState(1634) + p.SetState(1642) p.UsingTtlTimestamp() } } { - p.SetState(1637) + p.SetState(1645) p.KwSet() } { - p.SetState(1638) + p.SetState(1646) p.Assignments() } { - p.SetState(1639) + p.SetState(1647) p.WhereSpec() } - p.SetState(1642) + p.SetState(1650) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 121, p.GetParserRuleContext()) == 1 { { - p.SetState(1640) + p.SetState(1648) p.IfExist() } @@ -26131,19 +26136,19 @@ func (p *CqlParser) Update() (localctx IUpdateContext) { goto errorExit } else if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 121, p.GetParserRuleContext()) == 2 { { - p.SetState(1641) + p.SetState(1649) p.IfSpec() } } else if p.HasError() { // JIM goto errorExit } - p.SetState(1645) + p.SetState(1653) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 122, p.GetParserRuleContext()) == 1 { { - p.SetState(1644) + p.SetState(1652) p.StatementSeparator() } @@ -26268,11 +26273,11 @@ func (p *CqlParser) IfSpec() (localctx IIfSpecContext) { p.EnterRule(localctx, 236, CqlParserRULE_ifSpec) p.EnterOuterAlt(localctx, 1) { - p.SetState(1647) + p.SetState(1655) p.KwIf() } { - p.SetState(1648) + p.SetState(1656) p.IfConditionList() } @@ -26447,11 +26452,11 @@ func (p *CqlParser) IfConditionList() (localctx IIfConditionListContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1650) + p.SetState(1658) p.IfCondition() } - p.SetState(1656) + p.SetState(1664) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -26460,15 +26465,15 @@ func (p *CqlParser) IfConditionList() (localctx IIfConditionListContext) { for _la == CqlParserK_AND { { - p.SetState(1651) + p.SetState(1659) p.KwAnd() } { - p.SetState(1652) + p.SetState(1660) p.IfCondition() } - p.SetState(1658) + p.SetState(1666) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -26586,7 +26591,7 @@ func (p *CqlParser) IfCondition() (localctx IIfConditionContext) { p.EnterRule(localctx, 240, CqlParserRULE_ifCondition) p.EnterOuterAlt(localctx, 1) { - p.SetState(1659) + p.SetState(1667) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -26594,7 +26599,7 @@ func (p *CqlParser) IfCondition() (localctx IIfConditionContext) { } } { - p.SetState(1660) + p.SetState(1668) p.Match(CqlParserOPERATOR_EQ) if p.HasError() { // Recognition error - abort rule @@ -26602,7 +26607,7 @@ func (p *CqlParser) IfCondition() (localctx IIfConditionContext) { } } { - p.SetState(1661) + p.SetState(1669) p.Constant() } @@ -26777,11 +26782,11 @@ func (p *CqlParser) Assignments() (localctx IAssignmentsContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1663) + p.SetState(1671) p.AssignmentElement() } - p.SetState(1669) + p.SetState(1677) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -26790,15 +26795,15 @@ func (p *CqlParser) Assignments() (localctx IAssignmentsContext) { for _la == CqlParserCOMMA { { - p.SetState(1664) + p.SetState(1672) p.SyntaxComma() } { - p.SetState(1665) + p.SetState(1673) p.AssignmentElement() } - p.SetState(1671) + p.SetState(1679) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -26955,7 +26960,7 @@ func (s *AssignmentElementContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) AssignmentElement() (localctx IAssignmentElementContext) { localctx = NewAssignmentElementContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 244, CqlParserRULE_assignmentElement) - p.SetState(1676) + p.SetState(1684) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -26965,28 +26970,28 @@ func (p *CqlParser) AssignmentElement() (localctx IAssignmentElementContext) { case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(1672) + p.SetState(1680) p.AssignmentAppend() } case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(1673) + p.SetState(1681) p.AssignmentPrepend() } case 3: p.EnterOuterAlt(localctx, 3) { - p.SetState(1674) + p.SetState(1682) p.AssignmentEquals() } case 4: p.EnterOuterAlt(localctx, 4) { - p.SetState(1675) + p.SetState(1683) p.AssignmentIndex() } @@ -27116,11 +27121,11 @@ func (p *CqlParser) AssignmentEquals() (localctx IAssignmentEqualsContext) { p.EnterRule(localctx, 246, CqlParserRULE_assignmentEquals) p.EnterOuterAlt(localctx, 1) { - p.SetState(1678) + p.SetState(1686) p.Column() } { - p.SetState(1679) + p.SetState(1687) p.Match(CqlParserOPERATOR_EQ) if p.HasError() { // Recognition error - abort rule @@ -27128,7 +27133,7 @@ func (p *CqlParser) AssignmentEquals() (localctx IAssignmentEqualsContext) { } } { - p.SetState(1680) + p.SetState(1688) p.ValueAny() } @@ -27276,11 +27281,11 @@ func (p *CqlParser) AssignmentPrepend() (localctx IAssignmentPrependContext) { p.EnterRule(localctx, 248, CqlParserRULE_assignmentPrepend) p.EnterOuterAlt(localctx, 1) { - p.SetState(1682) + p.SetState(1690) p.Column() } { - p.SetState(1683) + p.SetState(1691) p.Match(CqlParserOPERATOR_EQ) if p.HasError() { // Recognition error - abort rule @@ -27288,15 +27293,15 @@ func (p *CqlParser) AssignmentPrepend() (localctx IAssignmentPrependContext) { } } { - p.SetState(1684) + p.SetState(1692) p.ValueAny() } { - p.SetState(1685) + p.SetState(1693) p.ArithmeticOperator() } { - p.SetState(1686) + p.SetState(1694) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -27448,11 +27453,11 @@ func (p *CqlParser) AssignmentAppend() (localctx IAssignmentAppendContext) { p.EnterRule(localctx, 250, CqlParserRULE_assignmentAppend) p.EnterOuterAlt(localctx, 1) { - p.SetState(1688) + p.SetState(1696) p.Column() } { - p.SetState(1689) + p.SetState(1697) p.Match(CqlParserOPERATOR_EQ) if p.HasError() { // Recognition error - abort rule @@ -27460,7 +27465,7 @@ func (p *CqlParser) AssignmentAppend() (localctx IAssignmentAppendContext) { } } { - p.SetState(1690) + p.SetState(1698) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -27468,11 +27473,11 @@ func (p *CqlParser) AssignmentAppend() (localctx IAssignmentAppendContext) { } } { - p.SetState(1691) + p.SetState(1699) p.ArithmeticOperator() } { - p.SetState(1692) + p.SetState(1700) p.ValueAny() } @@ -27610,15 +27615,15 @@ func (p *CqlParser) IndexOrKeyAccess() (localctx IIndexOrKeyAccessContext) { p.EnterRule(localctx, 252, CqlParserRULE_indexOrKeyAccess) p.EnterOuterAlt(localctx, 1) { - p.SetState(1694) + p.SetState(1702) p.SyntaxBracketLs() } { - p.SetState(1695) + p.SetState(1703) p.Constant() } { - p.SetState(1696) + p.SetState(1704) p.SyntaxBracketRs() } @@ -27761,15 +27766,15 @@ func (p *CqlParser) AssignmentIndex() (localctx IAssignmentIndexContext) { p.EnterRule(localctx, 254, CqlParserRULE_assignmentIndex) p.EnterOuterAlt(localctx, 1) { - p.SetState(1698) + p.SetState(1706) p.Column() } { - p.SetState(1699) + p.SetState(1707) p.IndexOrKeyAccess() } { - p.SetState(1700) + p.SetState(1708) p.Match(CqlParserOPERATOR_EQ) if p.HasError() { // Recognition error - abort rule @@ -27777,7 +27782,7 @@ func (p *CqlParser) AssignmentIndex() (localctx IAssignmentIndexContext) { } } { - p.SetState(1701) + p.SetState(1709) p.Constant() } @@ -27986,10 +27991,10 @@ func (p *CqlParser) ValueSet() (localctx IValueSetContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1703) + p.SetState(1711) p.SyntaxBracketLc() } - p.SetState(1713) + p.SetState(1721) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -27998,10 +28003,10 @@ func (p *CqlParser) ValueSet() (localctx IValueSetContext) { if _la == CqlParserK_FALSE || _la == CqlParserK_NULL || ((int64((_la-131)) & ^0x3f) == 0 && ((int64(1)<<(_la-131))&127405909868545) != 0) { { - p.SetState(1704) + p.SetState(1712) p.Constant() } - p.SetState(1710) + p.SetState(1718) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -28010,15 +28015,15 @@ func (p *CqlParser) ValueSet() (localctx IValueSetContext) { for _la == CqlParserCOMMA { { - p.SetState(1705) + p.SetState(1713) p.SyntaxComma() } { - p.SetState(1706) + p.SetState(1714) p.Constant() } - p.SetState(1712) + p.SetState(1720) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -28028,7 +28033,7 @@ func (p *CqlParser) ValueSet() (localctx IValueSetContext) { } { - p.SetState(1715) + p.SetState(1723) p.SyntaxBracketRc() } @@ -28280,24 +28285,24 @@ func (p *CqlParser) ValueMap() (localctx IValueMapContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1717) + p.SetState(1725) p.SyntaxBracketLc() } { - p.SetState(1718) + p.SetState(1726) p.Constant() } { - p.SetState(1719) + p.SetState(1727) p.SyntaxColon() } { - p.SetState(1720) + p.SetState(1728) p.Constant() } - p.SetState(1729) + p.SetState(1737) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -28306,23 +28311,23 @@ func (p *CqlParser) ValueMap() (localctx IValueMapContext) { for _la == CqlParserCOMMA { { - p.SetState(1722) + p.SetState(1730) p.SyntaxComma() } { - p.SetState(1723) + p.SetState(1731) p.Constant() } { - p.SetState(1724) + p.SetState(1732) p.SyntaxColon() } { - p.SetState(1725) + p.SetState(1733) p.Constant() } - p.SetState(1731) + p.SetState(1739) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -28330,7 +28335,7 @@ func (p *CqlParser) ValueMap() (localctx IValueMapContext) { _la = p.GetTokenStream().LA(1) } { - p.SetState(1732) + p.SetState(1740) p.SyntaxBracketRc() } @@ -28539,10 +28544,10 @@ func (p *CqlParser) ValueList() (localctx IValueListContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1734) + p.SetState(1742) p.SyntaxBracketLs() } - p.SetState(1744) + p.SetState(1752) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -28551,10 +28556,10 @@ func (p *CqlParser) ValueList() (localctx IValueListContext) { if _la == CqlParserK_FALSE || _la == CqlParserK_NULL || ((int64((_la-131)) & ^0x3f) == 0 && ((int64(1)<<(_la-131))&127405909868545) != 0) { { - p.SetState(1735) + p.SetState(1743) p.Constant() } - p.SetState(1741) + p.SetState(1749) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -28563,15 +28568,15 @@ func (p *CqlParser) ValueList() (localctx IValueListContext) { for _la == CqlParserCOMMA { { - p.SetState(1736) + p.SetState(1744) p.SyntaxComma() } { - p.SetState(1737) + p.SetState(1745) p.Constant() } - p.SetState(1743) + p.SetState(1751) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -28581,7 +28586,7 @@ func (p *CqlParser) ValueList() (localctx IValueListContext) { } { - p.SetState(1746) + p.SetState(1754) p.SyntaxBracketRs() } @@ -28680,7 +28685,7 @@ func (p *CqlParser) ArithmeticOperator() (localctx IArithmeticOperatorContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1748) + p.SetState(1756) _la = p.GetTokenStream().LA(1) if !(_la == CqlParserPLUS || _la == CqlParserMINUS) { @@ -28896,15 +28901,15 @@ func (p *CqlParser) AssignmentTuple() (localctx IAssignmentTupleContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1750) + p.SetState(1758) p.SyntaxBracketLr() } { - p.SetState(1751) + p.SetState(1759) p.Expression() } - p.SetState(1757) + p.SetState(1765) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -28913,15 +28918,15 @@ func (p *CqlParser) AssignmentTuple() (localctx IAssignmentTupleContext) { for _la == CqlParserCOMMA { { - p.SetState(1752) + p.SetState(1760) p.SyntaxComma() } { - p.SetState(1753) + p.SetState(1761) p.Expression() } - p.SetState(1759) + p.SetState(1767) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -28930,7 +28935,7 @@ func (p *CqlParser) AssignmentTuple() (localctx IAssignmentTupleContext) { } { - p.SetState(1760) + p.SetState(1768) p.SyntaxBracketRr() } @@ -29171,7 +29176,7 @@ func (p *CqlParser) Insert() (localctx IInsertContext) { var _la int p.EnterOuterAlt(localctx, 1) - p.SetState(1763) + p.SetState(1771) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -29180,24 +29185,24 @@ func (p *CqlParser) Insert() (localctx IInsertContext) { if _la == CqlParserK_BEGIN { { - p.SetState(1762) + p.SetState(1770) p.BeginBatch() } } { - p.SetState(1765) + p.SetState(1773) p.KwInsert() } { - p.SetState(1766) + p.SetState(1774) p.KwInto() } { - p.SetState(1767) + p.SetState(1775) p.TableSpec() } - p.SetState(1769) + p.SetState(1777) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -29206,16 +29211,16 @@ func (p *CqlParser) Insert() (localctx IInsertContext) { if _la == CqlParserLR_BRACKET { { - p.SetState(1768) + p.SetState(1776) p.InsertColumnSpec() } } { - p.SetState(1771) + p.SetState(1779) p.InsertValuesSpec() } - p.SetState(1773) + p.SetState(1781) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -29224,12 +29229,12 @@ func (p *CqlParser) Insert() (localctx IInsertContext) { if _la == CqlParserK_IF { { - p.SetState(1772) + p.SetState(1780) p.IfNotExist() } } - p.SetState(1776) + p.SetState(1784) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -29238,17 +29243,17 @@ func (p *CqlParser) Insert() (localctx IInsertContext) { if _la == CqlParserK_USING { { - p.SetState(1775) + p.SetState(1783) p.UsingTtlTimestamp() } } - p.SetState(1779) + p.SetState(1787) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 136, p.GetParserRuleContext()) == 1 { { - p.SetState(1778) + p.SetState(1786) p.StatementSeparator() } @@ -29405,7 +29410,7 @@ func (s *UsingTtlTimestampContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) UsingTtlTimestamp() (localctx IUsingTtlTimestampContext) { localctx = NewUsingTtlTimestampContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 268, CqlParserRULE_usingTtlTimestamp) - p.SetState(1797) + p.SetState(1805) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -29415,60 +29420,60 @@ func (p *CqlParser) UsingTtlTimestamp() (localctx IUsingTtlTimestampContext) { case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(1781) + p.SetState(1789) p.KwUsing() } { - p.SetState(1782) + p.SetState(1790) p.Ttl() } case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(1784) + p.SetState(1792) p.KwUsing() } { - p.SetState(1785) + p.SetState(1793) p.Ttl() } { - p.SetState(1786) + p.SetState(1794) p.KwAnd() } { - p.SetState(1787) + p.SetState(1795) p.Timestamp() } case 3: p.EnterOuterAlt(localctx, 3) { - p.SetState(1789) + p.SetState(1797) p.KwUsing() } { - p.SetState(1790) + p.SetState(1798) p.Timestamp() } case 4: p.EnterOuterAlt(localctx, 4) { - p.SetState(1792) + p.SetState(1800) p.KwUsing() } { - p.SetState(1793) + p.SetState(1801) p.Timestamp() } { - p.SetState(1794) + p.SetState(1802) p.KwAnd() } { - p.SetState(1795) + p.SetState(1803) p.Ttl() } @@ -29610,10 +29615,10 @@ func (p *CqlParser) Timestamp() (localctx ITimestampContext) { p.EnterRule(localctx, 270, CqlParserRULE_timestamp) p.EnterOuterAlt(localctx, 1) { - p.SetState(1799) + p.SetState(1807) p.KwTimestamp() } - p.SetState(1802) + p.SetState(1810) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -29622,13 +29627,13 @@ func (p *CqlParser) Timestamp() (localctx ITimestampContext) { switch p.GetTokenStream().LA(1) { case CqlParserQUESTION_MARK, CqlParserNAMED_MARK: { - p.SetState(1800) + p.SetState(1808) p.Marker() } case CqlParserDECIMAL_LITERAL: { - p.SetState(1801) + p.SetState(1809) p.DecimalLiteral() } @@ -29754,11 +29759,11 @@ func (p *CqlParser) Ttl() (localctx ITtlContext) { p.EnterRule(localctx, 272, CqlParserRULE_ttl) p.EnterOuterAlt(localctx, 1) { - p.SetState(1804) + p.SetState(1812) p.KwTtl() } { - p.SetState(1805) + p.SetState(1813) p.DecimalLiteral() } @@ -29879,11 +29884,11 @@ func (p *CqlParser) UsingTimestampSpec() (localctx IUsingTimestampSpecContext) { p.EnterRule(localctx, 274, CqlParserRULE_usingTimestampSpec) p.EnterOuterAlt(localctx, 1) { - p.SetState(1807) + p.SetState(1815) p.KwUsing() } { - p.SetState(1808) + p.SetState(1816) p.Timestamp() } @@ -30021,15 +30026,15 @@ func (p *CqlParser) IfNotExist() (localctx IIfNotExistContext) { p.EnterRule(localctx, 276, CqlParserRULE_ifNotExist) p.EnterOuterAlt(localctx, 1) { - p.SetState(1810) + p.SetState(1818) p.KwIf() } { - p.SetState(1811) + p.SetState(1819) p.KwNot() } { - p.SetState(1812) + p.SetState(1820) p.KwExists() } @@ -30150,11 +30155,11 @@ func (p *CqlParser) IfExist() (localctx IIfExistContext) { p.EnterRule(localctx, 278, CqlParserRULE_ifExist) p.EnterOuterAlt(localctx, 1) { - p.SetState(1814) + p.SetState(1822) p.KwIf() } { - p.SetState(1815) + p.SetState(1823) p.KwExists() } @@ -30317,7 +30322,7 @@ func (s *InsertValuesSpecContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) InsertValuesSpec() (localctx IInsertValuesSpecContext) { localctx = NewInsertValuesSpecContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 280, CqlParserRULE_insertValuesSpec) - p.SetState(1825) + p.SetState(1833) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -30327,11 +30332,11 @@ func (p *CqlParser) InsertValuesSpec() (localctx IInsertValuesSpecContext) { case CqlParserK_VALUES: p.EnterOuterAlt(localctx, 1) { - p.SetState(1817) + p.SetState(1825) p.KwValues() } { - p.SetState(1818) + p.SetState(1826) p.Match(CqlParserLR_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -30339,11 +30344,11 @@ func (p *CqlParser) InsertValuesSpec() (localctx IInsertValuesSpecContext) { } } { - p.SetState(1819) + p.SetState(1827) p.ValueListSpec() } { - p.SetState(1820) + p.SetState(1828) p.Match(CqlParserRR_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -30354,11 +30359,11 @@ func (p *CqlParser) InsertValuesSpec() (localctx IInsertValuesSpecContext) { case CqlParserK_JSON: p.EnterOuterAlt(localctx, 2) { - p.SetState(1822) + p.SetState(1830) p.KwJson() } { - p.SetState(1823) + p.SetState(1831) p.Constant() } @@ -30477,7 +30482,7 @@ func (p *CqlParser) InsertColumnSpec() (localctx IInsertColumnSpecContext) { p.EnterRule(localctx, 282, CqlParserRULE_insertColumnSpec) p.EnterOuterAlt(localctx, 1) { - p.SetState(1827) + p.SetState(1835) p.Match(CqlParserLR_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -30485,11 +30490,11 @@ func (p *CqlParser) InsertColumnSpec() (localctx IInsertColumnSpecContext) { } } { - p.SetState(1828) + p.SetState(1836) p.ColumnList() } { - p.SetState(1829) + p.SetState(1837) p.Match(CqlParserRR_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -30668,10 +30673,10 @@ func (p *CqlParser) ColumnList() (localctx IColumnListContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1831) + p.SetState(1839) p.Column() } - p.SetState(1837) + p.SetState(1845) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -30680,15 +30685,15 @@ func (p *CqlParser) ColumnList() (localctx IColumnListContext) { for _la == CqlParserCOMMA { { - p.SetState(1832) + p.SetState(1840) p.SyntaxComma() } { - p.SetState(1833) + p.SetState(1841) p.Column() } - p.SetState(1839) + p.SetState(1847) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -30867,10 +30872,10 @@ func (p *CqlParser) ValueListSpec() (localctx IValueListSpecContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1840) + p.SetState(1848) p.ValueAny() } - p.SetState(1846) + p.SetState(1854) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -30879,15 +30884,15 @@ func (p *CqlParser) ValueListSpec() (localctx IValueListSpecContext) { for _la == CqlParserCOMMA { { - p.SetState(1841) + p.SetState(1849) p.SyntaxComma() } { - p.SetState(1842) + p.SetState(1850) p.ValueAny() } - p.SetState(1848) + p.SetState(1856) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -31078,7 +31083,7 @@ func (s *ExpressionContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Expression() (localctx IExpressionContext) { localctx = NewExpressionContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 288, CqlParserRULE_expression) - p.SetState(1855) + p.SetState(1863) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -31088,42 +31093,42 @@ func (p *CqlParser) Expression() (localctx IExpressionContext) { case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(1849) + p.SetState(1857) p.Constant() } case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(1850) + p.SetState(1858) p.FunctionCall() } case 3: p.EnterOuterAlt(localctx, 3) { - p.SetState(1851) + p.SetState(1859) p.ValueMap() } case 4: p.EnterOuterAlt(localctx, 4) { - p.SetState(1852) + p.SetState(1860) p.ValueSet() } case 5: p.EnterOuterAlt(localctx, 5) { - p.SetState(1853) + p.SetState(1861) p.ValueList() } case 6: p.EnterOuterAlt(localctx, 6) { - p.SetState(1854) + p.SetState(1862) p.AssignmentTuple() } @@ -31403,10 +31408,10 @@ func (p *CqlParser) Select_() (localctx ISelect_Context) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1857) + p.SetState(1865) p.KwSelect() } - p.SetState(1859) + p.SetState(1867) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -31415,12 +31420,12 @@ func (p *CqlParser) Select_() (localctx ISelect_Context) { if _la == CqlParserK_DISTINCT { { - p.SetState(1858) + p.SetState(1866) p.DistinctSpec() } } - p.SetState(1862) + p.SetState(1870) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -31429,20 +31434,20 @@ func (p *CqlParser) Select_() (localctx ISelect_Context) { if _la == CqlParserK_JSON { { - p.SetState(1861) + p.SetState(1869) p.KwJson() } } { - p.SetState(1864) + p.SetState(1872) p.SelectElements() } { - p.SetState(1865) + p.SetState(1873) p.FromSpec() } - p.SetState(1867) + p.SetState(1875) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -31451,12 +31456,12 @@ func (p *CqlParser) Select_() (localctx ISelect_Context) { if _la == CqlParserK_WHERE { { - p.SetState(1866) + p.SetState(1874) p.WhereSpec() } } - p.SetState(1870) + p.SetState(1878) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -31465,12 +31470,12 @@ func (p *CqlParser) Select_() (localctx ISelect_Context) { if _la == CqlParserK_GROUP { { - p.SetState(1869) + p.SetState(1877) p.GroupSpec() } } - p.SetState(1873) + p.SetState(1881) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -31479,12 +31484,12 @@ func (p *CqlParser) Select_() (localctx ISelect_Context) { if _la == CqlParserK_ORDER { { - p.SetState(1872) + p.SetState(1880) p.OrderSpec() } } - p.SetState(1876) + p.SetState(1884) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -31493,12 +31498,12 @@ func (p *CqlParser) Select_() (localctx ISelect_Context) { if _la == CqlParserK_LIMIT { { - p.SetState(1875) + p.SetState(1883) p.LimitSpec() } } - p.SetState(1879) + p.SetState(1887) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -31507,17 +31512,17 @@ func (p *CqlParser) Select_() (localctx ISelect_Context) { if _la == CqlParserK_ALLOW { { - p.SetState(1878) + p.SetState(1886) p.AllowFilteringSpec() } } - p.SetState(1882) + p.SetState(1890) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 150, p.GetParserRuleContext()) == 1 { { - p.SetState(1881) + p.SetState(1889) p.StatementSeparator() } @@ -31642,11 +31647,11 @@ func (p *CqlParser) AllowFilteringSpec() (localctx IAllowFilteringSpecContext) { p.EnterRule(localctx, 292, CqlParserRULE_allowFilteringSpec) p.EnterOuterAlt(localctx, 1) { - p.SetState(1884) + p.SetState(1892) p.KwAllow() } { - p.SetState(1885) + p.SetState(1893) p.KwFiltering() } @@ -31784,10 +31789,10 @@ func (p *CqlParser) LimitSpec() (localctx ILimitSpecContext) { p.EnterRule(localctx, 294, CqlParserRULE_limitSpec) p.EnterOuterAlt(localctx, 1) { - p.SetState(1887) + p.SetState(1895) p.KwLimit() } - p.SetState(1890) + p.SetState(1898) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -31796,13 +31801,13 @@ func (p *CqlParser) LimitSpec() (localctx ILimitSpecContext) { switch p.GetTokenStream().LA(1) { case CqlParserQUESTION_MARK, CqlParserNAMED_MARK: { - p.SetState(1888) + p.SetState(1896) p.Marker() } case CqlParserDECIMAL_LITERAL: { - p.SetState(1889) + p.SetState(1897) p.DecimalLiteral() } @@ -31899,7 +31904,7 @@ func (p *CqlParser) KwLike() (localctx IKwLikeContext) { p.EnterRule(localctx, 296, CqlParserRULE_kwLike) p.EnterOuterAlt(localctx, 1) { - p.SetState(1892) + p.SetState(1900) p.Match(CqlParserK_LIKE) if p.HasError() { // Recognition error - abort rule @@ -32028,16 +32033,16 @@ func (p *CqlParser) TableSpec() (localctx ITableSpecContext) { localctx = NewTableSpecContext(p, p.GetParserRuleContext(), p.GetState()) p.EnterRule(localctx, 298, CqlParserRULE_tableSpec) p.EnterOuterAlt(localctx, 1) - p.SetState(1897) + p.SetState(1905) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 152, p.GetParserRuleContext()) == 1 { { - p.SetState(1894) + p.SetState(1902) p.Keyspace() } { - p.SetState(1895) + p.SetState(1903) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -32049,7 +32054,7 @@ func (p *CqlParser) TableSpec() (localctx ITableSpecContext) { goto errorExit } { - p.SetState(1899) + p.SetState(1907) p.Table() } @@ -32170,11 +32175,11 @@ func (p *CqlParser) FromSpec() (localctx IFromSpecContext) { p.EnterRule(localctx, 300, CqlParserRULE_fromSpec) p.EnterOuterAlt(localctx, 1) { - p.SetState(1901) + p.SetState(1909) p.KwFrom() } { - p.SetState(1902) + p.SetState(1910) p.TableSpec() } @@ -32383,18 +32388,18 @@ func (p *CqlParser) OrderSpec() (localctx IOrderSpecContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1904) + p.SetState(1912) p.KwOrder() } { - p.SetState(1905) + p.SetState(1913) p.KwBy() } { - p.SetState(1906) + p.SetState(1914) p.OrderSpecElement() } - p.SetState(1912) + p.SetState(1920) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -32403,15 +32408,15 @@ func (p *CqlParser) OrderSpec() (localctx IOrderSpecContext) { for _la == CqlParserCOMMA { { - p.SetState(1907) + p.SetState(1915) p.SyntaxComma() } { - p.SetState(1908) + p.SetState(1916) p.OrderSpecElement() } - p.SetState(1914) + p.SetState(1922) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -32541,19 +32546,19 @@ func (p *CqlParser) OrderSpecElement() (localctx IOrderSpecElementContext) { p.EnterRule(localctx, 304, CqlParserRULE_orderSpecElement) p.EnterOuterAlt(localctx, 1) { - p.SetState(1915) + p.SetState(1923) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule goto errorExit } } - p.SetState(1918) + p.SetState(1926) p.GetErrorHandler().Sync(p) if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 154, p.GetParserRuleContext()) == 1 { { - p.SetState(1916) + p.SetState(1924) p.KwAsc() } @@ -32561,7 +32566,7 @@ func (p *CqlParser) OrderSpecElement() (localctx IOrderSpecElementContext) { goto errorExit } else if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 154, p.GetParserRuleContext()) == 2 { { - p.SetState(1917) + p.SetState(1925) p.KwDesc() } @@ -32686,11 +32691,11 @@ func (p *CqlParser) WhereSpec() (localctx IWhereSpecContext) { p.EnterRule(localctx, 306, CqlParserRULE_whereSpec) p.EnterOuterAlt(localctx, 1) { - p.SetState(1920) + p.SetState(1928) p.KwWhere() } { - p.SetState(1921) + p.SetState(1929) p.RelationElements() } @@ -32794,7 +32799,7 @@ func (p *CqlParser) DistinctSpec() (localctx IDistinctSpecContext) { p.EnterRule(localctx, 308, CqlParserRULE_distinctSpec) p.EnterOuterAlt(localctx, 1) { - p.SetState(1923) + p.SetState(1931) p.KwDistinct() } @@ -32984,7 +32989,7 @@ func (p *CqlParser) SelectElements() (localctx ISelectElementsContext) { var _la int p.EnterOuterAlt(localctx, 1) - p.SetState(1927) + p.SetState(1935) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -32993,7 +32998,7 @@ func (p *CqlParser) SelectElements() (localctx ISelectElementsContext) { switch p.GetTokenStream().LA(1) { case CqlParserSTAR: { - p.SetState(1925) + p.SetState(1933) var _m = p.Match(CqlParserSTAR) @@ -33006,7 +33011,7 @@ func (p *CqlParser) SelectElements() (localctx ISelectElementsContext) { case CqlParserDQUOTE, CqlParserK_KEY, CqlParserK_TYPE, CqlParserK_UUID, CqlParserK_WRITETIME, CqlParserOBJECT_NAME: { - p.SetState(1926) + p.SetState(1934) p.SelectElement() } @@ -33014,7 +33019,7 @@ func (p *CqlParser) SelectElements() (localctx ISelectElementsContext) { p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil)) goto errorExit } - p.SetState(1934) + p.SetState(1942) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -33023,15 +33028,15 @@ func (p *CqlParser) SelectElements() (localctx ISelectElementsContext) { for _la == CqlParserCOMMA { { - p.SetState(1929) + p.SetState(1937) p.SyntaxComma() } { - p.SetState(1930) + p.SetState(1938) p.SelectElement() } - p.SetState(1936) + p.SetState(1944) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -33190,7 +33195,7 @@ func (p *CqlParser) SelectElement() (localctx ISelectElementContext) { p.EnterRule(localctx, 312, CqlParserRULE_selectElement) var _la int - p.SetState(1949) + p.SetState(1957) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -33200,10 +33205,10 @@ func (p *CqlParser) SelectElement() (localctx ISelectElementContext) { case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(1937) + p.SetState(1945) p.SelectColumn() } - p.SetState(1939) + p.SetState(1947) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -33212,7 +33217,7 @@ func (p *CqlParser) SelectElement() (localctx ISelectElementContext) { if _la == CqlParserK_AS { { - p.SetState(1938) + p.SetState(1946) p.AsSpec() } @@ -33221,10 +33226,10 @@ func (p *CqlParser) SelectElement() (localctx ISelectElementContext) { case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(1941) + p.SetState(1949) p.SelectFunction() } - p.SetState(1943) + p.SetState(1951) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -33233,7 +33238,7 @@ func (p *CqlParser) SelectElement() (localctx ISelectElementContext) { if _la == CqlParserK_AS { { - p.SetState(1942) + p.SetState(1950) p.AsSpec() } @@ -33242,10 +33247,10 @@ func (p *CqlParser) SelectElement() (localctx ISelectElementContext) { case 3: p.EnterOuterAlt(localctx, 3) { - p.SetState(1945) + p.SetState(1953) p.SelectIndex() } - p.SetState(1947) + p.SetState(1955) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -33254,7 +33259,7 @@ func (p *CqlParser) SelectElement() (localctx ISelectElementContext) { if _la == CqlParserK_AS { { - p.SetState(1946) + p.SetState(1954) p.AsSpec() } @@ -33364,7 +33369,7 @@ func (p *CqlParser) SelectColumn() (localctx ISelectColumnContext) { p.EnterRule(localctx, 314, CqlParserRULE_selectColumn) p.EnterOuterAlt(localctx, 1) { - p.SetState(1951) + p.SetState(1959) p.Column() } @@ -33468,7 +33473,7 @@ func (p *CqlParser) SelectFunction() (localctx ISelectFunctionContext) { p.EnterRule(localctx, 316, CqlParserRULE_selectFunction) p.EnterOuterAlt(localctx, 1) { - p.SetState(1953) + p.SetState(1961) p.FunctionCall() } @@ -33623,19 +33628,19 @@ func (p *CqlParser) SelectIndex() (localctx ISelectIndexContext) { p.EnterRule(localctx, 318, CqlParserRULE_selectIndex) p.EnterOuterAlt(localctx, 1) { - p.SetState(1955) + p.SetState(1963) p.Column() } { - p.SetState(1956) + p.SetState(1964) p.SyntaxBracketLs() } { - p.SetState(1957) + p.SetState(1965) p.Constant() } { - p.SetState(1958) + p.SetState(1966) p.SyntaxBracketRs() } @@ -33744,11 +33749,11 @@ func (p *CqlParser) AsSpec() (localctx IAsSpecContext) { p.EnterRule(localctx, 320, CqlParserRULE_asSpec) p.EnterOuterAlt(localctx, 1) { - p.SetState(1960) + p.SetState(1968) p.KwAs() } { - p.SetState(1961) + p.SetState(1969) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -33927,11 +33932,11 @@ func (p *CqlParser) RelationElements() (localctx IRelationElementsContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(1963) + p.SetState(1971) p.RelationElement() } - p.SetState(1969) + p.SetState(1977) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -33940,15 +33945,15 @@ func (p *CqlParser) RelationElements() (localctx IRelationElementsContext) { for _la == CqlParserK_AND { { - p.SetState(1964) + p.SetState(1972) p.KwAnd() } { - p.SetState(1965) + p.SetState(1973) p.RelationElement() } - p.SetState(1971) + p.SetState(1979) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -33982,6 +33987,8 @@ type IRelationElementContext interface { RelationBetween() IRelationBetweenContext RelationFunctionCompareConstant() IRelationFunctionCompareConstantContext RelationFunctionCompareFunction() IRelationFunctionCompareFunctionContext + RelationColumnCompareFunction() IRelationColumnCompareFunctionContext + RelationFunctionCompareColumn() IRelationFunctionCompareColumnContext RelationContainsKey() IRelationContainsKeyContext RelationContains() IRelationContainsContext RelationIn() IRelationInContext @@ -34120,6 +34127,38 @@ func (s *RelationElementContext) RelationFunctionCompareFunction() IRelationFunc return t.(IRelationFunctionCompareFunctionContext) } +func (s *RelationElementContext) RelationColumnCompareFunction() IRelationColumnCompareFunctionContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IRelationColumnCompareFunctionContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IRelationColumnCompareFunctionContext) +} + +func (s *RelationElementContext) RelationFunctionCompareColumn() IRelationFunctionCompareColumnContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IRelationFunctionCompareColumnContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IRelationFunctionCompareColumnContext) +} + func (s *RelationElementContext) RelationContainsKey() IRelationContainsKeyContext { var t antlr.RuleContext for _, ctx := range s.GetChildren() { @@ -34424,7 +34463,7 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { p.EnterRule(localctx, 324, CqlParserRULE_relationElement) var _la int - p.SetState(2039) + p.SetState(2049) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -34434,63 +34473,77 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(1972) + p.SetState(1980) p.RelationCompare() } case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(1973) + p.SetState(1981) p.RelationLike() } case 3: p.EnterOuterAlt(localctx, 3) { - p.SetState(1974) + p.SetState(1982) p.RelationBetween() } case 4: p.EnterOuterAlt(localctx, 4) { - p.SetState(1975) + p.SetState(1983) p.RelationFunctionCompareConstant() } case 5: p.EnterOuterAlt(localctx, 5) { - p.SetState(1976) + p.SetState(1984) p.RelationFunctionCompareFunction() } case 6: p.EnterOuterAlt(localctx, 6) { - p.SetState(1977) - p.RelationContainsKey() + p.SetState(1985) + p.RelationColumnCompareFunction() } case 7: p.EnterOuterAlt(localctx, 7) { - p.SetState(1978) - p.RelationContains() + p.SetState(1986) + p.RelationFunctionCompareColumn() } case 8: p.EnterOuterAlt(localctx, 8) { - p.SetState(1979) - p.RelationIn() + p.SetState(1987) + p.RelationContainsKey() } case 9: p.EnterOuterAlt(localctx, 9) { - p.SetState(1980) + p.SetState(1988) + p.RelationContains() + } + + case 10: + p.EnterOuterAlt(localctx, 10) + { + p.SetState(1989) + p.RelationIn() + } + + case 11: + p.EnterOuterAlt(localctx, 11) + { + p.SetState(1990) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -34498,7 +34551,7 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { } } { - p.SetState(1981) + p.SetState(1991) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -34506,7 +34559,7 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { } } { - p.SetState(1982) + p.SetState(1992) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -34514,18 +34567,18 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { } } { - p.SetState(1983) + p.SetState(1993) p.KwLike() } { - p.SetState(1984) + p.SetState(1994) p.Constant() } - case 10: - p.EnterOuterAlt(localctx, 10) + case 12: + p.EnterOuterAlt(localctx, 12) { - p.SetState(1986) + p.SetState(1996) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -34533,7 +34586,7 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { } } { - p.SetState(1987) + p.SetState(1997) p.Match(CqlParserDOT) if p.HasError() { // Recognition error - abort rule @@ -34541,7 +34594,7 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { } } { - p.SetState(1988) + p.SetState(1998) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -34549,26 +34602,26 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { } } { - p.SetState(1989) + p.SetState(1999) p.KwBetween() } { - p.SetState(1990) + p.SetState(2000) p.Constant() } { - p.SetState(1991) + p.SetState(2001) p.KwAnd() } { - p.SetState(1992) + p.SetState(2002) p.Constant() } - case 11: - p.EnterOuterAlt(localctx, 11) + case 13: + p.EnterOuterAlt(localctx, 13) { - p.SetState(1994) + p.SetState(2004) p.Match(CqlParserLR_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -34576,14 +34629,14 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { } } { - p.SetState(1995) + p.SetState(2005) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule goto errorExit } } - p.SetState(2001) + p.SetState(2011) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -34592,11 +34645,11 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { for _la == CqlParserCOMMA { { - p.SetState(1996) + p.SetState(2006) p.SyntaxComma() } { - p.SetState(1997) + p.SetState(2007) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -34604,7 +34657,7 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { } } - p.SetState(2003) + p.SetState(2013) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -34612,7 +34665,7 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { _la = p.GetTokenStream().LA(1) } { - p.SetState(2004) + p.SetState(2014) p.Match(CqlParserRR_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -34620,11 +34673,11 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { } } { - p.SetState(2005) + p.SetState(2015) p.KwIn() } { - p.SetState(2006) + p.SetState(2016) p.Match(CqlParserLR_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -34632,10 +34685,10 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { } } { - p.SetState(2007) + p.SetState(2017) p.AssignmentTuple() } - p.SetState(2013) + p.SetState(2023) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -34644,15 +34697,15 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { for _la == CqlParserCOMMA { { - p.SetState(2008) + p.SetState(2018) p.SyntaxComma() } { - p.SetState(2009) + p.SetState(2019) p.AssignmentTuple() } - p.SetState(2015) + p.SetState(2025) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -34660,7 +34713,7 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { _la = p.GetTokenStream().LA(1) } { - p.SetState(2016) + p.SetState(2026) p.Match(CqlParserRR_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -34668,10 +34721,10 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { } } - case 12: - p.EnterOuterAlt(localctx, 12) + case 14: + p.EnterOuterAlt(localctx, 14) { - p.SetState(2018) + p.SetState(2028) p.Match(CqlParserLR_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -34679,14 +34732,14 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { } } { - p.SetState(2019) + p.SetState(2029) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule goto errorExit } } - p.SetState(2025) + p.SetState(2035) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -34695,11 +34748,11 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { for _la == CqlParserCOMMA { { - p.SetState(2020) + p.SetState(2030) p.SyntaxComma() } { - p.SetState(2021) + p.SetState(2031) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -34707,7 +34760,7 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { } } - p.SetState(2027) + p.SetState(2037) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -34715,7 +34768,7 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { _la = p.GetTokenStream().LA(1) } { - p.SetState(2028) + p.SetState(2038) p.Match(CqlParserRR_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -34723,15 +34776,15 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { } } { - p.SetState(2029) + p.SetState(2039) p.CompareOperator() } { - p.SetState(2030) + p.SetState(2040) p.AssignmentTuple() } - p.SetState(2036) + p.SetState(2046) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -34740,15 +34793,15 @@ func (p *CqlParser) RelationElement() (localctx IRelationElementContext) { for _la == CqlParserCOMMA { { - p.SetState(2031) + p.SetState(2041) p.SyntaxComma() } { - p.SetState(2032) + p.SetState(2042) p.AssignmentTuple() } - p.SetState(2038) + p.SetState(2048) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -34870,7 +34923,7 @@ func (p *CqlParser) CompareOperator() (localctx ICompareOperatorContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(2041) + p.SetState(2051) _la = p.GetTokenStream().LA(1) if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&16252928) != 0) { @@ -35015,15 +35068,15 @@ func (p *CqlParser) RelationFunctionCompareConstant() (localctx IRelationFunctio p.EnterRule(localctx, 328, CqlParserRULE_relationFunctionCompareConstant) p.EnterOuterAlt(localctx, 1) { - p.SetState(2043) + p.SetState(2053) p.FunctionCall() } { - p.SetState(2044) + p.SetState(2054) p.CompareOperator() } { - p.SetState(2045) + p.SetState(2055) p.Constant() } @@ -35170,15 +35223,15 @@ func (p *CqlParser) RelationFunctionCompareFunction() (localctx IRelationFunctio p.EnterRule(localctx, 330, CqlParserRULE_relationFunctionCompareFunction) p.EnterOuterAlt(localctx, 1) { - p.SetState(2047) + p.SetState(2057) p.FunctionCall() } { - p.SetState(2048) + p.SetState(2058) p.CompareOperator() } { - p.SetState(2049) + p.SetState(2059) p.FunctionCall() } @@ -35195,6 +35248,298 @@ errorExit: goto errorExit // Trick to prevent compiler error if the label is not used } +// IRelationColumnCompareFunctionContext is an interface to support dynamic dispatch. +type IRelationColumnCompareFunctionContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + Column() IColumnContext + CompareOperator() ICompareOperatorContext + FunctionCall() IFunctionCallContext + + // IsRelationColumnCompareFunctionContext differentiates from other interfaces. + IsRelationColumnCompareFunctionContext() +} + +type RelationColumnCompareFunctionContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyRelationColumnCompareFunctionContext() *RelationColumnCompareFunctionContext { + var p = new(RelationColumnCompareFunctionContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = CqlParserRULE_relationColumnCompareFunction + return p +} + +func InitEmptyRelationColumnCompareFunctionContext(p *RelationColumnCompareFunctionContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = CqlParserRULE_relationColumnCompareFunction +} + +func (*RelationColumnCompareFunctionContext) IsRelationColumnCompareFunctionContext() {} + +func NewRelationColumnCompareFunctionContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *RelationColumnCompareFunctionContext { + var p = new(RelationColumnCompareFunctionContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = CqlParserRULE_relationColumnCompareFunction + + return p +} + +func (s *RelationColumnCompareFunctionContext) GetParser() antlr.Parser { return s.parser } + +func (s *RelationColumnCompareFunctionContext) Column() IColumnContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IColumnContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IColumnContext) +} + +func (s *RelationColumnCompareFunctionContext) CompareOperator() ICompareOperatorContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(ICompareOperatorContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(ICompareOperatorContext) +} + +func (s *RelationColumnCompareFunctionContext) FunctionCall() IFunctionCallContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IFunctionCallContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IFunctionCallContext) +} + +func (s *RelationColumnCompareFunctionContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *RelationColumnCompareFunctionContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *RelationColumnCompareFunctionContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(CqlParserListener); ok { + listenerT.EnterRelationColumnCompareFunction(s) + } +} + +func (s *RelationColumnCompareFunctionContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(CqlParserListener); ok { + listenerT.ExitRelationColumnCompareFunction(s) + } +} + +func (p *CqlParser) RelationColumnCompareFunction() (localctx IRelationColumnCompareFunctionContext) { + localctx = NewRelationColumnCompareFunctionContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 332, CqlParserRULE_relationColumnCompareFunction) + p.EnterOuterAlt(localctx, 1) + { + p.SetState(2061) + p.Column() + } + { + p.SetState(2062) + p.CompareOperator() + } + { + p.SetState(2063) + p.FunctionCall() + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IRelationFunctionCompareColumnContext is an interface to support dynamic dispatch. +type IRelationFunctionCompareColumnContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + FunctionCall() IFunctionCallContext + CompareOperator() ICompareOperatorContext + Column() IColumnContext + + // IsRelationFunctionCompareColumnContext differentiates from other interfaces. + IsRelationFunctionCompareColumnContext() +} + +type RelationFunctionCompareColumnContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyRelationFunctionCompareColumnContext() *RelationFunctionCompareColumnContext { + var p = new(RelationFunctionCompareColumnContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = CqlParserRULE_relationFunctionCompareColumn + return p +} + +func InitEmptyRelationFunctionCompareColumnContext(p *RelationFunctionCompareColumnContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = CqlParserRULE_relationFunctionCompareColumn +} + +func (*RelationFunctionCompareColumnContext) IsRelationFunctionCompareColumnContext() {} + +func NewRelationFunctionCompareColumnContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *RelationFunctionCompareColumnContext { + var p = new(RelationFunctionCompareColumnContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = CqlParserRULE_relationFunctionCompareColumn + + return p +} + +func (s *RelationFunctionCompareColumnContext) GetParser() antlr.Parser { return s.parser } + +func (s *RelationFunctionCompareColumnContext) FunctionCall() IFunctionCallContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IFunctionCallContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IFunctionCallContext) +} + +func (s *RelationFunctionCompareColumnContext) CompareOperator() ICompareOperatorContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(ICompareOperatorContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(ICompareOperatorContext) +} + +func (s *RelationFunctionCompareColumnContext) Column() IColumnContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IColumnContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IColumnContext) +} + +func (s *RelationFunctionCompareColumnContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *RelationFunctionCompareColumnContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *RelationFunctionCompareColumnContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(CqlParserListener); ok { + listenerT.EnterRelationFunctionCompareColumn(s) + } +} + +func (s *RelationFunctionCompareColumnContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(CqlParserListener); ok { + listenerT.ExitRelationFunctionCompareColumn(s) + } +} + +func (p *CqlParser) RelationFunctionCompareColumn() (localctx IRelationFunctionCompareColumnContext) { + localctx = NewRelationFunctionCompareColumnContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 334, CqlParserRULE_relationFunctionCompareColumn) + p.EnterOuterAlt(localctx, 1) + { + p.SetState(2065) + p.FunctionCall() + } + { + p.SetState(2066) + p.CompareOperator() + } + { + p.SetState(2067) + p.Column() + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + // IRelationBetweenContext is an interface to support dynamic dispatch. type IRelationBetweenContext interface { antlr.ParserRuleContext @@ -35205,8 +35550,8 @@ type IRelationBetweenContext interface { // Getter signatures Column() IColumnContext KwBetween() IKwBetweenContext - AllConstant() []IConstantContext - Constant(i int) IConstantContext + AllValueAny() []IValueAnyContext + ValueAny(i int) IValueAnyContext KwAnd() IKwAndContext // IsRelationBetweenContext differentiates from other interfaces. @@ -35277,20 +35622,20 @@ func (s *RelationBetweenContext) KwBetween() IKwBetweenContext { return t.(IKwBetweenContext) } -func (s *RelationBetweenContext) AllConstant() []IConstantContext { +func (s *RelationBetweenContext) AllValueAny() []IValueAnyContext { children := s.GetChildren() len := 0 for _, ctx := range children { - if _, ok := ctx.(IConstantContext); ok { + if _, ok := ctx.(IValueAnyContext); ok { len++ } } - tst := make([]IConstantContext, len) + tst := make([]IValueAnyContext, len) i := 0 for _, ctx := range children { - if t, ok := ctx.(IConstantContext); ok { - tst[i] = t.(IConstantContext) + if t, ok := ctx.(IValueAnyContext); ok { + tst[i] = t.(IValueAnyContext) i++ } } @@ -35298,11 +35643,11 @@ func (s *RelationBetweenContext) AllConstant() []IConstantContext { return tst } -func (s *RelationBetweenContext) Constant(i int) IConstantContext { +func (s *RelationBetweenContext) ValueAny(i int) IValueAnyContext { var t antlr.RuleContext j := 0 for _, ctx := range s.GetChildren() { - if _, ok := ctx.(IConstantContext); ok { + if _, ok := ctx.(IValueAnyContext); ok { if j == i { t = ctx.(antlr.RuleContext) break @@ -35315,7 +35660,7 @@ func (s *RelationBetweenContext) Constant(i int) IConstantContext { return nil } - return t.(IConstantContext) + return t.(IValueAnyContext) } func (s *RelationBetweenContext) KwAnd() IKwAndContext { @@ -35356,27 +35701,27 @@ func (s *RelationBetweenContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) RelationBetween() (localctx IRelationBetweenContext) { localctx = NewRelationBetweenContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 332, CqlParserRULE_relationBetween) + p.EnterRule(localctx, 336, CqlParserRULE_relationBetween) p.EnterOuterAlt(localctx, 1) { - p.SetState(2051) + p.SetState(2069) p.Column() } { - p.SetState(2052) + p.SetState(2070) p.KwBetween() } { - p.SetState(2053) - p.Constant() + p.SetState(2071) + p.ValueAny() } { - p.SetState(2054) + p.SetState(2072) p.KwAnd() } { - p.SetState(2055) - p.Constant() + p.SetState(2073) + p.ValueAny() } errorExit: @@ -35510,18 +35855,18 @@ func (s *RelationCompareContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) RelationCompare() (localctx IRelationCompareContext) { localctx = NewRelationCompareContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 334, CqlParserRULE_relationCompare) + p.EnterRule(localctx, 338, CqlParserRULE_relationCompare) p.EnterOuterAlt(localctx, 1) { - p.SetState(2057) + p.SetState(2075) p.Column() } { - p.SetState(2058) + p.SetState(2076) p.CompareOperator() } { - p.SetState(2059) + p.SetState(2077) p.Constant() } @@ -35656,18 +36001,18 @@ func (s *RelationLikeContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) RelationLike() (localctx IRelationLikeContext) { localctx = NewRelationLikeContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 336, CqlParserRULE_relationLike) + p.EnterRule(localctx, 340, CqlParserRULE_relationLike) p.EnterOuterAlt(localctx, 1) { - p.SetState(2061) + p.SetState(2079) p.Column() } { - p.SetState(2062) + p.SetState(2080) p.KwLike() } { - p.SetState(2063) + p.SetState(2081) p.Constant() } @@ -35761,12 +36106,12 @@ func (s *MarkerContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Marker() (localctx IMarkerContext) { localctx = NewMarkerContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 338, CqlParserRULE_marker) + p.EnterRule(localctx, 342, CqlParserRULE_marker) var _la int p.EnterOuterAlt(localctx, 1) { - p.SetState(2065) + p.SetState(2083) _la = p.GetTokenStream().LA(1) if !(_la == CqlParserQUESTION_MARK || _la == CqlParserNAMED_MARK) { @@ -35901,8 +36246,8 @@ func (s *TupleValueContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) TupleValue() (localctx ITupleValueContext) { localctx = NewTupleValueContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 340, CqlParserRULE_tupleValue) - p.SetState(2072) + p.EnterRule(localctx, 344, CqlParserRULE_tupleValue) + p.SetState(2090) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -35912,14 +36257,14 @@ func (p *CqlParser) TupleValue() (localctx ITupleValueContext) { case CqlParserQUESTION_MARK, CqlParserNAMED_MARK: p.EnterOuterAlt(localctx, 1) { - p.SetState(2067) + p.SetState(2085) p.Marker() } case CqlParserLR_BRACKET: p.EnterOuterAlt(localctx, 2) { - p.SetState(2068) + p.SetState(2086) p.Match(CqlParserLR_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -35927,11 +36272,11 @@ func (p *CqlParser) TupleValue() (localctx ITupleValueContext) { } } { - p.SetState(2069) + p.SetState(2087) p.FunctionArgs() } { - p.SetState(2070) + p.SetState(2088) p.Match(CqlParserRR_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -36075,18 +36420,18 @@ func (s *RelationInContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) RelationIn() (localctx IRelationInContext) { localctx = NewRelationInContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 342, CqlParserRULE_relationIn) + p.EnterRule(localctx, 346, CqlParserRULE_relationIn) p.EnterOuterAlt(localctx, 1) { - p.SetState(2074) + p.SetState(2092) p.Column() } { - p.SetState(2075) + p.SetState(2093) p.KwIn() } { - p.SetState(2076) + p.SetState(2094) p.TupleValue() } @@ -36221,18 +36566,18 @@ func (s *RelationContainsContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) RelationContains() (localctx IRelationContainsContext) { localctx = NewRelationContainsContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 344, CqlParserRULE_relationContains) + p.EnterRule(localctx, 348, CqlParserRULE_relationContains) p.EnterOuterAlt(localctx, 1) { - p.SetState(2078) + p.SetState(2096) p.Column() } { - p.SetState(2079) + p.SetState(2097) p.KwContains() } { - p.SetState(2080) + p.SetState(2098) p.Constant() } @@ -36384,24 +36729,24 @@ func (s *RelationContainsKeyContext) ExitRule(listener antlr.ParseTreeListener) func (p *CqlParser) RelationContainsKey() (localctx IRelationContainsKeyContext) { localctx = NewRelationContainsKeyContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 346, CqlParserRULE_relationContainsKey) + p.EnterRule(localctx, 350, CqlParserRULE_relationContainsKey) p.EnterOuterAlt(localctx, 1) { - p.SetState(2082) + p.SetState(2100) p.Column() } { - p.SetState(2083) + p.SetState(2101) p.KwContains() } { - p.SetState(2084) + p.SetState(2102) p.KwKey() } { - p.SetState(2086) + p.SetState(2104) p.Constant() } @@ -36426,13 +36771,10 @@ type IFunctionCallContext interface { GetParser() antlr.Parser // Getter signatures - OBJECT_NAME() antlr.TerminalNode + FunctionName() IFunctionNameContext LR_BRACKET() antlr.TerminalNode - STAR() antlr.TerminalNode RR_BRACKET() antlr.TerminalNode FunctionArgs() IFunctionArgsContext - K_UUID() antlr.TerminalNode - K_WRITETIME() antlr.TerminalNode // IsFunctionCallContext differentiates from other interfaces. IsFunctionCallContext() @@ -36470,18 +36812,26 @@ func NewFunctionCallContext(parser antlr.Parser, parent antlr.ParserRuleContext, func (s *FunctionCallContext) GetParser() antlr.Parser { return s.parser } -func (s *FunctionCallContext) OBJECT_NAME() antlr.TerminalNode { - return s.GetToken(CqlParserOBJECT_NAME, 0) +func (s *FunctionCallContext) FunctionName() IFunctionNameContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IFunctionNameContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IFunctionNameContext) } func (s *FunctionCallContext) LR_BRACKET() antlr.TerminalNode { return s.GetToken(CqlParserLR_BRACKET, 0) } -func (s *FunctionCallContext) STAR() antlr.TerminalNode { - return s.GetToken(CqlParserSTAR, 0) -} - func (s *FunctionCallContext) RR_BRACKET() antlr.TerminalNode { return s.GetToken(CqlParserRR_BRACKET, 0) } @@ -36502,14 +36852,6 @@ func (s *FunctionCallContext) FunctionArgs() IFunctionArgsContext { return t.(IFunctionArgsContext) } -func (s *FunctionCallContext) K_UUID() antlr.TerminalNode { - return s.GetToken(CqlParserK_UUID, 0) -} - -func (s *FunctionCallContext) K_WRITETIME() antlr.TerminalNode { - return s.GetToken(CqlParserK_WRITETIME, 0) -} - func (s *FunctionCallContext) GetRuleContext() antlr.RuleContext { return s } @@ -36532,162 +36874,154 @@ func (s *FunctionCallContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) FunctionCall() (localctx IFunctionCallContext) { localctx = NewFunctionCallContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 348, CqlParserRULE_functionCall) + p.EnterRule(localctx, 352, CqlParserRULE_functionCall) var _la int - p.SetState(2107) + p.EnterOuterAlt(localctx, 1) + { + p.SetState(2106) + p.FunctionName() + } + { + p.SetState(2107) + p.Match(CqlParserLR_BRACKET) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + p.SetState(2109) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit } + _la = p.GetTokenStream().LA(1) - switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 170, p.GetParserRuleContext()) { - case 1: - p.EnterOuterAlt(localctx, 1) + if ((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&144115188075989034) != 0) || ((int64((_la-76)) & ^0x3f) == 0 && ((int64(1)<<(_la-76))&612489549322911745) != 0) || ((int64((_la-141)) & ^0x3f) == 0 && ((int64(1)<<(_la-141))&133009768481) != 0) { { - p.SetState(2088) - p.Match(CqlParserOBJECT_NAME) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(2089) - p.Match(CqlParserLR_BRACKET) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(2090) - p.Match(CqlParserSTAR) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(2091) - p.Match(CqlParserRR_BRACKET) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } + p.SetState(2108) + p.FunctionArgs() } - case 2: - p.EnterOuterAlt(localctx, 2) - { - p.SetState(2092) - p.Match(CqlParserOBJECT_NAME) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(2093) - p.Match(CqlParserLR_BRACKET) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - p.SetState(2095) - p.GetErrorHandler().Sync(p) + } + { + p.SetState(2111) + p.Match(CqlParserRR_BRACKET) if p.HasError() { + // Recognition error - abort rule goto errorExit } - _la = p.GetTokenStream().LA(1) + } - if _la == CqlParserK_FALSE || _la == CqlParserK_NULL || ((int64((_la-131)) & ^0x3f) == 0 && ((int64(1)<<(_la-131))&136202002924545) != 0) { - { - p.SetState(2094) - p.FunctionArgs() - } +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} - } - { - p.SetState(2097) - p.Match(CqlParserRR_BRACKET) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } +// IFunctionNameContext is an interface to support dynamic dispatch. +type IFunctionNameContext interface { + antlr.ParserRuleContext - case 3: - p.EnterOuterAlt(localctx, 3) - { - p.SetState(2098) - p.Match(CqlParserK_UUID) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(2099) - p.Match(CqlParserLR_BRACKET) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(2100) - p.Match(CqlParserRR_BRACKET) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } + // GetParser returns the parser. + GetParser() antlr.Parser - case 4: - p.EnterOuterAlt(localctx, 4) - { - p.SetState(2101) - p.Match(CqlParserK_WRITETIME) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(2102) - p.Match(CqlParserLR_BRACKET) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - p.SetState(2104) - p.GetErrorHandler().Sync(p) - if p.HasError() { - goto errorExit - } - _la = p.GetTokenStream().LA(1) + // Getter signatures + OBJECT_NAME() antlr.TerminalNode + K_UUID() antlr.TerminalNode + K_WRITETIME() antlr.TerminalNode - if _la == CqlParserK_FALSE || _la == CqlParserK_NULL || ((int64((_la-131)) & ^0x3f) == 0 && ((int64(1)<<(_la-131))&136202002924545) != 0) { - { - p.SetState(2103) - p.FunctionArgs() - } + // IsFunctionNameContext differentiates from other interfaces. + IsFunctionNameContext() +} - } - { - p.SetState(2106) - p.Match(CqlParserRR_BRACKET) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } +type FunctionNameContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} - case antlr.ATNInvalidAltNumber: - goto errorExit +func NewEmptyFunctionNameContext() *FunctionNameContext { + var p = new(FunctionNameContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = CqlParserRULE_functionName + return p +} + +func InitEmptyFunctionNameContext(p *FunctionNameContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = CqlParserRULE_functionName +} + +func (*FunctionNameContext) IsFunctionNameContext() {} + +func NewFunctionNameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *FunctionNameContext { + var p = new(FunctionNameContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = CqlParserRULE_functionName + + return p +} + +func (s *FunctionNameContext) GetParser() antlr.Parser { return s.parser } + +func (s *FunctionNameContext) OBJECT_NAME() antlr.TerminalNode { + return s.GetToken(CqlParserOBJECT_NAME, 0) +} + +func (s *FunctionNameContext) K_UUID() antlr.TerminalNode { + return s.GetToken(CqlParserK_UUID, 0) +} + +func (s *FunctionNameContext) K_WRITETIME() antlr.TerminalNode { + return s.GetToken(CqlParserK_WRITETIME, 0) +} + +func (s *FunctionNameContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *FunctionNameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *FunctionNameContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(CqlParserListener); ok { + listenerT.EnterFunctionName(s) + } +} + +func (s *FunctionNameContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(CqlParserListener); ok { + listenerT.ExitFunctionName(s) + } +} + +func (p *CqlParser) FunctionName() (localctx IFunctionNameContext) { + localctx = NewFunctionNameContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 354, CqlParserRULE_functionName) + var _la int + + p.EnterOuterAlt(localctx, 1) + { + p.SetState(2113) + _la = p.GetTokenStream().LA(1) + + if !((int64((_la-141)) & ^0x3f) == 0 && ((int64(1)<<(_la-141))&8589934625) != 0) { + p.GetErrorHandler().RecoverInline(p) + } else { + p.GetErrorHandler().ReportMatch(p) + p.Consume() + } } errorExit: @@ -36711,12 +37045,8 @@ type IFunctionArgsContext interface { GetParser() antlr.Parser // Getter signatures - AllConstant() []IConstantContext - Constant(i int) IConstantContext - AllOBJECT_NAME() []antlr.TerminalNode - OBJECT_NAME(i int) antlr.TerminalNode - AllFunctionCall() []IFunctionCallContext - FunctionCall(i int) IFunctionCallContext + AllFunctionArg() []IFunctionArgContext + FunctionArg(i int) IFunctionArgContext AllSyntaxComma() []ISyntaxCommaContext SyntaxComma(i int) ISyntaxCommaContext @@ -36756,69 +37086,20 @@ func NewFunctionArgsContext(parser antlr.Parser, parent antlr.ParserRuleContext, func (s *FunctionArgsContext) GetParser() antlr.Parser { return s.parser } -func (s *FunctionArgsContext) AllConstant() []IConstantContext { - children := s.GetChildren() - len := 0 - for _, ctx := range children { - if _, ok := ctx.(IConstantContext); ok { - len++ - } - } - - tst := make([]IConstantContext, len) - i := 0 - for _, ctx := range children { - if t, ok := ctx.(IConstantContext); ok { - tst[i] = t.(IConstantContext) - i++ - } - } - - return tst -} - -func (s *FunctionArgsContext) Constant(i int) IConstantContext { - var t antlr.RuleContext - j := 0 - for _, ctx := range s.GetChildren() { - if _, ok := ctx.(IConstantContext); ok { - if j == i { - t = ctx.(antlr.RuleContext) - break - } - j++ - } - } - - if t == nil { - return nil - } - - return t.(IConstantContext) -} - -func (s *FunctionArgsContext) AllOBJECT_NAME() []antlr.TerminalNode { - return s.GetTokens(CqlParserOBJECT_NAME) -} - -func (s *FunctionArgsContext) OBJECT_NAME(i int) antlr.TerminalNode { - return s.GetToken(CqlParserOBJECT_NAME, i) -} - -func (s *FunctionArgsContext) AllFunctionCall() []IFunctionCallContext { +func (s *FunctionArgsContext) AllFunctionArg() []IFunctionArgContext { children := s.GetChildren() len := 0 for _, ctx := range children { - if _, ok := ctx.(IFunctionCallContext); ok { + if _, ok := ctx.(IFunctionArgContext); ok { len++ } } - tst := make([]IFunctionCallContext, len) + tst := make([]IFunctionArgContext, len) i := 0 for _, ctx := range children { - if t, ok := ctx.(IFunctionCallContext); ok { - tst[i] = t.(IFunctionCallContext) + if t, ok := ctx.(IFunctionArgContext); ok { + tst[i] = t.(IFunctionArgContext) i++ } } @@ -36826,11 +37107,11 @@ func (s *FunctionArgsContext) AllFunctionCall() []IFunctionCallContext { return tst } -func (s *FunctionArgsContext) FunctionCall(i int) IFunctionCallContext { +func (s *FunctionArgsContext) FunctionArg(i int) IFunctionArgContext { var t antlr.RuleContext j := 0 for _, ctx := range s.GetChildren() { - if _, ok := ctx.(IFunctionCallContext); ok { + if _, ok := ctx.(IFunctionArgContext); ok { if j == i { t = ctx.(antlr.RuleContext) break @@ -36843,7 +37124,7 @@ func (s *FunctionArgsContext) FunctionCall(i int) IFunctionCallContext { return nil } - return t.(IFunctionCallContext) + return t.(IFunctionArgContext) } func (s *FunctionArgsContext) AllSyntaxComma() []ISyntaxCommaContext { @@ -36909,93 +37190,194 @@ func (s *FunctionArgsContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) FunctionArgs() (localctx IFunctionArgsContext) { localctx = NewFunctionArgsContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 350, CqlParserRULE_functionArgs) + p.EnterRule(localctx, 356, CqlParserRULE_functionArgs) var _la int p.EnterOuterAlt(localctx, 1) - p.SetState(2112) + { + p.SetState(2115) + p.FunctionArg() + } + + p.SetState(2121) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit } + _la = p.GetTokenStream().LA(1) - switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 171, p.GetParserRuleContext()) { - case 1: + for _la == CqlParserCOMMA { { - p.SetState(2109) - p.Constant() + p.SetState(2116) + p.SyntaxComma() } - - case 2: { - p.SetState(2110) - p.Match(CqlParserOBJECT_NAME) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } + p.SetState(2117) + p.FunctionArg() } - case 3: - { - p.SetState(2111) - p.FunctionCall() + p.SetState(2123) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit } + _la = p.GetTokenStream().LA(1) + } - case antlr.ATNInvalidAltNumber: - goto errorExit +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) } - p.SetState(2122) + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IFunctionArgContext is an interface to support dynamic dispatch. +type IFunctionArgContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + ValueAny() IValueAnyContext + Column() IColumnContext + STAR() antlr.TerminalNode + + // IsFunctionArgContext differentiates from other interfaces. + IsFunctionArgContext() +} + +type FunctionArgContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyFunctionArgContext() *FunctionArgContext { + var p = new(FunctionArgContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = CqlParserRULE_functionArg + return p +} + +func InitEmptyFunctionArgContext(p *FunctionArgContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = CqlParserRULE_functionArg +} + +func (*FunctionArgContext) IsFunctionArgContext() {} + +func NewFunctionArgContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *FunctionArgContext { + var p = new(FunctionArgContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = CqlParserRULE_functionArg + + return p +} + +func (s *FunctionArgContext) GetParser() antlr.Parser { return s.parser } + +func (s *FunctionArgContext) ValueAny() IValueAnyContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IValueAnyContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IValueAnyContext) +} + +func (s *FunctionArgContext) Column() IColumnContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IColumnContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IColumnContext) +} + +func (s *FunctionArgContext) STAR() antlr.TerminalNode { + return s.GetToken(CqlParserSTAR, 0) +} + +func (s *FunctionArgContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *FunctionArgContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *FunctionArgContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(CqlParserListener); ok { + listenerT.EnterFunctionArg(s) + } +} + +func (s *FunctionArgContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(CqlParserListener); ok { + listenerT.ExitFunctionArg(s) + } +} + +func (p *CqlParser) FunctionArg() (localctx IFunctionArgContext) { + localctx = NewFunctionArgContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 358, CqlParserRULE_functionArg) + p.SetState(2127) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit } - _la = p.GetTokenStream().LA(1) - for _la == CqlParserCOMMA { + switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 170, p.GetParserRuleContext()) { + case 1: + p.EnterOuterAlt(localctx, 1) { - p.SetState(2114) - p.SyntaxComma() - } - p.SetState(2118) - p.GetErrorHandler().Sync(p) - if p.HasError() { - goto errorExit + p.SetState(2124) + p.ValueAny() } - switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 172, p.GetParserRuleContext()) { - case 1: - { - p.SetState(2115) - p.Constant() - } - - case 2: - { - p.SetState(2116) - p.Match(CqlParserOBJECT_NAME) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } + case 2: + p.EnterOuterAlt(localctx, 2) + { + p.SetState(2125) + p.Column() + } - case 3: - { - p.SetState(2117) - p.FunctionCall() + case 3: + p.EnterOuterAlt(localctx, 3) + { + p.SetState(2126) + p.Match(CqlParserSTAR) + if p.HasError() { + // Recognition error - abort rule + goto errorExit } - - case antlr.ATNInvalidAltNumber: - goto errorExit } - p.SetState(2124) - p.GetErrorHandler().Sync(p) - if p.HasError() { - goto errorExit - } - _la = p.GetTokenStream().LA(1) + case antlr.ATNInvalidAltNumber: + goto errorExit } errorExit: @@ -37197,60 +37579,60 @@ func (s *ValueAnyContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) ValueAny() (localctx IValueAnyContext) { localctx = NewValueAnyContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 352, CqlParserRULE_valueAny) - p.SetState(2132) + p.EnterRule(localctx, 360, CqlParserRULE_valueAny) + p.SetState(2136) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit } - switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 174, p.GetParserRuleContext()) { + switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 171, p.GetParserRuleContext()) { case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(2125) + p.SetState(2129) p.Marker() } case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(2126) + p.SetState(2130) p.Constant() } case 3: p.EnterOuterAlt(localctx, 3) { - p.SetState(2127) + p.SetState(2131) p.FunctionCall() } case 4: p.EnterOuterAlt(localctx, 4) { - p.SetState(2128) + p.SetState(2132) p.ValueMap() } case 5: p.EnterOuterAlt(localctx, 5) { - p.SetState(2129) + p.SetState(2133) p.ValueSet() } case 6: p.EnterOuterAlt(localctx, 6) { - p.SetState(2130) + p.SetState(2134) p.ValueList() } case 7: p.EnterOuterAlt(localctx, 7) { - p.SetState(2131) + p.SetState(2135) p.AssignmentTuple() } @@ -37479,32 +37861,32 @@ func (s *ConstantContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Constant() (localctx IConstantContext) { localctx = NewConstantContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 354, CqlParserRULE_constant) - p.SetState(2143) + p.EnterRule(localctx, 362, CqlParserRULE_constant) + p.SetState(2147) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit } - switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 175, p.GetParserRuleContext()) { + switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 172, p.GetParserRuleContext()) { case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(2134) + p.SetState(2138) p.Marker() } case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(2135) + p.SetState(2139) p.KwNull() } case 3: p.EnterOuterAlt(localctx, 3) { - p.SetState(2136) + p.SetState(2140) p.Match(CqlParserUUID) if p.HasError() { // Recognition error - abort rule @@ -37515,42 +37897,42 @@ func (p *CqlParser) Constant() (localctx IConstantContext) { case 4: p.EnterOuterAlt(localctx, 4) { - p.SetState(2137) + p.SetState(2141) p.StringLiteral() } case 5: p.EnterOuterAlt(localctx, 5) { - p.SetState(2138) + p.SetState(2142) p.DecimalLiteral() } case 6: p.EnterOuterAlt(localctx, 6) { - p.SetState(2139) + p.SetState(2143) p.FloatLiteral() } case 7: p.EnterOuterAlt(localctx, 7) { - p.SetState(2140) + p.SetState(2144) p.HexadecimalLiteral() } case 8: p.EnterOuterAlt(localctx, 8) { - p.SetState(2141) + p.SetState(2145) p.BooleanLiteral() } case 9: p.EnterOuterAlt(localctx, 9) { - p.SetState(2142) + p.SetState(2146) p.CodeBlock() } @@ -37643,10 +38025,10 @@ func (s *DecimalLiteralContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) DecimalLiteral() (localctx IDecimalLiteralContext) { localctx = NewDecimalLiteralContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 356, CqlParserRULE_decimalLiteral) + p.EnterRule(localctx, 364, CqlParserRULE_decimalLiteral) p.EnterOuterAlt(localctx, 1) { - p.SetState(2145) + p.SetState(2149) p.Match(CqlParserDECIMAL_LITERAL) if p.HasError() { // Recognition error - abort rule @@ -37744,12 +38126,12 @@ func (s *FloatLiteralContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) FloatLiteral() (localctx IFloatLiteralContext) { localctx = NewFloatLiteralContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 358, CqlParserRULE_floatLiteral) + p.EnterRule(localctx, 366, CqlParserRULE_floatLiteral) var _la int p.EnterOuterAlt(localctx, 1) { - p.SetState(2147) + p.SetState(2151) _la = p.GetTokenStream().LA(1) if !(_la == CqlParserDECIMAL_LITERAL || _la == CqlParserFLOAT_LITERAL) { @@ -37845,10 +38227,10 @@ func (s *StringLiteralContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) StringLiteral() (localctx IStringLiteralContext) { localctx = NewStringLiteralContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 360, CqlParserRULE_stringLiteral) + p.EnterRule(localctx, 368, CqlParserRULE_stringLiteral) p.EnterOuterAlt(localctx, 1) { - p.SetState(2149) + p.SetState(2153) p.Match(CqlParserSTRING_LITERAL) if p.HasError() { // Recognition error - abort rule @@ -37946,12 +38328,12 @@ func (s *BooleanLiteralContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) BooleanLiteral() (localctx IBooleanLiteralContext) { localctx = NewBooleanLiteralContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 362, CqlParserRULE_booleanLiteral) + p.EnterRule(localctx, 370, CqlParserRULE_booleanLiteral) var _la int p.EnterOuterAlt(localctx, 1) { - p.SetState(2151) + p.SetState(2155) _la = p.GetTokenStream().LA(1) if !(_la == CqlParserK_FALSE || _la == CqlParserK_TRUE) { @@ -38047,10 +38429,10 @@ func (s *HexadecimalLiteralContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) HexadecimalLiteral() (localctx IHexadecimalLiteralContext) { localctx = NewHexadecimalLiteralContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 364, CqlParserRULE_hexadecimalLiteral) + p.EnterRule(localctx, 372, CqlParserRULE_hexadecimalLiteral) p.EnterOuterAlt(localctx, 1) { - p.SetState(2153) + p.SetState(2157) p.Match(CqlParserHEXADECIMAL_LITERAL) if p.HasError() { // Recognition error - abort rule @@ -38153,8 +38535,8 @@ func (s *KeyspaceContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Keyspace() (localctx IKeyspaceContext) { localctx = NewKeyspaceContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 366, CqlParserRULE_keyspace) - p.SetState(2159) + p.EnterRule(localctx, 374, CqlParserRULE_keyspace) + p.SetState(2163) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -38164,7 +38546,7 @@ func (p *CqlParser) Keyspace() (localctx IKeyspaceContext) { case CqlParserOBJECT_NAME: p.EnterOuterAlt(localctx, 1) { - p.SetState(2155) + p.SetState(2159) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -38175,7 +38557,7 @@ func (p *CqlParser) Keyspace() (localctx IKeyspaceContext) { case CqlParserDQUOTE: p.EnterOuterAlt(localctx, 2) { - p.SetState(2156) + p.SetState(2160) p.Match(CqlParserDQUOTE) if p.HasError() { // Recognition error - abort rule @@ -38183,7 +38565,7 @@ func (p *CqlParser) Keyspace() (localctx IKeyspaceContext) { } } { - p.SetState(2157) + p.SetState(2161) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -38191,7 +38573,7 @@ func (p *CqlParser) Keyspace() (localctx IKeyspaceContext) { } } { - p.SetState(2158) + p.SetState(2162) p.Match(CqlParserDQUOTE) if p.HasError() { // Recognition error - abort rule @@ -38314,8 +38696,8 @@ func (s *TableContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Table() (localctx ITableContext) { localctx = NewTableContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 368, CqlParserRULE_table) - p.SetState(2168) + p.EnterRule(localctx, 376, CqlParserRULE_table) + p.SetState(2172) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -38325,7 +38707,7 @@ func (p *CqlParser) Table() (localctx ITableContext) { case CqlParserOBJECT_NAME: p.EnterOuterAlt(localctx, 1) { - p.SetState(2161) + p.SetState(2165) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -38336,7 +38718,7 @@ func (p *CqlParser) Table() (localctx ITableContext) { case CqlParserK_KEYSPACES: p.EnterOuterAlt(localctx, 2) { - p.SetState(2162) + p.SetState(2166) p.Match(CqlParserK_KEYSPACES) if p.HasError() { // Recognition error - abort rule @@ -38347,7 +38729,7 @@ func (p *CqlParser) Table() (localctx ITableContext) { case CqlParserK_TABLES: p.EnterOuterAlt(localctx, 3) { - p.SetState(2163) + p.SetState(2167) p.Match(CqlParserK_TABLES) if p.HasError() { // Recognition error - abort rule @@ -38358,7 +38740,7 @@ func (p *CqlParser) Table() (localctx ITableContext) { case CqlParserK_FUNCTIONS: p.EnterOuterAlt(localctx, 4) { - p.SetState(2164) + p.SetState(2168) p.Match(CqlParserK_FUNCTIONS) if p.HasError() { // Recognition error - abort rule @@ -38369,7 +38751,7 @@ func (p *CqlParser) Table() (localctx ITableContext) { case CqlParserDQUOTE: p.EnterOuterAlt(localctx, 5) { - p.SetState(2165) + p.SetState(2169) p.Match(CqlParserDQUOTE) if p.HasError() { // Recognition error - abort rule @@ -38377,7 +38759,7 @@ func (p *CqlParser) Table() (localctx ITableContext) { } } { - p.SetState(2166) + p.SetState(2170) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -38385,7 +38767,7 @@ func (p *CqlParser) Table() (localctx ITableContext) { } } { - p.SetState(2167) + p.SetState(2171) p.Match(CqlParserDQUOTE) if p.HasError() { // Recognition error - abort rule @@ -38515,8 +38897,8 @@ func (s *ColumnContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Column() (localctx IColumnContext) { localctx = NewColumnContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 370, CqlParserRULE_column) - p.SetState(2176) + p.EnterRule(localctx, 378, CqlParserRULE_column) + p.SetState(2180) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -38526,7 +38908,7 @@ func (p *CqlParser) Column() (localctx IColumnContext) { case CqlParserOBJECT_NAME: p.EnterOuterAlt(localctx, 1) { - p.SetState(2170) + p.SetState(2174) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -38537,14 +38919,14 @@ func (p *CqlParser) Column() (localctx IColumnContext) { case CqlParserK_TYPE: p.EnterOuterAlt(localctx, 2) { - p.SetState(2171) + p.SetState(2175) p.KwType() } case CqlParserK_KEY: p.EnterOuterAlt(localctx, 3) { - p.SetState(2172) + p.SetState(2176) p.Match(CqlParserK_KEY) if p.HasError() { // Recognition error - abort rule @@ -38555,7 +38937,7 @@ func (p *CqlParser) Column() (localctx IColumnContext) { case CqlParserDQUOTE: p.EnterOuterAlt(localctx, 4) { - p.SetState(2173) + p.SetState(2177) p.Match(CqlParserDQUOTE) if p.HasError() { // Recognition error - abort rule @@ -38563,7 +38945,7 @@ func (p *CqlParser) Column() (localctx IColumnContext) { } } { - p.SetState(2174) + p.SetState(2178) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -38571,7 +38953,7 @@ func (p *CqlParser) Column() (localctx IColumnContext) { } } { - p.SetState(2175) + p.SetState(2179) p.Match(CqlParserDQUOTE) if p.HasError() { // Recognition error - abort rule @@ -38698,15 +39080,15 @@ func (s *DataTypeContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) DataType() (localctx IDataTypeContext) { localctx = NewDataTypeContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 372, CqlParserRULE_dataType) + p.EnterRule(localctx, 380, CqlParserRULE_dataType) var _la int p.EnterOuterAlt(localctx, 1) { - p.SetState(2178) + p.SetState(2182) p.DataTypeName() } - p.SetState(2180) + p.SetState(2184) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -38715,7 +39097,7 @@ func (p *CqlParser) DataType() (localctx IDataTypeContext) { if _la == CqlParserOPERATOR_LT { { - p.SetState(2179) + p.SetState(2183) p.DataTypeDefinition() } @@ -38931,12 +39313,12 @@ func (s *DataTypeNameContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) DataTypeName() (localctx IDataTypeNameContext) { localctx = NewDataTypeNameContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 374, CqlParserRULE_dataTypeName) + p.EnterRule(localctx, 382, CqlParserRULE_dataTypeName) var _la int p.EnterOuterAlt(localctx, 1) { - p.SetState(2182) + p.SetState(2186) _la = p.GetTokenStream().LA(1) if !(((int64((_la-84)) & ^0x3f) == 0 && ((int64(1)<<(_la-84))&-9079248035506028543) != 0) || ((int64((_la-148)) & ^0x3f) == 0 && ((int64(1)<<(_la-148))&68157439) != 0)) { @@ -39147,19 +39529,19 @@ func (s *DataTypeDefinitionContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) DataTypeDefinition() (localctx IDataTypeDefinitionContext) { localctx = NewDataTypeDefinitionContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 376, CqlParserRULE_dataTypeDefinition) + p.EnterRule(localctx, 384, CqlParserRULE_dataTypeDefinition) var _la int p.EnterOuterAlt(localctx, 1) { - p.SetState(2184) + p.SetState(2188) p.SyntaxBracketLa() } { - p.SetState(2185) + p.SetState(2189) p.DataType() } - p.SetState(2191) + p.SetState(2195) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -39168,15 +39550,15 @@ func (p *CqlParser) DataTypeDefinition() (localctx IDataTypeDefinitionContext) { for _la == CqlParserCOMMA { { - p.SetState(2186) + p.SetState(2190) p.SyntaxComma() } { - p.SetState(2187) + p.SetState(2191) p.DataType() } - p.SetState(2193) + p.SetState(2197) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -39184,7 +39566,7 @@ func (p *CqlParser) DataTypeDefinition() (localctx IDataTypeDefinitionContext) { _la = p.GetTokenStream().LA(1) } { - p.SetState(2194) + p.SetState(2198) p.SyntaxBracketRa() } @@ -39302,8 +39684,8 @@ func (s *OrderDirectionContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) OrderDirection() (localctx IOrderDirectionContext) { localctx = NewOrderDirectionContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 378, CqlParserRULE_orderDirection) - p.SetState(2198) + p.EnterRule(localctx, 386, CqlParserRULE_orderDirection) + p.SetState(2202) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -39313,14 +39695,14 @@ func (p *CqlParser) OrderDirection() (localctx IOrderDirectionContext) { case CqlParserK_ASC: p.EnterOuterAlt(localctx, 1) { - p.SetState(2196) + p.SetState(2200) p.KwAsc() } case CqlParserK_DESC: p.EnterOuterAlt(localctx, 2) { - p.SetState(2197) + p.SetState(2201) p.KwDesc() } @@ -39414,10 +39796,10 @@ func (s *RoleContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Role() (localctx IRoleContext) { localctx = NewRoleContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 380, CqlParserRULE_role) + p.EnterRule(localctx, 388, CqlParserRULE_role) p.EnterOuterAlt(localctx, 1) { - p.SetState(2200) + p.SetState(2204) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -39510,10 +39892,10 @@ func (s *TriggerContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Trigger() (localctx ITriggerContext) { localctx = NewTriggerContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 382, CqlParserRULE_trigger) + p.EnterRule(localctx, 390, CqlParserRULE_trigger) p.EnterOuterAlt(localctx, 1) { - p.SetState(2202) + p.SetState(2206) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -39618,10 +40000,10 @@ func (s *TriggerClassContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) TriggerClass() (localctx ITriggerClassContext) { localctx = NewTriggerClassContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 384, CqlParserRULE_triggerClass) + p.EnterRule(localctx, 392, CqlParserRULE_triggerClass) p.EnterOuterAlt(localctx, 1) { - p.SetState(2204) + p.SetState(2208) p.StringLiteral() } @@ -39710,10 +40092,10 @@ func (s *MaterializedViewContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) MaterializedView() (localctx IMaterializedViewContext) { localctx = NewMaterializedViewContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 386, CqlParserRULE_materializedView) + p.EnterRule(localctx, 394, CqlParserRULE_materializedView) p.EnterOuterAlt(localctx, 1) { - p.SetState(2206) + p.SetState(2210) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -39806,10 +40188,10 @@ func (s *Type_Context) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Type_() (localctx IType_Context) { localctx = NewType_Context(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 388, CqlParserRULE_type_) + p.EnterRule(localctx, 396, CqlParserRULE_type_) p.EnterOuterAlt(localctx, 1) { - p.SetState(2208) + p.SetState(2212) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -39902,10 +40284,10 @@ func (s *AggregateContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Aggregate() (localctx IAggregateContext) { localctx = NewAggregateContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 390, CqlParserRULE_aggregate) + p.EnterRule(localctx, 398, CqlParserRULE_aggregate) p.EnterOuterAlt(localctx, 1) { - p.SetState(2210) + p.SetState(2214) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -39998,10 +40380,10 @@ func (s *Function_Context) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Function_() (localctx IFunction_Context) { localctx = NewFunction_Context(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 392, CqlParserRULE_function_) + p.EnterRule(localctx, 400, CqlParserRULE_function_) p.EnterOuterAlt(localctx, 1) { - p.SetState(2212) + p.SetState(2216) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -40094,10 +40476,10 @@ func (s *LanguageContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Language() (localctx ILanguageContext) { localctx = NewLanguageContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 394, CqlParserRULE_language) + p.EnterRule(localctx, 402, CqlParserRULE_language) p.EnterOuterAlt(localctx, 1) { - p.SetState(2214) + p.SetState(2218) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -40190,10 +40572,10 @@ func (s *UserContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) User() (localctx IUserContext) { localctx = NewUserContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 396, CqlParserRULE_user) + p.EnterRule(localctx, 404, CqlParserRULE_user) p.EnterOuterAlt(localctx, 1) { - p.SetState(2216) + p.SetState(2220) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -40298,10 +40680,10 @@ func (s *PasswordContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Password() (localctx IPasswordContext) { localctx = NewPasswordContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 398, CqlParserRULE_password) + p.EnterRule(localctx, 406, CqlParserRULE_password) p.EnterOuterAlt(localctx, 1) { - p.SetState(2218) + p.SetState(2222) p.StringLiteral() } @@ -40390,10 +40772,10 @@ func (s *HashKeyContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) HashKey() (localctx IHashKeyContext) { localctx = NewHashKeyContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 400, CqlParserRULE_hashKey) + p.EnterRule(localctx, 408, CqlParserRULE_hashKey) p.EnterOuterAlt(localctx, 1) { - p.SetState(2220) + p.SetState(2224) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule @@ -40515,14 +40897,14 @@ func (s *ParamContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) Param() (localctx IParamContext) { localctx = NewParamContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 402, CqlParserRULE_param) + p.EnterRule(localctx, 410, CqlParserRULE_param) p.EnterOuterAlt(localctx, 1) { - p.SetState(2222) + p.SetState(2226) p.ParamName() } { - p.SetState(2223) + p.SetState(2227) p.DataType() } @@ -40616,12 +40998,12 @@ func (s *ParamNameContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) ParamName() (localctx IParamNameContext) { localctx = NewParamNameContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 404, CqlParserRULE_paramName) + p.EnterRule(localctx, 412, CqlParserRULE_paramName) var _la int p.EnterOuterAlt(localctx, 1) { - p.SetState(2225) + p.SetState(2229) _la = p.GetTokenStream().LA(1) if !(_la == CqlParserK_INPUT || _la == CqlParserOBJECT_NAME) { @@ -40717,10 +41099,10 @@ func (s *KwAddContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwAdd() (localctx IKwAddContext) { localctx = NewKwAddContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 406, CqlParserRULE_kwAdd) + p.EnterRule(localctx, 414, CqlParserRULE_kwAdd) p.EnterOuterAlt(localctx, 1) { - p.SetState(2227) + p.SetState(2231) p.Match(CqlParserK_ADD) if p.HasError() { // Recognition error - abort rule @@ -40813,10 +41195,10 @@ func (s *KwAggregateContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwAggregate() (localctx IKwAggregateContext) { localctx = NewKwAggregateContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 408, CqlParserRULE_kwAggregate) + p.EnterRule(localctx, 416, CqlParserRULE_kwAggregate) p.EnterOuterAlt(localctx, 1) { - p.SetState(2229) + p.SetState(2233) p.Match(CqlParserK_AGGREGATE) if p.HasError() { // Recognition error - abort rule @@ -40909,10 +41291,10 @@ func (s *KwAllContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwAll() (localctx IKwAllContext) { localctx = NewKwAllContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 410, CqlParserRULE_kwAll) + p.EnterRule(localctx, 418, CqlParserRULE_kwAll) p.EnterOuterAlt(localctx, 1) { - p.SetState(2231) + p.SetState(2235) p.Match(CqlParserK_ALL) if p.HasError() { // Recognition error - abort rule @@ -41010,10 +41392,10 @@ func (s *KwAllPermissionsContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwAllPermissions() (localctx IKwAllPermissionsContext) { localctx = NewKwAllPermissionsContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 412, CqlParserRULE_kwAllPermissions) + p.EnterRule(localctx, 420, CqlParserRULE_kwAllPermissions) p.EnterOuterAlt(localctx, 1) { - p.SetState(2233) + p.SetState(2237) p.Match(CqlParserK_ALL) if p.HasError() { // Recognition error - abort rule @@ -41021,7 +41403,7 @@ func (p *CqlParser) KwAllPermissions() (localctx IKwAllPermissionsContext) { } } { - p.SetState(2234) + p.SetState(2238) p.Match(CqlParserK_PERMISSIONS) if p.HasError() { // Recognition error - abort rule @@ -41114,10 +41496,10 @@ func (s *KwAllowContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwAllow() (localctx IKwAllowContext) { localctx = NewKwAllowContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 414, CqlParserRULE_kwAllow) + p.EnterRule(localctx, 422, CqlParserRULE_kwAllow) p.EnterOuterAlt(localctx, 1) { - p.SetState(2236) + p.SetState(2240) p.Match(CqlParserK_ALLOW) if p.HasError() { // Recognition error - abort rule @@ -41210,10 +41592,10 @@ func (s *KwAlterContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwAlter() (localctx IKwAlterContext) { localctx = NewKwAlterContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 416, CqlParserRULE_kwAlter) + p.EnterRule(localctx, 424, CqlParserRULE_kwAlter) p.EnterOuterAlt(localctx, 1) { - p.SetState(2238) + p.SetState(2242) p.Match(CqlParserK_ALTER) if p.HasError() { // Recognition error - abort rule @@ -41306,10 +41688,10 @@ func (s *KwAndContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwAnd() (localctx IKwAndContext) { localctx = NewKwAndContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 418, CqlParserRULE_kwAnd) + p.EnterRule(localctx, 426, CqlParserRULE_kwAnd) p.EnterOuterAlt(localctx, 1) { - p.SetState(2240) + p.SetState(2244) p.Match(CqlParserK_AND) if p.HasError() { // Recognition error - abort rule @@ -41402,10 +41784,10 @@ func (s *KwApplyContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwApply() (localctx IKwApplyContext) { localctx = NewKwApplyContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 420, CqlParserRULE_kwApply) + p.EnterRule(localctx, 428, CqlParserRULE_kwApply) p.EnterOuterAlt(localctx, 1) { - p.SetState(2242) + p.SetState(2246) p.Match(CqlParserK_APPLY) if p.HasError() { // Recognition error - abort rule @@ -41498,10 +41880,10 @@ func (s *KwAsContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwAs() (localctx IKwAsContext) { localctx = NewKwAsContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 422, CqlParserRULE_kwAs) + p.EnterRule(localctx, 430, CqlParserRULE_kwAs) p.EnterOuterAlt(localctx, 1) { - p.SetState(2244) + p.SetState(2248) p.Match(CqlParserK_AS) if p.HasError() { // Recognition error - abort rule @@ -41594,10 +41976,10 @@ func (s *KwAscContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwAsc() (localctx IKwAscContext) { localctx = NewKwAscContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 424, CqlParserRULE_kwAsc) + p.EnterRule(localctx, 432, CqlParserRULE_kwAsc) p.EnterOuterAlt(localctx, 1) { - p.SetState(2246) + p.SetState(2250) p.Match(CqlParserK_ASC) if p.HasError() { // Recognition error - abort rule @@ -41690,10 +42072,10 @@ func (s *KwAuthorizeContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwAuthorize() (localctx IKwAuthorizeContext) { localctx = NewKwAuthorizeContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 426, CqlParserRULE_kwAuthorize) + p.EnterRule(localctx, 434, CqlParserRULE_kwAuthorize) p.EnterOuterAlt(localctx, 1) { - p.SetState(2248) + p.SetState(2252) p.Match(CqlParserK_AUTHORIZE) if p.HasError() { // Recognition error - abort rule @@ -41786,10 +42168,10 @@ func (s *KwBatchContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwBatch() (localctx IKwBatchContext) { localctx = NewKwBatchContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 428, CqlParserRULE_kwBatch) + p.EnterRule(localctx, 436, CqlParserRULE_kwBatch) p.EnterOuterAlt(localctx, 1) { - p.SetState(2250) + p.SetState(2254) p.Match(CqlParserK_BATCH) if p.HasError() { // Recognition error - abort rule @@ -41882,10 +42264,10 @@ func (s *KwBetweenContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwBetween() (localctx IKwBetweenContext) { localctx = NewKwBetweenContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 430, CqlParserRULE_kwBetween) + p.EnterRule(localctx, 438, CqlParserRULE_kwBetween) p.EnterOuterAlt(localctx, 1) { - p.SetState(2252) + p.SetState(2256) p.Match(CqlParserK_BETWEEN) if p.HasError() { // Recognition error - abort rule @@ -41978,10 +42360,10 @@ func (s *KwBeginContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwBegin() (localctx IKwBeginContext) { localctx = NewKwBeginContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 432, CqlParserRULE_kwBegin) + p.EnterRule(localctx, 440, CqlParserRULE_kwBegin) p.EnterOuterAlt(localctx, 1) { - p.SetState(2254) + p.SetState(2258) p.Match(CqlParserK_BEGIN) if p.HasError() { // Recognition error - abort rule @@ -42074,10 +42456,10 @@ func (s *KwByContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwBy() (localctx IKwByContext) { localctx = NewKwByContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 434, CqlParserRULE_kwBy) + p.EnterRule(localctx, 442, CqlParserRULE_kwBy) p.EnterOuterAlt(localctx, 1) { - p.SetState(2256) + p.SetState(2260) p.Match(CqlParserK_BY) if p.HasError() { // Recognition error - abort rule @@ -42170,10 +42552,10 @@ func (s *KwCalledContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwCalled() (localctx IKwCalledContext) { localctx = NewKwCalledContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 436, CqlParserRULE_kwCalled) + p.EnterRule(localctx, 444, CqlParserRULE_kwCalled) p.EnterOuterAlt(localctx, 1) { - p.SetState(2258) + p.SetState(2262) p.Match(CqlParserK_CALLED) if p.HasError() { // Recognition error - abort rule @@ -42266,10 +42648,10 @@ func (s *KwClusteringContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwClustering() (localctx IKwClusteringContext) { localctx = NewKwClusteringContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 438, CqlParserRULE_kwClustering) + p.EnterRule(localctx, 446, CqlParserRULE_kwClustering) p.EnterOuterAlt(localctx, 1) { - p.SetState(2260) + p.SetState(2264) p.Match(CqlParserK_CLUSTERING) if p.HasError() { // Recognition error - abort rule @@ -42362,10 +42744,10 @@ func (s *KwCompactContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwCompact() (localctx IKwCompactContext) { localctx = NewKwCompactContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 440, CqlParserRULE_kwCompact) + p.EnterRule(localctx, 448, CqlParserRULE_kwCompact) p.EnterOuterAlt(localctx, 1) { - p.SetState(2262) + p.SetState(2266) p.Match(CqlParserK_COMPACT) if p.HasError() { // Recognition error - abort rule @@ -42458,10 +42840,10 @@ func (s *KwContainsContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwContains() (localctx IKwContainsContext) { localctx = NewKwContainsContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 442, CqlParserRULE_kwContains) + p.EnterRule(localctx, 450, CqlParserRULE_kwContains) p.EnterOuterAlt(localctx, 1) { - p.SetState(2264) + p.SetState(2268) p.Match(CqlParserK_CONTAINS) if p.HasError() { // Recognition error - abort rule @@ -42554,10 +42936,10 @@ func (s *KwCreateContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwCreate() (localctx IKwCreateContext) { localctx = NewKwCreateContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 444, CqlParserRULE_kwCreate) + p.EnterRule(localctx, 452, CqlParserRULE_kwCreate) p.EnterOuterAlt(localctx, 1) { - p.SetState(2266) + p.SetState(2270) p.Match(CqlParserK_CREATE) if p.HasError() { // Recognition error - abort rule @@ -42650,10 +43032,10 @@ func (s *KwDeleteContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwDelete() (localctx IKwDeleteContext) { localctx = NewKwDeleteContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 446, CqlParserRULE_kwDelete) + p.EnterRule(localctx, 454, CqlParserRULE_kwDelete) p.EnterOuterAlt(localctx, 1) { - p.SetState(2268) + p.SetState(2272) p.Match(CqlParserK_DELETE) if p.HasError() { // Recognition error - abort rule @@ -42746,10 +43128,10 @@ func (s *KwDescContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwDesc() (localctx IKwDescContext) { localctx = NewKwDescContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 448, CqlParserRULE_kwDesc) + p.EnterRule(localctx, 456, CqlParserRULE_kwDesc) p.EnterOuterAlt(localctx, 1) { - p.SetState(2270) + p.SetState(2274) p.Match(CqlParserK_DESC) if p.HasError() { // Recognition error - abort rule @@ -42842,10 +43224,10 @@ func (s *KwDescibeContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwDescibe() (localctx IKwDescibeContext) { localctx = NewKwDescibeContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 450, CqlParserRULE_kwDescibe) + p.EnterRule(localctx, 458, CqlParserRULE_kwDescibe) p.EnterOuterAlt(localctx, 1) { - p.SetState(2272) + p.SetState(2276) p.Match(CqlParserK_DESCRIBE) if p.HasError() { // Recognition error - abort rule @@ -42938,10 +43320,10 @@ func (s *KwDistinctContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwDistinct() (localctx IKwDistinctContext) { localctx = NewKwDistinctContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 452, CqlParserRULE_kwDistinct) + p.EnterRule(localctx, 460, CqlParserRULE_kwDistinct) p.EnterOuterAlt(localctx, 1) { - p.SetState(2274) + p.SetState(2278) p.Match(CqlParserK_DISTINCT) if p.HasError() { // Recognition error - abort rule @@ -43034,10 +43416,10 @@ func (s *KwDropContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwDrop() (localctx IKwDropContext) { localctx = NewKwDropContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 454, CqlParserRULE_kwDrop) + p.EnterRule(localctx, 462, CqlParserRULE_kwDrop) p.EnterOuterAlt(localctx, 1) { - p.SetState(2276) + p.SetState(2280) p.Match(CqlParserK_DROP) if p.HasError() { // Recognition error - abort rule @@ -43130,10 +43512,10 @@ func (s *KwDurableWritesContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwDurableWrites() (localctx IKwDurableWritesContext) { localctx = NewKwDurableWritesContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 456, CqlParserRULE_kwDurableWrites) + p.EnterRule(localctx, 464, CqlParserRULE_kwDurableWrites) p.EnterOuterAlt(localctx, 1) { - p.SetState(2278) + p.SetState(2282) p.Match(CqlParserK_DURABLE_WRITES) if p.HasError() { // Recognition error - abort rule @@ -43226,10 +43608,10 @@ func (s *KwEntriesContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwEntries() (localctx IKwEntriesContext) { localctx = NewKwEntriesContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 458, CqlParserRULE_kwEntries) + p.EnterRule(localctx, 466, CqlParserRULE_kwEntries) p.EnterOuterAlt(localctx, 1) { - p.SetState(2280) + p.SetState(2284) p.Match(CqlParserK_ENTRIES) if p.HasError() { // Recognition error - abort rule @@ -43322,10 +43704,10 @@ func (s *KwExecuteContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwExecute() (localctx IKwExecuteContext) { localctx = NewKwExecuteContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 460, CqlParserRULE_kwExecute) + p.EnterRule(localctx, 468, CqlParserRULE_kwExecute) p.EnterOuterAlt(localctx, 1) { - p.SetState(2282) + p.SetState(2286) p.Match(CqlParserK_EXECUTE) if p.HasError() { // Recognition error - abort rule @@ -43418,10 +43800,10 @@ func (s *KwExistsContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwExists() (localctx IKwExistsContext) { localctx = NewKwExistsContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 462, CqlParserRULE_kwExists) + p.EnterRule(localctx, 470, CqlParserRULE_kwExists) p.EnterOuterAlt(localctx, 1) { - p.SetState(2284) + p.SetState(2288) p.Match(CqlParserK_EXISTS) if p.HasError() { // Recognition error - abort rule @@ -43514,10 +43896,10 @@ func (s *KwFilteringContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwFiltering() (localctx IKwFilteringContext) { localctx = NewKwFilteringContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 464, CqlParserRULE_kwFiltering) + p.EnterRule(localctx, 472, CqlParserRULE_kwFiltering) p.EnterOuterAlt(localctx, 1) { - p.SetState(2286) + p.SetState(2290) p.Match(CqlParserK_FILTERING) if p.HasError() { // Recognition error - abort rule @@ -43610,10 +43992,10 @@ func (s *KwFinalfuncContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwFinalfunc() (localctx IKwFinalfuncContext) { localctx = NewKwFinalfuncContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 466, CqlParserRULE_kwFinalfunc) + p.EnterRule(localctx, 474, CqlParserRULE_kwFinalfunc) p.EnterOuterAlt(localctx, 1) { - p.SetState(2288) + p.SetState(2292) p.Match(CqlParserK_FINALFUNC) if p.HasError() { // Recognition error - abort rule @@ -43706,10 +44088,10 @@ func (s *KwFromContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwFrom() (localctx IKwFromContext) { localctx = NewKwFromContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 468, CqlParserRULE_kwFrom) + p.EnterRule(localctx, 476, CqlParserRULE_kwFrom) p.EnterOuterAlt(localctx, 1) { - p.SetState(2290) + p.SetState(2294) p.Match(CqlParserK_FROM) if p.HasError() { // Recognition error - abort rule @@ -43802,10 +44184,10 @@ func (s *KwFullContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwFull() (localctx IKwFullContext) { localctx = NewKwFullContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 470, CqlParserRULE_kwFull) + p.EnterRule(localctx, 478, CqlParserRULE_kwFull) p.EnterOuterAlt(localctx, 1) { - p.SetState(2292) + p.SetState(2296) p.Match(CqlParserK_FULL) if p.HasError() { // Recognition error - abort rule @@ -43898,10 +44280,10 @@ func (s *KwFunctionContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwFunction() (localctx IKwFunctionContext) { localctx = NewKwFunctionContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 472, CqlParserRULE_kwFunction) + p.EnterRule(localctx, 480, CqlParserRULE_kwFunction) p.EnterOuterAlt(localctx, 1) { - p.SetState(2294) + p.SetState(2298) p.Match(CqlParserK_FUNCTION) if p.HasError() { // Recognition error - abort rule @@ -43994,10 +44376,10 @@ func (s *KwFunctionsContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwFunctions() (localctx IKwFunctionsContext) { localctx = NewKwFunctionsContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 474, CqlParserRULE_kwFunctions) + p.EnterRule(localctx, 482, CqlParserRULE_kwFunctions) p.EnterOuterAlt(localctx, 1) { - p.SetState(2296) + p.SetState(2300) p.Match(CqlParserK_FUNCTIONS) if p.HasError() { // Recognition error - abort rule @@ -44090,10 +44472,10 @@ func (s *KwGrantContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwGrant() (localctx IKwGrantContext) { localctx = NewKwGrantContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 476, CqlParserRULE_kwGrant) + p.EnterRule(localctx, 484, CqlParserRULE_kwGrant) p.EnterOuterAlt(localctx, 1) { - p.SetState(2298) + p.SetState(2302) p.Match(CqlParserK_GRANT) if p.HasError() { // Recognition error - abort rule @@ -44186,10 +44568,10 @@ func (s *KwIfContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwIf() (localctx IKwIfContext) { localctx = NewKwIfContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 478, CqlParserRULE_kwIf) + p.EnterRule(localctx, 486, CqlParserRULE_kwIf) p.EnterOuterAlt(localctx, 1) { - p.SetState(2300) + p.SetState(2304) p.Match(CqlParserK_IF) if p.HasError() { // Recognition error - abort rule @@ -44282,10 +44664,10 @@ func (s *KwInContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwIn() (localctx IKwInContext) { localctx = NewKwInContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 480, CqlParserRULE_kwIn) + p.EnterRule(localctx, 488, CqlParserRULE_kwIn) p.EnterOuterAlt(localctx, 1) { - p.SetState(2302) + p.SetState(2306) p.Match(CqlParserK_IN) if p.HasError() { // Recognition error - abort rule @@ -44378,10 +44760,10 @@ func (s *KwIndexContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwIndex() (localctx IKwIndexContext) { localctx = NewKwIndexContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 482, CqlParserRULE_kwIndex) + p.EnterRule(localctx, 490, CqlParserRULE_kwIndex) p.EnterOuterAlt(localctx, 1) { - p.SetState(2304) + p.SetState(2308) p.Match(CqlParserK_INDEX) if p.HasError() { // Recognition error - abort rule @@ -44474,10 +44856,10 @@ func (s *KwInitcondContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwInitcond() (localctx IKwInitcondContext) { localctx = NewKwInitcondContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 484, CqlParserRULE_kwInitcond) + p.EnterRule(localctx, 492, CqlParserRULE_kwInitcond) p.EnterOuterAlt(localctx, 1) { - p.SetState(2306) + p.SetState(2310) p.Match(CqlParserK_INITCOND) if p.HasError() { // Recognition error - abort rule @@ -44570,10 +44952,10 @@ func (s *KwInputContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwInput() (localctx IKwInputContext) { localctx = NewKwInputContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 486, CqlParserRULE_kwInput) + p.EnterRule(localctx, 494, CqlParserRULE_kwInput) p.EnterOuterAlt(localctx, 1) { - p.SetState(2308) + p.SetState(2312) p.Match(CqlParserK_INPUT) if p.HasError() { // Recognition error - abort rule @@ -44666,10 +45048,10 @@ func (s *KwInsertContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwInsert() (localctx IKwInsertContext) { localctx = NewKwInsertContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 488, CqlParserRULE_kwInsert) + p.EnterRule(localctx, 496, CqlParserRULE_kwInsert) p.EnterOuterAlt(localctx, 1) { - p.SetState(2310) + p.SetState(2314) p.Match(CqlParserK_INSERT) if p.HasError() { // Recognition error - abort rule @@ -44762,10 +45144,10 @@ func (s *KwIntoContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwInto() (localctx IKwIntoContext) { localctx = NewKwIntoContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 490, CqlParserRULE_kwInto) + p.EnterRule(localctx, 498, CqlParserRULE_kwInto) p.EnterOuterAlt(localctx, 1) { - p.SetState(2312) + p.SetState(2316) p.Match(CqlParserK_INTO) if p.HasError() { // Recognition error - abort rule @@ -44858,10 +45240,10 @@ func (s *KwIsContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwIs() (localctx IKwIsContext) { localctx = NewKwIsContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 492, CqlParserRULE_kwIs) + p.EnterRule(localctx, 500, CqlParserRULE_kwIs) p.EnterOuterAlt(localctx, 1) { - p.SetState(2314) + p.SetState(2318) p.Match(CqlParserK_IS) if p.HasError() { // Recognition error - abort rule @@ -44954,10 +45336,10 @@ func (s *KwJsonContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwJson() (localctx IKwJsonContext) { localctx = NewKwJsonContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 494, CqlParserRULE_kwJson) + p.EnterRule(localctx, 502, CqlParserRULE_kwJson) p.EnterOuterAlt(localctx, 1) { - p.SetState(2316) + p.SetState(2320) p.Match(CqlParserK_JSON) if p.HasError() { // Recognition error - abort rule @@ -45050,10 +45432,10 @@ func (s *KwKeyContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwKey() (localctx IKwKeyContext) { localctx = NewKwKeyContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 496, CqlParserRULE_kwKey) + p.EnterRule(localctx, 504, CqlParserRULE_kwKey) p.EnterOuterAlt(localctx, 1) { - p.SetState(2318) + p.SetState(2322) p.Match(CqlParserK_KEY) if p.HasError() { // Recognition error - abort rule @@ -45146,10 +45528,10 @@ func (s *KwKeysContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwKeys() (localctx IKwKeysContext) { localctx = NewKwKeysContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 498, CqlParserRULE_kwKeys) + p.EnterRule(localctx, 506, CqlParserRULE_kwKeys) p.EnterOuterAlt(localctx, 1) { - p.SetState(2320) + p.SetState(2324) p.Match(CqlParserK_KEYS) if p.HasError() { // Recognition error - abort rule @@ -45242,10 +45624,10 @@ func (s *KwKeyspaceContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwKeyspace() (localctx IKwKeyspaceContext) { localctx = NewKwKeyspaceContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 500, CqlParserRULE_kwKeyspace) + p.EnterRule(localctx, 508, CqlParserRULE_kwKeyspace) p.EnterOuterAlt(localctx, 1) { - p.SetState(2322) + p.SetState(2326) p.Match(CqlParserK_KEYSPACE) if p.HasError() { // Recognition error - abort rule @@ -45338,10 +45720,10 @@ func (s *KwKeyspacesContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwKeyspaces() (localctx IKwKeyspacesContext) { localctx = NewKwKeyspacesContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 502, CqlParserRULE_kwKeyspaces) + p.EnterRule(localctx, 510, CqlParserRULE_kwKeyspaces) p.EnterOuterAlt(localctx, 1) { - p.SetState(2324) + p.SetState(2328) p.Match(CqlParserK_KEYSPACES) if p.HasError() { // Recognition error - abort rule @@ -45434,10 +45816,10 @@ func (s *KwLanguageContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwLanguage() (localctx IKwLanguageContext) { localctx = NewKwLanguageContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 504, CqlParserRULE_kwLanguage) + p.EnterRule(localctx, 512, CqlParserRULE_kwLanguage) p.EnterOuterAlt(localctx, 1) { - p.SetState(2326) + p.SetState(2330) p.Match(CqlParserK_LANGUAGE) if p.HasError() { // Recognition error - abort rule @@ -45530,10 +45912,10 @@ func (s *KwLimitContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwLimit() (localctx IKwLimitContext) { localctx = NewKwLimitContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 506, CqlParserRULE_kwLimit) + p.EnterRule(localctx, 514, CqlParserRULE_kwLimit) p.EnterOuterAlt(localctx, 1) { - p.SetState(2328) + p.SetState(2332) p.Match(CqlParserK_LIMIT) if p.HasError() { // Recognition error - abort rule @@ -45626,10 +46008,10 @@ func (s *KwListContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwList() (localctx IKwListContext) { localctx = NewKwListContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 508, CqlParserRULE_kwList) + p.EnterRule(localctx, 516, CqlParserRULE_kwList) p.EnterOuterAlt(localctx, 1) { - p.SetState(2330) + p.SetState(2334) p.Match(CqlParserK_LIST) if p.HasError() { // Recognition error - abort rule @@ -45722,10 +46104,10 @@ func (s *KwLoggedContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwLogged() (localctx IKwLoggedContext) { localctx = NewKwLoggedContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 510, CqlParserRULE_kwLogged) + p.EnterRule(localctx, 518, CqlParserRULE_kwLogged) p.EnterOuterAlt(localctx, 1) { - p.SetState(2332) + p.SetState(2336) p.Match(CqlParserK_LOGGED) if p.HasError() { // Recognition error - abort rule @@ -45818,10 +46200,10 @@ func (s *KwLoginContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwLogin() (localctx IKwLoginContext) { localctx = NewKwLoginContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 512, CqlParserRULE_kwLogin) + p.EnterRule(localctx, 520, CqlParserRULE_kwLogin) p.EnterOuterAlt(localctx, 1) { - p.SetState(2334) + p.SetState(2338) p.Match(CqlParserK_LOGIN) if p.HasError() { // Recognition error - abort rule @@ -45914,10 +46296,10 @@ func (s *KwMaterializedContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwMaterialized() (localctx IKwMaterializedContext) { localctx = NewKwMaterializedContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 514, CqlParserRULE_kwMaterialized) + p.EnterRule(localctx, 522, CqlParserRULE_kwMaterialized) p.EnterOuterAlt(localctx, 1) { - p.SetState(2336) + p.SetState(2340) p.Match(CqlParserK_MATERIALIZED) if p.HasError() { // Recognition error - abort rule @@ -46010,10 +46392,10 @@ func (s *KwModifyContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwModify() (localctx IKwModifyContext) { localctx = NewKwModifyContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 516, CqlParserRULE_kwModify) + p.EnterRule(localctx, 524, CqlParserRULE_kwModify) p.EnterOuterAlt(localctx, 1) { - p.SetState(2338) + p.SetState(2342) p.Match(CqlParserK_MODIFY) if p.HasError() { // Recognition error - abort rule @@ -46106,10 +46488,10 @@ func (s *KwNosuperuserContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwNosuperuser() (localctx IKwNosuperuserContext) { localctx = NewKwNosuperuserContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 518, CqlParserRULE_kwNosuperuser) + p.EnterRule(localctx, 526, CqlParserRULE_kwNosuperuser) p.EnterOuterAlt(localctx, 1) { - p.SetState(2340) + p.SetState(2344) p.Match(CqlParserK_NOSUPERUSER) if p.HasError() { // Recognition error - abort rule @@ -46202,10 +46584,10 @@ func (s *KwNorecursiveContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwNorecursive() (localctx IKwNorecursiveContext) { localctx = NewKwNorecursiveContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 520, CqlParserRULE_kwNorecursive) + p.EnterRule(localctx, 528, CqlParserRULE_kwNorecursive) p.EnterOuterAlt(localctx, 1) { - p.SetState(2342) + p.SetState(2346) p.Match(CqlParserK_NORECURSIVE) if p.HasError() { // Recognition error - abort rule @@ -46298,10 +46680,10 @@ func (s *KwNotContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwNot() (localctx IKwNotContext) { localctx = NewKwNotContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 522, CqlParserRULE_kwNot) + p.EnterRule(localctx, 530, CqlParserRULE_kwNot) p.EnterOuterAlt(localctx, 1) { - p.SetState(2344) + p.SetState(2348) p.Match(CqlParserK_NOT) if p.HasError() { // Recognition error - abort rule @@ -46394,10 +46776,10 @@ func (s *KwNullContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwNull() (localctx IKwNullContext) { localctx = NewKwNullContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 524, CqlParserRULE_kwNull) + p.EnterRule(localctx, 532, CqlParserRULE_kwNull) p.EnterOuterAlt(localctx, 1) { - p.SetState(2346) + p.SetState(2350) p.Match(CqlParserK_NULL) if p.HasError() { // Recognition error - abort rule @@ -46490,10 +46872,10 @@ func (s *KwOfContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwOf() (localctx IKwOfContext) { localctx = NewKwOfContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 526, CqlParserRULE_kwOf) + p.EnterRule(localctx, 534, CqlParserRULE_kwOf) p.EnterOuterAlt(localctx, 1) { - p.SetState(2348) + p.SetState(2352) p.Match(CqlParserK_OF) if p.HasError() { // Recognition error - abort rule @@ -46586,10 +46968,10 @@ func (s *KwOnContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwOn() (localctx IKwOnContext) { localctx = NewKwOnContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 528, CqlParserRULE_kwOn) + p.EnterRule(localctx, 536, CqlParserRULE_kwOn) p.EnterOuterAlt(localctx, 1) { - p.SetState(2350) + p.SetState(2354) p.Match(CqlParserK_ON) if p.HasError() { // Recognition error - abort rule @@ -46682,10 +47064,10 @@ func (s *KwOptionsContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwOptions() (localctx IKwOptionsContext) { localctx = NewKwOptionsContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 530, CqlParserRULE_kwOptions) + p.EnterRule(localctx, 538, CqlParserRULE_kwOptions) p.EnterOuterAlt(localctx, 1) { - p.SetState(2352) + p.SetState(2356) p.Match(CqlParserK_OPTIONS) if p.HasError() { // Recognition error - abort rule @@ -46778,10 +47160,10 @@ func (s *KwOrContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwOr() (localctx IKwOrContext) { localctx = NewKwOrContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 532, CqlParserRULE_kwOr) + p.EnterRule(localctx, 540, CqlParserRULE_kwOr) p.EnterOuterAlt(localctx, 1) { - p.SetState(2354) + p.SetState(2358) p.Match(CqlParserK_OR) if p.HasError() { // Recognition error - abort rule @@ -46874,10 +47256,10 @@ func (s *KwOrderContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwOrder() (localctx IKwOrderContext) { localctx = NewKwOrderContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 534, CqlParserRULE_kwOrder) + p.EnterRule(localctx, 542, CqlParserRULE_kwOrder) p.EnterOuterAlt(localctx, 1) { - p.SetState(2356) + p.SetState(2360) p.Match(CqlParserK_ORDER) if p.HasError() { // Recognition error - abort rule @@ -46970,10 +47352,10 @@ func (s *KwPasswordContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwPassword() (localctx IKwPasswordContext) { localctx = NewKwPasswordContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 536, CqlParserRULE_kwPassword) + p.EnterRule(localctx, 544, CqlParserRULE_kwPassword) p.EnterOuterAlt(localctx, 1) { - p.SetState(2358) + p.SetState(2362) p.Match(CqlParserK_PASSWORD) if p.HasError() { // Recognition error - abort rule @@ -47066,10 +47448,10 @@ func (s *KwPrimaryContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwPrimary() (localctx IKwPrimaryContext) { localctx = NewKwPrimaryContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 538, CqlParserRULE_kwPrimary) + p.EnterRule(localctx, 546, CqlParserRULE_kwPrimary) p.EnterOuterAlt(localctx, 1) { - p.SetState(2360) + p.SetState(2364) p.Match(CqlParserK_PRIMARY) if p.HasError() { // Recognition error - abort rule @@ -47162,10 +47544,10 @@ func (s *KwRenameContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwRename() (localctx IKwRenameContext) { localctx = NewKwRenameContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 540, CqlParserRULE_kwRename) + p.EnterRule(localctx, 548, CqlParserRULE_kwRename) p.EnterOuterAlt(localctx, 1) { - p.SetState(2362) + p.SetState(2366) p.Match(CqlParserK_RENAME) if p.HasError() { // Recognition error - abort rule @@ -47258,10 +47640,10 @@ func (s *KwReplaceContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwReplace() (localctx IKwReplaceContext) { localctx = NewKwReplaceContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 542, CqlParserRULE_kwReplace) + p.EnterRule(localctx, 550, CqlParserRULE_kwReplace) p.EnterOuterAlt(localctx, 1) { - p.SetState(2364) + p.SetState(2368) p.Match(CqlParserK_REPLACE) if p.HasError() { // Recognition error - abort rule @@ -47354,10 +47736,10 @@ func (s *KwReplicationContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwReplication() (localctx IKwReplicationContext) { localctx = NewKwReplicationContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 544, CqlParserRULE_kwReplication) + p.EnterRule(localctx, 552, CqlParserRULE_kwReplication) p.EnterOuterAlt(localctx, 1) { - p.SetState(2366) + p.SetState(2370) p.Match(CqlParserK_REPLICATION) if p.HasError() { // Recognition error - abort rule @@ -47450,10 +47832,10 @@ func (s *KwReturnsContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwReturns() (localctx IKwReturnsContext) { localctx = NewKwReturnsContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 546, CqlParserRULE_kwReturns) + p.EnterRule(localctx, 554, CqlParserRULE_kwReturns) p.EnterOuterAlt(localctx, 1) { - p.SetState(2368) + p.SetState(2372) p.Match(CqlParserK_RETURNS) if p.HasError() { // Recognition error - abort rule @@ -47546,10 +47928,10 @@ func (s *KwRoleContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwRole() (localctx IKwRoleContext) { localctx = NewKwRoleContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 548, CqlParserRULE_kwRole) + p.EnterRule(localctx, 556, CqlParserRULE_kwRole) p.EnterOuterAlt(localctx, 1) { - p.SetState(2370) + p.SetState(2374) p.Match(CqlParserK_ROLE) if p.HasError() { // Recognition error - abort rule @@ -47642,10 +48024,10 @@ func (s *KwRolesContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwRoles() (localctx IKwRolesContext) { localctx = NewKwRolesContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 550, CqlParserRULE_kwRoles) + p.EnterRule(localctx, 558, CqlParserRULE_kwRoles) p.EnterOuterAlt(localctx, 1) { - p.SetState(2372) + p.SetState(2376) p.Match(CqlParserK_ROLES) if p.HasError() { // Recognition error - abort rule @@ -47738,10 +48120,10 @@ func (s *KwSelectContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwSelect() (localctx IKwSelectContext) { localctx = NewKwSelectContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 552, CqlParserRULE_kwSelect) + p.EnterRule(localctx, 560, CqlParserRULE_kwSelect) p.EnterOuterAlt(localctx, 1) { - p.SetState(2374) + p.SetState(2378) p.Match(CqlParserK_SELECT) if p.HasError() { // Recognition error - abort rule @@ -47834,10 +48216,10 @@ func (s *KwSetContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwSet() (localctx IKwSetContext) { localctx = NewKwSetContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 554, CqlParserRULE_kwSet) + p.EnterRule(localctx, 562, CqlParserRULE_kwSet) p.EnterOuterAlt(localctx, 1) { - p.SetState(2376) + p.SetState(2380) p.Match(CqlParserK_SET) if p.HasError() { // Recognition error - abort rule @@ -47930,10 +48312,10 @@ func (s *KwSfuncContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwSfunc() (localctx IKwSfuncContext) { localctx = NewKwSfuncContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 556, CqlParserRULE_kwSfunc) + p.EnterRule(localctx, 564, CqlParserRULE_kwSfunc) p.EnterOuterAlt(localctx, 1) { - p.SetState(2378) + p.SetState(2382) p.Match(CqlParserK_SFUNC) if p.HasError() { // Recognition error - abort rule @@ -48026,10 +48408,10 @@ func (s *KwStorageContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwStorage() (localctx IKwStorageContext) { localctx = NewKwStorageContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 558, CqlParserRULE_kwStorage) + p.EnterRule(localctx, 566, CqlParserRULE_kwStorage) p.EnterOuterAlt(localctx, 1) { - p.SetState(2380) + p.SetState(2384) p.Match(CqlParserK_STORAGE) if p.HasError() { // Recognition error - abort rule @@ -48122,10 +48504,10 @@ func (s *KwStypeContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwStype() (localctx IKwStypeContext) { localctx = NewKwStypeContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 560, CqlParserRULE_kwStype) + p.EnterRule(localctx, 568, CqlParserRULE_kwStype) p.EnterOuterAlt(localctx, 1) { - p.SetState(2382) + p.SetState(2386) p.Match(CqlParserK_STYPE) if p.HasError() { // Recognition error - abort rule @@ -48218,10 +48600,10 @@ func (s *KwSuperuserContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwSuperuser() (localctx IKwSuperuserContext) { localctx = NewKwSuperuserContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 562, CqlParserRULE_kwSuperuser) + p.EnterRule(localctx, 570, CqlParserRULE_kwSuperuser) p.EnterOuterAlt(localctx, 1) { - p.SetState(2384) + p.SetState(2388) p.Match(CqlParserK_SUPERUSER) if p.HasError() { // Recognition error - abort rule @@ -48314,10 +48696,10 @@ func (s *KwTableContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwTable() (localctx IKwTableContext) { localctx = NewKwTableContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 564, CqlParserRULE_kwTable) + p.EnterRule(localctx, 572, CqlParserRULE_kwTable) p.EnterOuterAlt(localctx, 1) { - p.SetState(2386) + p.SetState(2390) p.Match(CqlParserK_TABLE) if p.HasError() { // Recognition error - abort rule @@ -48410,10 +48792,10 @@ func (s *KwTablesContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwTables() (localctx IKwTablesContext) { localctx = NewKwTablesContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 566, CqlParserRULE_kwTables) + p.EnterRule(localctx, 574, CqlParserRULE_kwTables) p.EnterOuterAlt(localctx, 1) { - p.SetState(2388) + p.SetState(2392) p.Match(CqlParserK_TABLES) if p.HasError() { // Recognition error - abort rule @@ -48506,10 +48888,10 @@ func (s *KwTimestampContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwTimestamp() (localctx IKwTimestampContext) { localctx = NewKwTimestampContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 568, CqlParserRULE_kwTimestamp) + p.EnterRule(localctx, 576, CqlParserRULE_kwTimestamp) p.EnterOuterAlt(localctx, 1) { - p.SetState(2390) + p.SetState(2394) p.Match(CqlParserK_TIMESTAMP) if p.HasError() { // Recognition error - abort rule @@ -48602,10 +48984,10 @@ func (s *KwToContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwTo() (localctx IKwToContext) { localctx = NewKwToContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 570, CqlParserRULE_kwTo) + p.EnterRule(localctx, 578, CqlParserRULE_kwTo) p.EnterOuterAlt(localctx, 1) { - p.SetState(2392) + p.SetState(2396) p.Match(CqlParserK_TO) if p.HasError() { // Recognition error - abort rule @@ -48698,10 +49080,10 @@ func (s *KwTriggerContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwTrigger() (localctx IKwTriggerContext) { localctx = NewKwTriggerContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 572, CqlParserRULE_kwTrigger) + p.EnterRule(localctx, 580, CqlParserRULE_kwTrigger) p.EnterOuterAlt(localctx, 1) { - p.SetState(2394) + p.SetState(2398) p.Match(CqlParserK_TRIGGER) if p.HasError() { // Recognition error - abort rule @@ -48794,10 +49176,10 @@ func (s *KwTruncateContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwTruncate() (localctx IKwTruncateContext) { localctx = NewKwTruncateContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 574, CqlParserRULE_kwTruncate) + p.EnterRule(localctx, 582, CqlParserRULE_kwTruncate) p.EnterOuterAlt(localctx, 1) { - p.SetState(2396) + p.SetState(2400) p.Match(CqlParserK_TRUNCATE) if p.HasError() { // Recognition error - abort rule @@ -48890,10 +49272,10 @@ func (s *KwTtlContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwTtl() (localctx IKwTtlContext) { localctx = NewKwTtlContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 576, CqlParserRULE_kwTtl) + p.EnterRule(localctx, 584, CqlParserRULE_kwTtl) p.EnterOuterAlt(localctx, 1) { - p.SetState(2398) + p.SetState(2402) p.Match(CqlParserK_TTL) if p.HasError() { // Recognition error - abort rule @@ -48986,10 +49368,10 @@ func (s *KwTypeContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwType() (localctx IKwTypeContext) { localctx = NewKwTypeContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 578, CqlParserRULE_kwType) + p.EnterRule(localctx, 586, CqlParserRULE_kwType) p.EnterOuterAlt(localctx, 1) { - p.SetState(2400) + p.SetState(2404) p.Match(CqlParserK_TYPE) if p.HasError() { // Recognition error - abort rule @@ -49082,10 +49464,10 @@ func (s *KwUnloggedContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwUnlogged() (localctx IKwUnloggedContext) { localctx = NewKwUnloggedContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 580, CqlParserRULE_kwUnlogged) + p.EnterRule(localctx, 588, CqlParserRULE_kwUnlogged) p.EnterOuterAlt(localctx, 1) { - p.SetState(2402) + p.SetState(2406) p.Match(CqlParserK_UNLOGGED) if p.HasError() { // Recognition error - abort rule @@ -49178,10 +49560,10 @@ func (s *KwUpdateContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwUpdate() (localctx IKwUpdateContext) { localctx = NewKwUpdateContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 582, CqlParserRULE_kwUpdate) + p.EnterRule(localctx, 590, CqlParserRULE_kwUpdate) p.EnterOuterAlt(localctx, 1) { - p.SetState(2404) + p.SetState(2408) p.Match(CqlParserK_UPDATE) if p.HasError() { // Recognition error - abort rule @@ -49274,10 +49656,10 @@ func (s *KwUseContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwUse() (localctx IKwUseContext) { localctx = NewKwUseContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 584, CqlParserRULE_kwUse) + p.EnterRule(localctx, 592, CqlParserRULE_kwUse) p.EnterOuterAlt(localctx, 1) { - p.SetState(2406) + p.SetState(2410) p.Match(CqlParserK_USE) if p.HasError() { // Recognition error - abort rule @@ -49370,10 +49752,10 @@ func (s *KwUserContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwUser() (localctx IKwUserContext) { localctx = NewKwUserContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 586, CqlParserRULE_kwUser) + p.EnterRule(localctx, 594, CqlParserRULE_kwUser) p.EnterOuterAlt(localctx, 1) { - p.SetState(2408) + p.SetState(2412) p.Match(CqlParserK_USER) if p.HasError() { // Recognition error - abort rule @@ -49466,10 +49848,10 @@ func (s *KwUsingContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwUsing() (localctx IKwUsingContext) { localctx = NewKwUsingContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 588, CqlParserRULE_kwUsing) + p.EnterRule(localctx, 596, CqlParserRULE_kwUsing) p.EnterOuterAlt(localctx, 1) { - p.SetState(2410) + p.SetState(2414) p.Match(CqlParserK_USING) if p.HasError() { // Recognition error - abort rule @@ -49562,10 +49944,10 @@ func (s *KwValuesContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwValues() (localctx IKwValuesContext) { localctx = NewKwValuesContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 590, CqlParserRULE_kwValues) + p.EnterRule(localctx, 598, CqlParserRULE_kwValues) p.EnterOuterAlt(localctx, 1) { - p.SetState(2412) + p.SetState(2416) p.Match(CqlParserK_VALUES) if p.HasError() { // Recognition error - abort rule @@ -49658,10 +50040,10 @@ func (s *KwViewContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwView() (localctx IKwViewContext) { localctx = NewKwViewContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 592, CqlParserRULE_kwView) + p.EnterRule(localctx, 600, CqlParserRULE_kwView) p.EnterOuterAlt(localctx, 1) { - p.SetState(2414) + p.SetState(2418) p.Match(CqlParserK_VIEW) if p.HasError() { // Recognition error - abort rule @@ -49754,10 +50136,10 @@ func (s *KwWhereContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwWhere() (localctx IKwWhereContext) { localctx = NewKwWhereContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 594, CqlParserRULE_kwWhere) + p.EnterRule(localctx, 602, CqlParserRULE_kwWhere) p.EnterOuterAlt(localctx, 1) { - p.SetState(2416) + p.SetState(2420) p.Match(CqlParserK_WHERE) if p.HasError() { // Recognition error - abort rule @@ -49850,10 +50232,10 @@ func (s *KwWithContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwWith() (localctx IKwWithContext) { localctx = NewKwWithContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 596, CqlParserRULE_kwWith) + p.EnterRule(localctx, 604, CqlParserRULE_kwWith) p.EnterOuterAlt(localctx, 1) { - p.SetState(2418) + p.SetState(2422) p.Match(CqlParserK_WITH) if p.HasError() { // Recognition error - abort rule @@ -49946,10 +50328,10 @@ func (s *KwRevokeContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwRevoke() (localctx IKwRevokeContext) { localctx = NewKwRevokeContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 598, CqlParserRULE_kwRevoke) + p.EnterRule(localctx, 606, CqlParserRULE_kwRevoke) p.EnterOuterAlt(localctx, 1) { - p.SetState(2420) + p.SetState(2424) p.Match(CqlParserK_REVOKE) if p.HasError() { // Recognition error - abort rule @@ -50042,10 +50424,10 @@ func (s *KwGroupContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) KwGroup() (localctx IKwGroupContext) { localctx = NewKwGroupContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 600, CqlParserRULE_kwGroup) + p.EnterRule(localctx, 608, CqlParserRULE_kwGroup) p.EnterOuterAlt(localctx, 1) { - p.SetState(2422) + p.SetState(2426) p.Match(CqlParserK_GROUP) if p.HasError() { // Recognition error - abort rule @@ -50138,10 +50520,10 @@ func (s *SyntaxBracketLrContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) SyntaxBracketLr() (localctx ISyntaxBracketLrContext) { localctx = NewSyntaxBracketLrContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 602, CqlParserRULE_syntaxBracketLr) + p.EnterRule(localctx, 610, CqlParserRULE_syntaxBracketLr) p.EnterOuterAlt(localctx, 1) { - p.SetState(2424) + p.SetState(2428) p.Match(CqlParserLR_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -50234,10 +50616,10 @@ func (s *SyntaxBracketRrContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) SyntaxBracketRr() (localctx ISyntaxBracketRrContext) { localctx = NewSyntaxBracketRrContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 604, CqlParserRULE_syntaxBracketRr) + p.EnterRule(localctx, 612, CqlParserRULE_syntaxBracketRr) p.EnterOuterAlt(localctx, 1) { - p.SetState(2426) + p.SetState(2430) p.Match(CqlParserRR_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -50330,10 +50712,10 @@ func (s *SyntaxBracketLcContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) SyntaxBracketLc() (localctx ISyntaxBracketLcContext) { localctx = NewSyntaxBracketLcContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 606, CqlParserRULE_syntaxBracketLc) + p.EnterRule(localctx, 614, CqlParserRULE_syntaxBracketLc) p.EnterOuterAlt(localctx, 1) { - p.SetState(2428) + p.SetState(2432) p.Match(CqlParserLC_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -50426,10 +50808,10 @@ func (s *SyntaxBracketRcContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) SyntaxBracketRc() (localctx ISyntaxBracketRcContext) { localctx = NewSyntaxBracketRcContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 608, CqlParserRULE_syntaxBracketRc) + p.EnterRule(localctx, 616, CqlParserRULE_syntaxBracketRc) p.EnterOuterAlt(localctx, 1) { - p.SetState(2430) + p.SetState(2434) p.Match(CqlParserRC_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -50522,10 +50904,10 @@ func (s *SyntaxBracketLaContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) SyntaxBracketLa() (localctx ISyntaxBracketLaContext) { localctx = NewSyntaxBracketLaContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 610, CqlParserRULE_syntaxBracketLa) + p.EnterRule(localctx, 618, CqlParserRULE_syntaxBracketLa) p.EnterOuterAlt(localctx, 1) { - p.SetState(2432) + p.SetState(2436) p.Match(CqlParserOPERATOR_LT) if p.HasError() { // Recognition error - abort rule @@ -50618,10 +51000,10 @@ func (s *SyntaxBracketRaContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) SyntaxBracketRa() (localctx ISyntaxBracketRaContext) { localctx = NewSyntaxBracketRaContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 612, CqlParserRULE_syntaxBracketRa) + p.EnterRule(localctx, 620, CqlParserRULE_syntaxBracketRa) p.EnterOuterAlt(localctx, 1) { - p.SetState(2434) + p.SetState(2438) p.Match(CqlParserOPERATOR_GT) if p.HasError() { // Recognition error - abort rule @@ -50714,10 +51096,10 @@ func (s *SyntaxBracketLsContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) SyntaxBracketLs() (localctx ISyntaxBracketLsContext) { localctx = NewSyntaxBracketLsContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 614, CqlParserRULE_syntaxBracketLs) + p.EnterRule(localctx, 622, CqlParserRULE_syntaxBracketLs) p.EnterOuterAlt(localctx, 1) { - p.SetState(2436) + p.SetState(2440) p.Match(CqlParserLS_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -50810,10 +51192,10 @@ func (s *SyntaxBracketRsContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) SyntaxBracketRs() (localctx ISyntaxBracketRsContext) { localctx = NewSyntaxBracketRsContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 616, CqlParserRULE_syntaxBracketRs) + p.EnterRule(localctx, 624, CqlParserRULE_syntaxBracketRs) p.EnterOuterAlt(localctx, 1) { - p.SetState(2438) + p.SetState(2442) p.Match(CqlParserRS_BRACKET) if p.HasError() { // Recognition error - abort rule @@ -50906,10 +51288,10 @@ func (s *SyntaxCommaContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) SyntaxComma() (localctx ISyntaxCommaContext) { localctx = NewSyntaxCommaContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 618, CqlParserRULE_syntaxComma) + p.EnterRule(localctx, 626, CqlParserRULE_syntaxComma) p.EnterOuterAlt(localctx, 1) { - p.SetState(2440) + p.SetState(2444) p.Match(CqlParserCOMMA) if p.HasError() { // Recognition error - abort rule @@ -51002,10 +51384,10 @@ func (s *SyntaxColonContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) SyntaxColon() (localctx ISyntaxColonContext) { localctx = NewSyntaxColonContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 620, CqlParserRULE_syntaxColon) + p.EnterRule(localctx, 628, CqlParserRULE_syntaxColon) p.EnterOuterAlt(localctx, 1) { - p.SetState(2442) + p.SetState(2446) p.Match(CqlParserCOLON) if p.HasError() { // Recognition error - abort rule @@ -51213,23 +51595,23 @@ func (s *GroupSpecContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) GroupSpec() (localctx IGroupSpecContext) { localctx = NewGroupSpecContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 622, CqlParserRULE_groupSpec) + p.EnterRule(localctx, 630, CqlParserRULE_groupSpec) var _la int p.EnterOuterAlt(localctx, 1) { - p.SetState(2444) + p.SetState(2448) p.KwGroup() } { - p.SetState(2445) + p.SetState(2449) p.KwBy() } { - p.SetState(2446) + p.SetState(2450) p.GroupSpecElement() } - p.SetState(2452) + p.SetState(2456) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -51238,15 +51620,15 @@ func (p *CqlParser) GroupSpec() (localctx IGroupSpecContext) { for _la == CqlParserCOMMA { { - p.SetState(2447) + p.SetState(2451) p.SyntaxComma() } { - p.SetState(2448) + p.SetState(2452) p.GroupSpecElement() } - p.SetState(2454) + p.SetState(2458) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -51339,10 +51721,10 @@ func (s *GroupSpecElementContext) ExitRule(listener antlr.ParseTreeListener) { func (p *CqlParser) GroupSpecElement() (localctx IGroupSpecElementContext) { localctx = NewGroupSpecElementContext(p, p.GetParserRuleContext(), p.GetState()) - p.EnterRule(localctx, 624, CqlParserRULE_groupSpecElement) + p.EnterRule(localctx, 632, CqlParserRULE_groupSpecElement) p.EnterOuterAlt(localctx, 1) { - p.SetState(2455) + p.SetState(2459) p.Match(CqlParserOBJECT_NAME) if p.HasError() { // Recognition error - abort rule diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/cqlparser_base_listener.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/cqlparser_base_listener.go index a5c7b8f2..9c4c0616 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/cqlparser_base_listener.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/cqlparser_base_listener.go @@ -1030,6 +1030,22 @@ func (s *BaseCqlParserListener) EnterRelationFunctionCompareFunction(ctx *Relati func (s *BaseCqlParserListener) ExitRelationFunctionCompareFunction(ctx *RelationFunctionCompareFunctionContext) { } +// EnterRelationColumnCompareFunction is called when production relationColumnCompareFunction is entered. +func (s *BaseCqlParserListener) EnterRelationColumnCompareFunction(ctx *RelationColumnCompareFunctionContext) { +} + +// ExitRelationColumnCompareFunction is called when production relationColumnCompareFunction is exited. +func (s *BaseCqlParserListener) ExitRelationColumnCompareFunction(ctx *RelationColumnCompareFunctionContext) { +} + +// EnterRelationFunctionCompareColumn is called when production relationFunctionCompareColumn is entered. +func (s *BaseCqlParserListener) EnterRelationFunctionCompareColumn(ctx *RelationFunctionCompareColumnContext) { +} + +// ExitRelationFunctionCompareColumn is called when production relationFunctionCompareColumn is exited. +func (s *BaseCqlParserListener) ExitRelationFunctionCompareColumn(ctx *RelationFunctionCompareColumnContext) { +} + // EnterRelationBetween is called when production relationBetween is entered. func (s *BaseCqlParserListener) EnterRelationBetween(ctx *RelationBetweenContext) {} @@ -1084,12 +1100,24 @@ func (s *BaseCqlParserListener) EnterFunctionCall(ctx *FunctionCallContext) {} // ExitFunctionCall is called when production functionCall is exited. func (s *BaseCqlParserListener) ExitFunctionCall(ctx *FunctionCallContext) {} +// EnterFunctionName is called when production functionName is entered. +func (s *BaseCqlParserListener) EnterFunctionName(ctx *FunctionNameContext) {} + +// ExitFunctionName is called when production functionName is exited. +func (s *BaseCqlParserListener) ExitFunctionName(ctx *FunctionNameContext) {} + // EnterFunctionArgs is called when production functionArgs is entered. func (s *BaseCqlParserListener) EnterFunctionArgs(ctx *FunctionArgsContext) {} // ExitFunctionArgs is called when production functionArgs is exited. func (s *BaseCqlParserListener) ExitFunctionArgs(ctx *FunctionArgsContext) {} +// EnterFunctionArg is called when production functionArg is entered. +func (s *BaseCqlParserListener) EnterFunctionArg(ctx *FunctionArgContext) {} + +// ExitFunctionArg is called when production functionArg is exited. +func (s *BaseCqlParserListener) ExitFunctionArg(ctx *FunctionArgContext) {} + // EnterValueAny is called when production valueAny is entered. func (s *BaseCqlParserListener) EnterValueAny(ctx *ValueAnyContext) {} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/cqlparser_listener.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/cqlparser_listener.go index 92a9f262..49188653 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/cqlparser_listener.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser/cqlparser_listener.go @@ -505,6 +505,12 @@ type CqlParserListener interface { // EnterRelationFunctionCompareFunction is called when entering the relationFunctionCompareFunction production. EnterRelationFunctionCompareFunction(c *RelationFunctionCompareFunctionContext) + // EnterRelationColumnCompareFunction is called when entering the relationColumnCompareFunction production. + EnterRelationColumnCompareFunction(c *RelationColumnCompareFunctionContext) + + // EnterRelationFunctionCompareColumn is called when entering the relationFunctionCompareColumn production. + EnterRelationFunctionCompareColumn(c *RelationFunctionCompareColumnContext) + // EnterRelationBetween is called when entering the relationBetween production. EnterRelationBetween(c *RelationBetweenContext) @@ -532,9 +538,15 @@ type CqlParserListener interface { // EnterFunctionCall is called when entering the functionCall production. EnterFunctionCall(c *FunctionCallContext) + // EnterFunctionName is called when entering the functionName production. + EnterFunctionName(c *FunctionNameContext) + // EnterFunctionArgs is called when entering the functionArgs production. EnterFunctionArgs(c *FunctionArgsContext) + // EnterFunctionArg is called when entering the functionArg production. + EnterFunctionArg(c *FunctionArgContext) + // EnterValueAny is called when entering the valueAny production. EnterValueAny(c *ValueAnyContext) @@ -1444,6 +1456,12 @@ type CqlParserListener interface { // ExitRelationFunctionCompareFunction is called when exiting the relationFunctionCompareFunction production. ExitRelationFunctionCompareFunction(c *RelationFunctionCompareFunctionContext) + // ExitRelationColumnCompareFunction is called when exiting the relationColumnCompareFunction production. + ExitRelationColumnCompareFunction(c *RelationColumnCompareFunctionContext) + + // ExitRelationFunctionCompareColumn is called when exiting the relationFunctionCompareColumn production. + ExitRelationFunctionCompareColumn(c *RelationFunctionCompareColumnContext) + // ExitRelationBetween is called when exiting the relationBetween production. ExitRelationBetween(c *RelationBetweenContext) @@ -1471,9 +1489,15 @@ type CqlParserListener interface { // ExitFunctionCall is called when exiting the functionCall production. ExitFunctionCall(c *FunctionCallContext) + // ExitFunctionName is called when exiting the functionName production. + ExitFunctionName(c *FunctionNameContext) + // ExitFunctionArgs is called when exiting the functionArgs production. ExitFunctionArgs(c *FunctionArgsContext) + // ExitFunctionArg is called when exiting the functionArg production. + ExitFunctionArg(c *FunctionArgContext) + // ExitValueAny is called when exiting the valueAny production. ExitValueAny(c *ValueAnyContext) diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/datastax/proxycore/codecs.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/datastax/proxycore/codecs.go index daf846c0..ec279b95 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/datastax/proxycore/codecs.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/datastax/proxycore/codecs.go @@ -47,6 +47,9 @@ var primitiveCodecs = map[datatype.DataType]datacodec.Codec{ } func EncodeType(dt datatype.DataType, version primitive.ProtocolVersion, val interface{}) ([]byte, error) { + if val == nil { + return nil, nil + } c, err := codecFromDataType(dt) if err != nil { return nil, err diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/binding.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/binding.go index 040f3a8f..82bbad69 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/binding.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/binding.go @@ -5,8 +5,8 @@ import ( "fmt" "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types" schemaMapping "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/metadata" - "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/utilities" "github.com/datastax/go-cassandra-native-protocol/primitive" + "github.com/google/uuid" "strconv" "time" ) @@ -19,7 +19,7 @@ func BindMutations(assignments []types.Assignment, usingTimestamp types.DynamicV } switch v := assignment.(type) { case *types.AssignmentCounterIncrement: - value, err := utilities.GetValueInt64(v.Value(), values) + value, err := values.GetValueInt64(v.Value()) if err != nil { return err } @@ -42,7 +42,7 @@ func BindMutations(assignments []types.Assignment, usingTimestamp types.DynamicV if colType == types.LIST { lt := v.Column().CQLType.(*types.ListType) if v.Operator == types.PLUS { - value, err := utilities.GetValueSlice(v.Value(), values) + value, err := values.GetValueSlice(v.Value()) if err != nil { return err } @@ -52,7 +52,7 @@ func BindMutations(assignments []types.Assignment, usingTimestamp types.DynamicV } b.AddMutations(mutations...) } else if v.Operator == types.MINUS { - value, err := utilities.GetValueSlice(v.Value(), values) + value, err := values.GetValueSlice(v.Value()) if err != nil { return err } @@ -70,7 +70,7 @@ func BindMutations(assignments []types.Assignment, usingTimestamp types.DynamicV } } else if colType == types.SET { if v.Operator == types.PLUS { - value, err := utilities.GetValueSlice(v.Value(), values) + value, err := values.GetValueSlice(v.Value()) if err != nil { return err } @@ -80,7 +80,7 @@ func BindMutations(assignments []types.Assignment, usingTimestamp types.DynamicV } b.AddMutations(ops...) } else if v.Operator == types.MINUS { - value, err := utilities.GetValueSlice(v.Value(), values) + value, err := values.GetValueSlice(v.Value()) if err != nil { return err } @@ -94,7 +94,7 @@ func BindMutations(assignments []types.Assignment, usingTimestamp types.DynamicV } else if colType == types.MAP { mt := v.Column().CQLType.(*types.MapType) if v.Operator == types.PLUS { - value, err := utilities.GetValueMap(v.Value(), values) + value, err := values.GetValueMap(v.Value()) if err != nil { return err } @@ -103,7 +103,7 @@ func BindMutations(assignments []types.Assignment, usingTimestamp types.DynamicV return err } } else if v.Operator == types.MINUS { - value, err := utilities.GetValueSlice(v.Value(), values) + value, err := values.GetValueSlice(v.Value()) if err != nil { return err } @@ -189,7 +189,7 @@ func encodeSetValue(assignment *types.ComplexAssignmentSet, values *types.QueryP if col.CQLType.Code() == types.MAP { mt := col.CQLType.(*types.MapType) - mv, err := utilities.GetValueMap(assignment.Value(), values) + mv, err := values.GetValueMap(assignment.Value()) if err != nil { return nil, err } @@ -206,7 +206,7 @@ func encodeSetValue(assignment *types.ComplexAssignmentSet, values *types.QueryP } } else if col.CQLType.Code() == types.LIST { lt := col.CQLType.(*types.ListType) - lv, err := utilities.GetValueSlice(assignment.Value(), values) + lv, err := values.GetValueSlice(assignment.Value()) if err != nil { return nil, err } @@ -216,7 +216,7 @@ func encodeSetValue(assignment *types.ComplexAssignmentSet, values *types.QueryP } results = append(results, mutations...) } else if col.CQLType.Code() == types.SET { - lv, err := utilities.GetValueSlice(assignment.Value(), values) + lv, err := values.GetValueSlice(assignment.Value()) if err != nil { return nil, err } @@ -338,6 +338,12 @@ func scalarToColumnQualifier(val types.GoValue) (types.ColumnQualifier, error) { return types.ColumnQualifier(strconv.FormatInt(v.UnixMilli(), 10)), nil case time.Time: return types.ColumnQualifier(strconv.FormatInt(v.UnixMilli(), 10)), nil + case uuid.UUID: + return types.ColumnQualifier(v.String()), nil + case [16]byte: + return types.ColumnQualifier(uuid.UUID(v).String()), nil + case primitive.UUID: + return types.ColumnQualifier(uuid.UUID(v).String()), nil default: return "", fmt.Errorf("unsupported type: %T", v) } @@ -413,11 +419,11 @@ func BindQueryParams(params *types.QueryParameters, positionalValues []*primitiv } func bindPositionalParams(params *types.QueryParameters, values []*primitive.Value, pv primitive.ProtocolVersion) (*types.QueryParameterValues, error) { - if params.Count() != len(values) { - return nil, fmt.Errorf("expected %d prepared positional values but got %d", params.Count(), len(values)) + if params.CountUserParameters() != len(values) { + return nil, fmt.Errorf("expected %d prepared positional values but got %d", params.CountUserParameters(), len(values)) } result := types.NewQueryParameterValues(params, time.Now()) - for i, param := range params.Ordered() { + for i, param := range params.OrderedUserParams() { goVal, err := cassandraValueToGoValue(param.Type, values[i], pv) if err != nil { return nil, err @@ -431,8 +437,8 @@ func bindPositionalParams(params *types.QueryParameters, values []*primitive.Val } func bindNamedParams(params *types.QueryParameters, values map[string]*primitive.Value, pv primitive.ProtocolVersion) (*types.QueryParameterValues, error) { - if params.Count() != len(values) { - return nil, fmt.Errorf("expected %d prepared named values but got %d", params.Count(), len(values)) + if params.CountUserParameters() != len(values) { + return nil, fmt.Errorf("expected %d prepared named values but got %d", params.CountUserParameters(), len(values)) } result := types.NewQueryParameterValues(params, time.Now()) for param, value := range values { @@ -459,16 +465,12 @@ func BindSelectColumns(table *schemaMapping.TableSchema, selectedColumns []types var boundColumns []types.BoundSelectColumn for _, selectedColumn := range selectedColumns { var bc types.BoundSelectColumn - col, err := table.GetColumn(selectedColumn.ColumnName) - if err != nil { - return nil, err - } - if selectedColumn.ListIndex != -1 { - bc = types.NewBoundIndexColumn(col, int(selectedColumn.ListIndex)) - } else if selectedColumn.MapKey != "" { - bc = types.NewBoundKeyColumn(col, selectedColumn.MapKey) + if li, ok := selectedColumn.Value.(*types.ListElementValue); ok { + bc = types.NewBoundIndexColumn(li.Column, int(li.ListIndex)) + } else if mk, ok := selectedColumn.Value.(*types.MapAccessValue); ok { + bc = types.NewBoundKeyColumn(mk.Column, mk.MapKey) } else { - return nil, fmt.Errorf("unhandled select column type found binding") + return nil, fmt.Errorf("unhandled select column type found binding: %T", selectedColumn) } boundColumns = append(boundColumns, bc) } @@ -484,7 +486,7 @@ func BindUsingTimestamp(value types.DynamicValue, values *types.QueryParameterVa }, nil } - t, err := utilities.GetValueInt64(value, values) + t, err := values.GetValueInt64(value) if err != nil { return nil, err } diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/btql_functions.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/btql_functions.go deleted file mode 100644 index 1ae1dbc7..00000000 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/btql_functions.go +++ /dev/null @@ -1,36 +0,0 @@ -package common - -import ( - "fmt" - "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types" - cql "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/third_party/cqlparser" - "strings" -) - -func ParseCqlFunc(f cql.IFunctionCallContext) (types.CqlFuncCode, error) { - if f.K_UUID() != nil { - return types.FuncCodeUnknown, fmt.Errorf("unknown function: 'UUID'") - } - // writetime is a reserved word, so we have to handle that case separately - if f.K_WRITETIME() != nil { - return types.FuncCodeWriteTime, nil - } - - functionName := strings.ToLower(f.OBJECT_NAME().GetText()) - switch functionName { - case "writetime": - return types.FuncCodeWriteTime, nil - case "count": - return types.FuncCodeCount, nil - case "avg": - return types.FuncCodeAvg, nil - case "sum": - return types.FuncCodeSum, nil - case "min": - return types.FuncCodeMin, nil - case "max": - return types.FuncCodeMax, nil - default: - return types.FuncCodeUnknown, fmt.Errorf("unknown function: '%s'", functionName) - } -} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/rowkeys.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/rowkeys.go index 4b90a789..e7f9d1ca 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/rowkeys.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/rowkeys.go @@ -7,6 +7,7 @@ import ( "fmt" "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types" schemaMapping "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/metadata" + "github.com/datastax/go-cassandra-native-protocol/primitive" "time" ) @@ -73,6 +74,13 @@ func BindRowKey(tableConfig *schemaMapping.TableSchema, rowKeyValues []types.Dyn } // the ordered code library always appends a delimiter to strings, but we have custom delimiter logic so remove it orderEncodedField = orderEncodedField[:len(orderEncodedField)-2] + case primitive.UUID: + orderEncodedField, err = Append(nil, string(v[:])) + if err != nil { + return "", err + } + // the ordered code library always appends a delimiter to strings, but we have custom delimiter logic so remove it + orderEncodedField = orderEncodedField[:len(orderEncodedField)-2] default: return "", fmt.Errorf("unsupported row key type %T", value) } diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/rowkeys_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/rowkeys_test.go index 2998efde..c3a1e6d8 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/rowkeys_test.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/rowkeys_test.go @@ -15,10 +15,10 @@ func TestBindRowKeyTimestampPrecision(t *testing.T) { millis := time.UnixMilli(1767727307246) table := mockdata.GetTableOrDie("test_keyspace", "timestamp_key") - rowKeyMicro, err := BindRowKey(table, []types.DynamicValue{types.NewLiteralValue(micro)}, types.NewQueryParameterValues(types.NewEmptyQueryParameters(), time.Now())) + rowKeyMicro, err := BindRowKey(table, []types.DynamicValue{types.NewLiteralValue(micro, types.TypeTimestamp)}, types.NewQueryParameterValues(types.NewEmptyQueryParameters(), time.Now())) require.NoError(t, err) - rowKeyMillis, err := BindRowKey(table, []types.DynamicValue{types.NewLiteralValue(millis)}, types.NewQueryParameterValues(types.NewEmptyQueryParameters(), time.Now())) + rowKeyMillis, err := BindRowKey(table, []types.DynamicValue{types.NewLiteralValue(millis, types.TypeTimestamp)}, types.NewQueryParameterValues(types.NewEmptyQueryParameters(), time.Now())) require.NoError(t, err) // ensure microseconds are truncated because Bigtable uses microseconds for keys but Cassandra uses milliseconds @@ -72,8 +72,13 @@ func TestBindRowKey(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var values []types.DynamicValue - for _, v := range tt.values { - values = append(values, types.NewLiteralValue(v)) + for i, v := range tt.values { + if i < len(tt.table.PrimaryKeys) { + values = append(values, types.NewLiteralValue(v, tt.table.PrimaryKeys[i].CQLType)) + } else { + // Fallback for cases where we might have more values than primary keys (to test error handling) + values = append(values, types.NewLiteralValue(v, types.TypeVarchar)) + } } rowKey, err := BindRowKey(tt.table, values, types.NewQueryParameterValues(types.NewEmptyQueryParameters(), time.Now())) if tt.err != "" { diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/utils.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/utils.go index ffeae56f..e6a85cb6 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/utils.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/utils.go @@ -10,7 +10,9 @@ import ( "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/utilities" "github.com/datastax/go-cassandra-native-protocol/datatype" "github.com/datastax/go-cassandra-native-protocol/primitive" + "github.com/google/uuid" "regexp" + "slices" "strings" "time" ) @@ -39,7 +41,7 @@ func ExtractDecimalLiteral(d cql.IDecimalLiteralContext, cqlType types.CqlDataTy if err != nil { return nil, err } - return types.NewLiteralValue(val), err + return types.NewLiteralValue(val, cqlType), err } func ParseMarker(m cql.IMarkerContext, dt types.CqlDataType, params *types.QueryParameterBuilder, col *types.Column) (types.DynamicValue, error) { @@ -55,7 +57,7 @@ func ParseMarker(m cql.IMarkerContext, dt types.CqlDataType, params *types.Query if err != nil { return nil, err } - return types.NewParameterizedValue(marker), nil + return types.NewParameterizedValue(marker, dt), nil } func GetDecimalLiteral(d cql.IDecimalLiteralContext, cqlType types.CqlDataType) (types.GoValue, error) { @@ -109,6 +111,12 @@ func ParseWhereClause(input cql.IWhereSpecContext, tableConfig *schemaMapping.Ta condition, err = parseWhereLike(val.RelationLike(), tableConfig, params) } else if val.RelationContainsKey() != nil { condition, err = parseWhereContainsKey(val.RelationContainsKey(), tableConfig, params) + } else if val.RelationFunctionCompareColumn() != nil { + compareFn := val.RelationFunctionCompareColumn() + condition, err = parseColumnCompareFunction(compareFn.Column(), compareFn.CompareOperator(), compareFn.FunctionCall(), true, tableConfig, params) + } else if val.RelationColumnCompareFunction() != nil { + compareFn := val.RelationColumnCompareFunction() + condition, err = parseColumnCompareFunction(compareFn.Column(), compareFn.CompareOperator(), compareFn.FunctionCall(), false, tableConfig, params) } else if val.RelationContains() != nil { condition, err = parseWhereContains(val.RelationContains(), tableConfig, params) } else if val.RelationBetween() != nil { @@ -148,6 +156,30 @@ func parseWhereCompare(compare cql.IRelationCompareContext, tableConfig *schemaM Value: value, }, nil } + +func parseColumnCompareFunction(col cql.IColumnContext, op cql.ICompareOperatorContext, f cql.IFunctionCallContext, flip bool, tableConfig *schemaMapping.TableSchema, params *types.QueryParameterBuilder) (types.Condition, error) { + column, err := ParseColumnContext(tableConfig, col) + if err != nil { + return types.Condition{}, err + } + operator, err := ParseOperator(op) + if err != nil { + return types.Condition{}, err + } + if flip { + operator = types.FlipOperator(operator) + } + fn, err := ParseFunctionCall(f, tableConfig, types.QueryClauseWhere, params) + if err != nil { + return types.Condition{}, err + } + return types.Condition{ + Column: column, + Operator: operator, + Value: fn, + }, nil +} + func parseWhereLike(like cql.IRelationLikeContext, tableConfig *schemaMapping.TableSchema, params *types.QueryParameterBuilder) (types.Condition, error) { column, err := ParseColumnContext(tableConfig, like.Column()) if err != nil { @@ -214,15 +246,15 @@ func parseWhereBetween(between cql.IRelationBetweenContext, tableConfig *schemaM return types.Condition{}, err } - if len(between.AllConstant()) != 2 { + if len(between.AllValueAny()) != 2 { return types.Condition{}, fmt.Errorf("BETWEEN condition must have exactly 2 values") } - v1, err := ParseConstantValue(between.Constant(0), column.CQLType, params, column) + v1, err := ParseValueAny(between.ValueAny(0), tableConfig, column.CQLType, types.QueryClauseWhere, params, column) if err != nil { return types.Condition{}, err } - v2, err := ParseConstantValue(between.Constant(1), column.CQLType, params, column) + v2, err := ParseValueAny(between.ValueAny(1), tableConfig, column.CQLType, types.QueryClauseWhere, params, column) if err != nil { return types.Condition{}, err } @@ -256,7 +288,7 @@ func ParseTupleValue(tuple cql.ITupleValueContext, lt *types.ListType, params *t } valueFn := tuple.FunctionArgs() - all := valueFn.AllConstant() + all := valueFn.AllFunctionArg() if all == nil || len(all) == 0 { return nil, errors.New("failed to parse values for IN operator") } @@ -268,10 +300,10 @@ func ParseTupleValue(tuple cql.ITupleValueContext, lt *types.ListType, params *t } inValues = append(inValues, parsed) } - return types.NewLiteralValue(inValues), nil + return types.NewLiteralValue(inValues, lt), nil } -func ParseValueAny(v cql.IValueAnyContext, dt types.CqlDataType, params *types.QueryParameterBuilder, column *types.Column) (types.DynamicValue, error) { +func ParseValueAny(v cql.IValueAnyContext, table *schemaMapping.TableSchema, dt types.CqlDataType, clause types.QueryClause, params *types.QueryParameterBuilder, column *types.Column) (types.DynamicValue, error) { if v.Marker() != nil { return ParseMarker(v.Marker(), dt, params, column) } @@ -284,39 +316,129 @@ func ParseValueAny(v cql.IValueAnyContext, dt types.CqlDataType, params *types.Q if err != nil { return nil, err } - return types.NewLiteralValue(value), nil + return types.NewLiteralValue(value, dt), nil } if v.ValueMap() != nil { value, err := ParseCqlMapAssignment(v.ValueMap(), dt) if err != nil { return nil, err } - return types.NewLiteralValue(value), nil + return types.NewLiteralValue(value, dt), nil } if v.ValueSet() != nil { value, err := ParseCqlSetAssignment(v.ValueSet(), dt) if err != nil { return nil, err } - return types.NewLiteralValue(value), nil + return types.NewLiteralValue(value, dt), nil } // todo more robust function handling if v.FunctionCall() != nil { - functionName := strings.ToLower(v.FunctionCall().OBJECT_NAME().GetText()) - if functionName == "totimestamp" { - fnArgs := v.FunctionCall().FunctionArgs().AllFunctionCall() - if len(fnArgs) == 1 { - innerFn := strings.ToLower(fnArgs[0].OBJECT_NAME().GetText()) - if innerFn == "now" { - return types.NewTimestampNowValue(), nil - } - } - } - return nil, fmt.Errorf("unsupported function call: `%s`", v.GetText()) + return ParseFunctionCall(v.FunctionCall(), table, clause, params) } return nil, fmt.Errorf("unhandled value set `%s`", v.GetText()) } +func ParseFunctionCall(functionCall cql.IFunctionCallContext, table *schemaMapping.TableSchema, clause types.QueryClause, params *types.QueryParameterBuilder) (*types.FunctionValue, error) { + funcSpec, err := ParseFunctionName(functionCall.FunctionName()) + if err != nil { + return nil, err + } + if !slices.Contains(funcSpec.GetValidClauses(), clause) { + return nil, fmt.Errorf("function '%s' cannot be called in %s clause", funcSpec.GetName(), clause.String()) + } + + var allFunctionArgs []cql.IFunctionArgContext + if functionCall.FunctionArgs() == nil { + allFunctionArgs = nil + } else { + allFunctionArgs = functionCall.FunctionArgs().AllFunctionArg() + } + + if len(allFunctionArgs) != len(funcSpec.GetParameterTypes()) { + return nil, fmt.Errorf("expected %d args for function %s but got %d", len(funcSpec.GetParameterTypes()), funcSpec.GetName(), len(allFunctionArgs)) + } + var args []types.DynamicValue + for i, arg := range allFunctionArgs { + argSpec := funcSpec.GetParameterTypes()[i] + value, err := parseFunctionArg(table, arg, argSpec, clause, params) + if err != nil { + return nil, err + } + args = append(args, value) + } + var p types.Parameter + if clause == types.QueryClauseSelect { + // we can't use functions here so don't assign a parameter + p = "" + } else { + p, err = params.AddInternalParam(funcSpec.GetReturnType(args)) + if err != nil { + return nil, err + } + } + fv := types.NewFunctionValue(p, funcSpec, args...) + err = types.ValidateFunctionArgs(fv) + if err != nil { + return nil, err + } + return fv, nil +} + +func ParseFunctionName(f cql.IFunctionNameContext) (types.CqlFunc, error) { + functionName := strings.ToLower(f.GetText()) + switch functionName { + case "writetime": + return types.WriteTime, nil + case "count": + return types.Count, nil + case "avg": + return types.Avg, nil + case "sum": + return types.Sum, nil + case "min": + return types.Min, nil + case "max": + return types.Max, nil + case "now": + return types.Now, nil + case "totimestamp": + return types.ToTimestamp, nil + case "mintimeuuid": + return types.MinTimeuuid, nil + case "maxtimeuuid": + return types.MaxTimeuuid, nil + default: + return nil, fmt.Errorf("unknown function: '%s'", functionName) + } +} + +func parseFunctionArg(table *schemaMapping.TableSchema, arg cql.IFunctionArgContext, argSpec types.CqlFuncParameter, clause types.QueryClause, params *types.QueryParameterBuilder) (types.DynamicValue, error) { + if arg.ValueAny() != nil { + value, err := ParseValueAny(arg.ValueAny(), table, argSpec.Types[0], clause, params, nil) + if err != nil { + return nil, err + } + return value, nil + } else if arg.Column() != nil { + if clause != types.QueryClauseSelect { + return nil, fmt.Errorf("function calls on columns are not supported outside of the SELECT clause") + } + col, err := ParseColumnContext(table, arg.Column()) + if err != nil { + return nil, err + } + return types.NewColumnValue(col), nil + } else if arg.STAR() != nil { + if clause != types.QueryClauseSelect { + return nil, fmt.Errorf("function calls on '*' are not supported outside of the SELECT clause") + } + return types.NewSelectStarValue(), nil + } else { + return nil, fmt.Errorf("unsupported function argument: `%s`", arg.GetText()) + } +} + func ParseConstantValue(v cql.IConstantContext, dt types.CqlDataType, params *types.QueryParameterBuilder, col *types.Column) (types.DynamicValue, error) { if v.Marker() != nil { return ParseMarker(v.Marker(), dt, params, col) @@ -326,7 +448,7 @@ func ParseConstantValue(v cql.IConstantContext, dt types.CqlDataType, params *ty return nil, err } - return types.NewLiteralValue(goValue), nil + return types.NewLiteralValue(goValue, dt), nil } func ParseColumnContext(table *schemaMapping.TableSchema, r cql.IColumnContext) (*types.Column, error) { @@ -514,6 +636,10 @@ func ParseCqlConstant(c cql.IConstantContext, dt types.CqlDataType) (types.GoVal if c.HexadecimalLiteral() != nil { return utilities.StringToGo(c.HexadecimalLiteral().GetText(), dt) } + case types.UUID, types.TIMEUUID: + if c.UUID() != nil { + return utilities.StringToGo(c.UUID().GetText(), dt) + } } return nil, fmt.Errorf("invalid literal for type %s: '%s'", dt.String(), c.GetText()) @@ -552,11 +678,36 @@ func EncodeScalarForBigtable(value types.GoValue, cqlType types.CqlDataType) (ty return encodeBlobForBigtable(value) case datatype.Varchar, datatype.Ascii: return encodeStringForBigtable(value) + case datatype.Uuid, datatype.Timeuuid: + return encodeUuidForBigtable(value, cqlType.DataType()) default: return nil, fmt.Errorf("unsupported CQL type: %s", cqlType.String()) } } +func encodeUuidForBigtable(value interface{}, dt datatype.DataType) (types.BigtableValue, error) { + var valToEncode interface{} = value + switch v := value.(type) { + case uuid.UUID: + valToEncode = primitive.UUID(v) + case *uuid.UUID: + if v != nil { + valToEncode = primitive.UUID(*v) + } + case []byte: + if len(v) == 16 { + var u primitive.UUID + copy(u[:], v) + valToEncode = u + } + } + result, err := proxycore.EncodeType(dt, bigtableEncodingVersion, valToEncode) + if err != nil { + return nil, fmt.Errorf("failed to encode uuid/timeuuid: %w", err) + } + return result, err +} + func encodeBlobForBigtable(value types.GoValue) (types.BigtableValue, error) { bd, err := proxycore.EncodeType(datatype.Blob, bigtableEncodingVersion, value) if err != nil { @@ -630,6 +781,12 @@ func dereferenceSlice(goValue types.GoValue) types.GoValue { s[i] = *ps } return s + case []*primitive.UUID: + var s = make([]primitive.UUID, len(v)) + for i, ps := range v { + s[i] = *ps + } + return s } return goValue } @@ -820,14 +977,14 @@ func ParseSelectIndex(si cql.ISelectIndexContext, alias string, table *schemaMap if err != nil { return types.SelectedColumn{}, err } - return *types.NewSelectedColumnMapElement(si.GetText(), col.Name, alias, mt.ValueType(), colQualifier), nil + return types.NewSelectedColumn(si.GetText(), types.NewMapAccessValue(col, mt, colQualifier), alias), nil } else if col.CQLType.Code() == types.LIST { index, err := ParseBigInt(si.Constant().DecimalLiteral()) if err != nil { return types.SelectedColumn{}, err } lt := col.CQLType.(*types.ListType) - return *types.NewSelectedColumnListElement(si.GetText(), col.Name, alias, lt.ElementType(), index), nil + return types.NewSelectedColumn(si.GetText(), types.NewListElementValue(col, lt, index), alias), nil } else { return types.SelectedColumn{}, fmt.Errorf("cannot access index/key of column type %s", col.CQLType.String()) } @@ -838,80 +995,19 @@ func ParseSelectColumn(si cql.ISelectColumnContext, alias string, table *schemaM if err != nil { return types.SelectedColumn{}, err } - return *types.NewSelectedColumn(string(col.Name), col.Name, alias, col.CQLType), nil + return types.NewSelectedColumn(string(col.Name), types.NewColumnValue(col), alias), nil } -func ParseSelectFunction(sf cql.ISelectFunctionContext, alias string, table *schemaMapping.TableSchema) (types.SelectedColumn, error) { - f, err := ParseCqlFunc(sf.FunctionCall()) +func ParseSelectFunction(sf cql.ISelectFunctionContext, alias string, table *schemaMapping.TableSchema, params *types.QueryParameterBuilder) (types.SelectedColumn, error) { + f, err := ParseFunctionCall(sf.FunctionCall(), table, types.QueryClauseSelect, params) if err != nil { return types.SelectedColumn{}, err } - switch f { - case types.FuncCodeWriteTime: - col, err := parseSingleColumnFunctionArg(sf.FunctionCall(), table) - if err != nil { - return types.SelectedColumn{}, err - } - return *types.NewSelectedColumnFunction(sf.FunctionCall().GetText(), col.Name, alias, types.TypeBigInt, f), nil - case types.FuncCodeCount: - value, err := parseStarOrColumnFunctionArg(sf.FunctionCall(), table) - if err != nil { - return types.SelectedColumn{}, err - } - sql := fmt.Sprintf("system.count(%s)", value) - return *types.NewSelectedColumnFunction(sql, types.ColumnName(value), alias, types.TypeBigInt, f), nil - case types.FuncCodeAvg, types.FuncCodeSum, types.FuncCodeMin, types.FuncCodeMax: - col, err := parseSingleColumnFunctionArg(sf.FunctionCall(), table) - if err != nil { - return types.SelectedColumn{}, err - } - - if !isNumericType(col.CQLType) { - return types.SelectedColumn{}, fmt.Errorf("invalid aggregate type: %s", col.CQLType.String()) - } - - resultType := col.CQLType - // integer type columns need to have result a result type that captures decimal positionalValues - if f == types.FuncCodeAvg && (col.CQLType.Code() == types.BIGINT || col.CQLType.Code() == types.INT || col.CQLType.Code() == types.COUNTER) { - resultType = types.TypeDouble - } - - // example: system.avg(price) - sql := fmt.Sprintf("system.%s(%s)", strings.ToLower(f.String()), col.Name) - return *types.NewSelectedColumnFunction(sql, col.Name, alias, resultType, f), nil - default: - return types.SelectedColumn{}, fmt.Errorf("unhandled function type `%s`", sf.FunctionCall().GetText()) - } -} - -func isNumericType(t types.CqlDataType) bool { - return t.Code() == types.BIGINT || t.Code() == types.INT || t.Code() == types.FLOAT || t.Code() == types.DOUBLE || t.Code() == types.COUNTER -} - -func parseSingleColumnFunctionArg(fn cql.IFunctionCallContext, table *schemaMapping.TableSchema) (*types.Column, error) { - if fn.FunctionArgs() == nil || len(fn.FunctionArgs().AllOBJECT_NAME()) != 1 { - return nil, fmt.Errorf("expected 1 column argument for `%s`", fn.GetText()) - } - if len(fn.FunctionArgs().AllFunctionCall()) != 0 { - return nil, fmt.Errorf("expected 1 column argument for `%s`", fn.GetText()) - } - arg := fn.FunctionArgs().OBJECT_NAME(0).GetText() - col, err := table.GetColumn(types.ColumnName(arg)) - if err != nil { - return nil, fmt.Errorf("expected valid column in function arguments `%s`", fn.GetText()) - } - return col, nil -} - -func parseStarOrColumnFunctionArg(fn cql.IFunctionCallContext, table *schemaMapping.TableSchema) (string, error) { - if fn.STAR() != nil { - return "*", nil - } - col, err := parseSingleColumnFunctionArg(fn, table) - if err != nil { - return "", err + cqlText := sf.GetText() + if f.Func.GetCode() == types.FuncCodeCount || f.Func.GetCode() == types.FuncCodeAvg || f.Func.GetCode() == types.FuncCodeMin || f.Func.GetCode() == types.FuncCodeMax || f.Func.GetCode() == types.FuncCodeSum { + cqlText = "system." + strings.ToLower(cqlText) } - return string(col.Name), nil + return types.NewSelectedColumn(cqlText, f, alias), nil } func ParseAs(a cql.IAsSpecContext) (string, error) { diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/utils_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/utils_test.go index fe8ac00f..411c39b2 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/utils_test.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common/utils_test.go @@ -102,8 +102,8 @@ func Test_validateRequiredPrimaryKeys(t *testing.T) { name: "success", table: mockdata.GetTableOrDie("test_keyspace", "test_table"), assignments: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("value1")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("value2")), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("value1", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("value2", types.TypeVarchar)), }, err: "", }, @@ -111,7 +111,7 @@ func Test_validateRequiredPrimaryKeys(t *testing.T) { name: "missing pk2", table: mockdata.GetTableOrDie("test_keyspace", "test_table"), assignments: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("value1")), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("value1", types.TypeVarchar)), }, err: "missing primary key: 'pk2'", }, @@ -119,9 +119,9 @@ func Test_validateRequiredPrimaryKeys(t *testing.T) { name: "extra columns ok", table: mockdata.GetTableOrDie("test_keyspace", "test_table"), assignments: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("value1")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("value2")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewParameterizedValue("value3")), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("value1", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("value2", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewParameterizedValue("value3", types.TypeBlob)), }, err: "", }, @@ -129,9 +129,9 @@ func Test_validateRequiredPrimaryKeys(t *testing.T) { name: "out of order ok", table: mockdata.GetTableOrDie("test_keyspace", "test_table"), assignments: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewParameterizedValue("value0")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("value1")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("value2")), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewParameterizedValue("value0", types.TypeBlob)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("value1", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("value2", types.TypeVarchar)), }, err: "", }, @@ -139,8 +139,8 @@ func Test_validateRequiredPrimaryKeys(t *testing.T) { name: "mixed types ok", table: mockdata.GetTableOrDie("test_keyspace", "user_info"), assignments: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "user_info", "age"), types.NewParameterizedValue("value1")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "user_info", "name"), types.NewParameterizedValue("value2")), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "user_info", "age"), types.NewParameterizedValue("value1", types.TypeBigInt)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "user_info", "name"), types.NewParameterizedValue("value2", types.TypeVarchar)), }, err: "", }, @@ -179,7 +179,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeVarchar, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), values: []*types.TypedGoValue{types.NewTypedGoValue("user1", types.TypeVarchar)}, - rowKey: []types.DynamicValue{types.NewParameterizedValue("value0")}, + rowKey: []types.DynamicValue{types.NewParameterizedValue("value0", types.TypeVarchar)}, want: "user1", }, { @@ -188,7 +188,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeBigInt, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), values: []*types.TypedGoValue{types.NewTypedGoValue(int64(1), types.TypeBigInt)}, - rowKey: []types.DynamicValue{types.NewParameterizedValue("value0")}, + rowKey: []types.DynamicValue{types.NewParameterizedValue("value0", types.TypeBigInt)}, want: "\x81", }, { @@ -197,7 +197,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeInt, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), values: []*types.TypedGoValue{types.NewTypedGoValue(int32(1), types.TypeInt)}, - rowKey: []types.DynamicValue{types.NewParameterizedValue("value0")}, + rowKey: []types.DynamicValue{types.NewParameterizedValue("value0", types.TypeInt)}, want: "\x81", }, { @@ -206,7 +206,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeInt, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), values: []*types.TypedGoValue{types.NewTypedGoValue(int32(1), types.TypeInt)}, - rowKey: []types.DynamicValue{types.NewParameterizedValue("value0")}, + rowKey: []types.DynamicValue{types.NewParameterizedValue("value0", types.TypeInt)}, want: "\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x01", }, { @@ -215,7 +215,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeInt, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), values: []*types.TypedGoValue{types.NewTypedGoValue(int64(2147483647), types.TypeBigInt)}, - rowKey: []types.DynamicValue{types.NewParameterizedValue("value0")}, + rowKey: []types.DynamicValue{types.NewParameterizedValue("value0", types.TypeBigInt)}, want: "\x00\xff\x00\xff\x00\xff\x00\xff\x7f\xff\xff\xff", }, { @@ -224,7 +224,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeBigInt, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), values: []*types.TypedGoValue{types.NewTypedGoValue(int64(9223372036854775807), types.TypeBigInt)}, - rowKey: []types.DynamicValue{types.NewParameterizedValue("value0")}, + rowKey: []types.DynamicValue{types.NewParameterizedValue("value0", types.TypeBigInt)}, want: "\x7f\xff\xff\xff\xff\xff\xff\xff", }, { @@ -233,7 +233,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeBigInt, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), values: []*types.TypedGoValue{types.NewTypedGoValue(int64(-1), types.TypeBigInt)}, - rowKey: []types.DynamicValue{types.NewParameterizedValue("value0")}, + rowKey: []types.DynamicValue{types.NewParameterizedValue("value0", types.TypeBigInt)}, want: "\x7f", }, { @@ -242,7 +242,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeBigInt, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), values: []*types.TypedGoValue{types.NewTypedGoValue(int64(-1), types.TypeBigInt)}, - rowKey: []types.DynamicValue{types.NewParameterizedValue("value0")}, + rowKey: []types.DynamicValue{types.NewParameterizedValue("value0", types.TypeBigInt)}, want: "", wantErr: "row keys with big endian encoding cannot contain negative integer values", }, @@ -252,7 +252,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeBigInt, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), values: []*types.TypedGoValue{types.NewTypedGoValue(int64(0), types.TypeBigInt)}, - rowKey: []types.DynamicValue{types.NewParameterizedValue("value0")}, + rowKey: []types.DynamicValue{types.NewParameterizedValue("value0", types.TypeBigInt)}, want: "\x80", }, { @@ -261,7 +261,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeBigInt, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), values: []*types.TypedGoValue{types.NewTypedGoValue(int64(math.MinInt64), types.TypeBigInt)}, - rowKey: []types.DynamicValue{types.NewParameterizedValue("value0")}, + rowKey: []types.DynamicValue{types.NewParameterizedValue("value0", types.TypeBigInt)}, want: "\x00\xff\x3f\x80\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff", }, { @@ -270,7 +270,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeBigInt, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), values: []*types.TypedGoValue{types.NewTypedGoValue(int64(-922337203685473), types.TypeBigInt)}, - rowKey: []types.DynamicValue{types.NewParameterizedValue("value0")}, + rowKey: []types.DynamicValue{types.NewParameterizedValue("value0", types.TypeBigInt)}, want: "\x00\xff\xfc\xb9\x23\xa2\x9c\x77\x9f", }, { @@ -279,7 +279,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeInt, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), values: []*types.TypedGoValue{types.NewTypedGoValue(int64(math.MinInt32), types.TypeInt)}, - rowKey: []types.DynamicValue{types.NewParameterizedValue("value0")}, + rowKey: []types.DynamicValue{types.NewParameterizedValue("value0", types.TypeInt)}, want: "\x07\x80\x00\xff\x00\xff\x00\xff", }, { @@ -295,9 +295,9 @@ func TestCreateOrderedCodeKey(t *testing.T) { types.NewTypedGoValue("id123", types.TypeVarchar), }, rowKey: []types.DynamicValue{ - types.NewParameterizedValue("value0"), - types.NewParameterizedValue("value1"), - types.NewParameterizedValue("value2"), + types.NewParameterizedValue("value0", types.TypeBigInt), + types.NewParameterizedValue("value1", types.TypeInt), + types.NewParameterizedValue("value2", types.TypeVarchar), }, want: "\x00\xff\x3f\x80\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\x01\x07\x80\x00\xff\x00\xff\x00\xff\x00\x01\x69\x64\x31\x32\x33", }, @@ -308,8 +308,8 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "other_id", CQLType: types.TypeInt, KeyType: types.KeyTypePartition, PkPrecedence: 2}, }), rowKey: []types.DynamicValue{ - types.NewLiteralValue(int64(-43232545)), - types.NewLiteralValue(int64(-12451)), + types.NewLiteralValue(int64(-43232545), types.TypeBigInt), + types.NewLiteralValue(int64(-12451), types.TypeInt), }, want: "\x0d\x6c\x52\xdf\x00\x01\x1f\xcf\x5d", }, @@ -319,7 +319,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeBigInt, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), rowKey: []types.DynamicValue{ - types.NewLiteralValue(int64(0)), + types.NewLiteralValue(int64(0), types.TypeBigInt), }, want: "\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff", }, @@ -336,9 +336,9 @@ func TestCreateOrderedCodeKey(t *testing.T) { types.NewTypedGoValue("new york", types.TypeVarchar), }, rowKey: []types.DynamicValue{ - types.NewParameterizedValue("value0"), - types.NewParameterizedValue("value1"), - types.NewParameterizedValue("value2"), + types.NewParameterizedValue("value0", types.TypeVarchar), + types.NewParameterizedValue("value1", types.TypeBigInt), + types.NewParameterizedValue("value2", types.TypeVarchar), }, want: "user1\x00\x01\x81\x00\x01new york", }, @@ -350,9 +350,9 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "city", CQLType: types.TypeVarchar, KeyType: types.KeyTypeClustering, PkPrecedence: 3}, }), rowKey: []types.DynamicValue{ - types.NewLiteralValue("user1"), - types.NewLiteralValue(int64(1)), - types.NewLiteralValue("new york"), + types.NewLiteralValue("user1", types.TypeVarchar), + types.NewLiteralValue(int64(1), types.TypeBigInt), + types.NewLiteralValue("new york", types.TypeVarchar), }, want: "user1\x00\x01\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x01\x00\x01new york", }, @@ -364,9 +364,9 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "city", CQLType: types.TypeVarchar, KeyType: types.KeyTypeClustering, PkPrecedence: 3}, }), rowKey: []types.DynamicValue{ - types.NewLiteralValue("user1"), - types.NewLiteralValue(int64(1)), - types.NewLiteralValue("new york"), + types.NewLiteralValue("user1", types.TypeVarchar), + types.NewLiteralValue(int64(1), types.TypeBigInt), + types.NewLiteralValue("new york", types.TypeVarchar), }, want: "", wantErr: "unhandled int encoding type", @@ -386,10 +386,10 @@ func TestCreateOrderedCodeKey(t *testing.T) { types.NewTypedGoValue("", types.TypeVarchar), }, rowKey: []types.DynamicValue{ - types.NewParameterizedValue("value0"), - types.NewParameterizedValue("value1"), - types.NewParameterizedValue("value2"), - types.NewParameterizedValue("value3"), + types.NewParameterizedValue("value0", types.TypeVarchar), + types.NewParameterizedValue("value1", types.TypeBigInt), + types.NewParameterizedValue("value2", types.TypeVarchar), + types.NewParameterizedValue("value3", types.TypeVarchar), }, want: "user3\x00\x01\x83", }, @@ -408,10 +408,10 @@ func TestCreateOrderedCodeKey(t *testing.T) { types.NewTypedGoValue("", types.TypeVarchar), }, rowKey: []types.DynamicValue{ - types.NewParameterizedValue("value0"), - types.NewParameterizedValue("value1"), - types.NewParameterizedValue("value2"), - types.NewParameterizedValue("value3"), + types.NewParameterizedValue("value0", types.TypeVarchar), + types.NewParameterizedValue("value1", types.TypeBigInt), + types.NewParameterizedValue("value2", types.TypeVarchar), + types.NewParameterizedValue("value3", types.TypeVarchar), }, want: "user3\x00\x01\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x03", }, @@ -428,9 +428,9 @@ func TestCreateOrderedCodeKey(t *testing.T) { types.NewTypedGoValue("\xb7", types.TypeBlob), }, rowKey: []types.DynamicValue{ - types.NewParameterizedValue("value0"), - types.NewParameterizedValue("value1"), - types.NewParameterizedValue("value2"), + types.NewParameterizedValue("value0", types.TypeBlob), + types.NewParameterizedValue("value1", types.TypeBlob), + types.NewParameterizedValue("value2", types.TypeBlob), }, want: "\xa2\x00\x01\x00\x00\x00\x01\xb7", }, @@ -440,7 +440,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeBlob, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), rowKey: []types.DynamicValue{ - types.NewLiteralValue("\x80\x00\x01\x81"), + types.NewLiteralValue("\x80\x00\x01\x81", types.TypeBlob), }, want: "\x80\x00\xff\x01\x81", }, @@ -453,10 +453,10 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "borough", CQLType: types.TypeBlob, KeyType: types.KeyTypeClustering, PkPrecedence: 4}, }), rowKey: []types.DynamicValue{ - types.NewLiteralValue("\xa2"), - types.NewLiteralValue(""), - types.NewLiteralValue(""), - types.NewLiteralValue("\xb7"), + types.NewLiteralValue("\xa2", types.TypeBlob), + types.NewLiteralValue("", types.TypeBlob), + types.NewLiteralValue("", types.TypeBlob), + types.NewLiteralValue("\xb7", types.TypeBlob), }, want: "\xa2\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\xb7", }, @@ -467,8 +467,8 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "city", CQLType: types.TypeBlob, KeyType: types.KeyTypeClustering, PkPrecedence: 2}, }), rowKey: []types.DynamicValue{ - types.NewLiteralValue("\xa5"), - types.NewLiteralValue("\x90"), + types.NewLiteralValue("\xa5", types.TypeBlob), + types.NewLiteralValue("\x90", types.TypeBlob), }, want: "\xa5\x00\x01\x90", }, @@ -479,8 +479,8 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "city", CQLType: types.TypeBlob, KeyType: types.KeyTypeClustering, PkPrecedence: 2}, }), rowKey: []types.DynamicValue{ - types.NewLiteralValue(""), - types.NewLiteralValue("\xaa"), + types.NewLiteralValue("", types.TypeVarchar), + types.NewLiteralValue("\xaa", types.TypeBlob), }, want: "\x00\x00\x00\x01\xaa", }, @@ -492,9 +492,9 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "borough", CQLType: types.TypeVarchar, KeyType: types.KeyTypeClustering, PkPrecedence: 3}, }), rowKey: []types.DynamicValue{ - types.NewLiteralValue("nn"), - types.NewLiteralValue("t\x00t"), - types.NewLiteralValue("end"), + types.NewLiteralValue("nn", types.TypeVarchar), + types.NewLiteralValue("t\x00t", types.TypeVarchar), + types.NewLiteralValue("end", types.TypeVarchar), }, want: "nn\x00\x01t\x00\xfft\x00\x01end", }, @@ -506,9 +506,9 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "city", CQLType: types.TypeVarchar, KeyType: types.KeyTypeClustering, PkPrecedence: 3}, }), rowKey: []types.DynamicValue{ - types.NewLiteralValue("abcd"), - types.NewLiteralValue(int64(45)), - types.NewLiteralValue("name"), + types.NewLiteralValue("abcd", types.TypeVarchar), + types.NewLiteralValue(int64(45), types.TypeBigInt), + types.NewLiteralValue("name", types.TypeVarchar), }, want: "abcd\x00\x01\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x2d\x00\x01name", }, @@ -518,7 +518,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeVarchar, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), rowKey: []types.DynamicValue{ - types.NewLiteralValue("\x00\x01"), + types.NewLiteralValue("\x00\x01", types.TypeVarchar), }, want: "\x00\xff\x01", }, @@ -529,7 +529,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { }), values: []*types.TypedGoValue{}, rowKey: []types.DynamicValue{ - types.NewParameterizedValue("value1"), + types.NewParameterizedValue("value1", types.TypeVarchar), }, want: "", wantErr: "no query param for value1", @@ -540,7 +540,7 @@ func TestCreateOrderedCodeKey(t *testing.T) { {Name: "user_id", CQLType: types.TypeVarchar, KeyType: types.KeyTypePartition, PkPrecedence: 1}, }), rowKey: []types.DynamicValue{ - types.NewLiteralValue(nil), + types.NewLiteralValue(nil, types.TypeVarchar), }, want: "", wantErr: "value cannot be null for primary key 'user_id'", @@ -550,6 +550,16 @@ func TestCreateOrderedCodeKey(t *testing.T) { t.Run(tt.name, func(t *testing.T) { values, err := mockdata.CreateQueryParams(tt.values) require.NoError(t, err) + + // We need to ensure that literal values in tt.rowKey also have types if they are used + for i, rv := range tt.rowKey { + if lit, ok := rv.(*types.LiteralValue); ok { + if i < len(tt.tableConfig.PrimaryKeys) { + tt.rowKey[i] = types.NewLiteralValue(lit.Value, tt.tableConfig.PrimaryKeys[i].CQLType) + } + } + } + got, err := BindRowKey(tt.tableConfig, tt.rowKey, values) if tt.wantErr != "" { require.Error(t, err) @@ -748,12 +758,12 @@ func TestRelationFragment(t *testing.T) { require.NoError(t, err) param, ok := result.(*types.ParameterizedValue) assert.True(t, ok) - assert.Equal(t, types.Parameter("my_marker_1"), param.Parameter) + assert.Equal(t, types.Parameter("my_marker_1"), param.GetParameter()) builtParams, err := qp.Build() assert.NoError(t, err) - metadata, err := builtParams.GetMetadata(param.Parameter) + metadata, err := builtParams.GetMetadata(param.GetParameter()) require.NoError(t, err) assert.Equal(t, types.Parameter("my_marker_1"), metadata.Key) assert.Equal(t, types.TypeText, metadata.Type) diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/create_translator/translator_create_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/create_translator/translator_create_test.go index 78cade49..64e3e258 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/create_translator/translator_create_test.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/create_translator/translator_create_test.go @@ -410,9 +410,9 @@ func TestTranslateCreateTableToBigtable(t *testing.T) { }, { name: "parser returns error when invalid column type is used", - query: "CREATE TABLE test_keyspace.table1 (column1 int, column10 UUID, column11 int, PRIMARY KEY (column1))", + query: "CREATE TABLE test_keyspace.table1 (column1 int, column10 TUPLE, column11 int, PRIMARY KEY (column1))", want: nil, - error: "column type 'uuid' is not supported", + error: "unknown data type name: 'TUPLE'", defaultKeyspace: "test_keyspace", }, { diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/delete_translator/translator_delete_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/delete_translator/translator_delete_test.go index 9bff2dd8..55ac7eb3 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/delete_translator/translator_delete_test.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/delete_translator/translator_delete_test.go @@ -63,8 +63,8 @@ func TestTranslator_TranslateDeleteQuerytoBigtable(t *testing.T) { Table: "user_info", IfExists: false, RowKey: []types.DynamicValue{ - types.NewLiteralValue("test"), - types.NewLiteralValue(int64(72)), + types.NewLiteralValue("test", types.TypeVarchar), + types.NewLiteralValue(int64(72), types.TypeBigInt), }, SelectedColumns: nil, }, @@ -78,8 +78,8 @@ func TestTranslator_TranslateDeleteQuerytoBigtable(t *testing.T) { Table: "user_info", IfExists: false, RowKey: []types.DynamicValue{ - types.NewParameterizedValue("value0"), - types.NewParameterizedValue("value1"), + types.NewParameterizedValue("value0", types.TypeVarchar), + types.NewParameterizedValue("value1", types.TypeBigInt), }, SelectedColumns: nil, }, @@ -93,8 +93,8 @@ func TestTranslator_TranslateDeleteQuerytoBigtable(t *testing.T) { Table: "user_info", IfExists: false, RowKey: []types.DynamicValue{ - types.NewLiteralValue("test"), - types.NewLiteralValue(int64(72)), + types.NewLiteralValue("test", types.TypeVarchar), + types.NewLiteralValue(int64(72), types.TypeBigInt), }, SelectedColumns: nil, }, @@ -119,8 +119,8 @@ func TestTranslator_TranslateDeleteQuerytoBigtable(t *testing.T) { Table: "user_info", IfExists: true, RowKey: []types.DynamicValue{ - types.NewLiteralValue("test"), - types.NewLiteralValue(int64(72)), + types.NewLiteralValue("test", types.TypeVarchar), + types.NewLiteralValue(int64(72), types.TypeBigInt), }, SelectedColumns: nil, }, @@ -134,8 +134,8 @@ func TestTranslator_TranslateDeleteQuerytoBigtable(t *testing.T) { Table: "user_info", IfExists: true, RowKey: []types.DynamicValue{ - types.NewLiteralValue("tes't"), - types.NewLiteralValue(int64(72)), + types.NewLiteralValue("tes't", types.TypeVarchar), + types.NewLiteralValue(int64(72), types.TypeBigInt), }, SelectedColumns: nil, }, @@ -149,8 +149,8 @@ func TestTranslator_TranslateDeleteQuerytoBigtable(t *testing.T) { Table: "user_info", IfExists: false, RowKey: []types.DynamicValue{ - types.NewLiteralValue("test"), - types.NewLiteralValue(int64(72)), + types.NewLiteralValue("test", types.TypeVarchar), + types.NewLiteralValue(int64(72), types.TypeBigInt), }, SelectedColumns: nil, }, diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/insert_translator/translator_insert.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/insert_translator/translator_insert.go index 8a80c084..8ef9d1b6 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/insert_translator/translator_insert.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/insert_translator/translator_insert.go @@ -48,7 +48,7 @@ func (t *InsertTranslator) Translate(query *types.RawQuery, sessionKeyspace type return nil, err } - values, err := parseInsertValues(insertObj.InsertValuesSpec(), columns, params) + values, err := parseInsertValues(insertObj.InsertValuesSpec(), table, columns, params) if err != nil { return nil, err } diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/insert_translator/translator_insert_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/insert_translator/translator_insert_test.go index 17edb82d..79ee6994 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/insert_translator/translator_insert_test.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/insert_translator/translator_insert_test.go @@ -50,8 +50,8 @@ func TestSelectTranslator_Translate(t *testing.T) { Table: "test_table", IfNotExists: false, Assignments: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("value0")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("value1")), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("value0", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("value1", types.TypeVarchar)), }, AllParams: []*types.ParameterMetadata{ { @@ -77,8 +77,8 @@ func TestSelectTranslator_Translate(t *testing.T) { Table: "test_table", IfNotExists: false, Assignments: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("v_1")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("v_2")), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("v_1", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("v_2", types.TypeVarchar)), }, AllParams: []*types.ParameterMetadata{ { @@ -104,9 +104,9 @@ func TestSelectTranslator_Translate(t *testing.T) { Table: "test_table", IfNotExists: false, Assignments: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("pk")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("pk")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), types.NewParameterizedValue("i")), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("pk", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("pk", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), types.NewParameterizedValue("i", types.TypeInt)), }, AllParams: []*types.ParameterMetadata{ { @@ -132,15 +132,15 @@ func TestSelectTranslator_Translate(t *testing.T) { Table: "test_table", IfNotExists: false, Assignments: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("value0")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewParameterizedValue("value1")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bool"), types.NewParameterizedValue("value2")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "list_text"), types.NewParameterizedValue("value3")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), types.NewParameterizedValue("value4")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bigint"), types.NewParameterizedValue("value5")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("value6")), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("value0", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewParameterizedValue("value1", types.TypeBlob)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bool"), types.NewParameterizedValue("value2", types.TypeBoolean)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "list_text"), types.NewParameterizedValue("value3", types.NewListType(types.TypeText))), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), types.NewParameterizedValue("value4", types.TypeInt)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bigint"), types.NewParameterizedValue("value5", types.TypeBigInt)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("value6", types.TypeVarchar)), }, - UsingTimestamp: types.NewParameterizedValue("value7"), + UsingTimestamp: types.NewParameterizedValue("value7", types.TypeBigInt), AllParams: []*types.ParameterMetadata{ { Key: "value0", @@ -201,16 +201,16 @@ func TestSelectTranslator_Translate(t *testing.T) { Table: "test_table", IfNotExists: false, Assignments: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewLiteralValue("u123")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewLiteralValue([]byte{0x00, 0x03})), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bool"), types.NewLiteralValue(true)), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "list_text"), types.NewLiteralValue([]types.GoValue{"item1", "item2", "item1"})), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), types.NewLiteralValue(int32(3))), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bigint"), types.NewLiteralValue(int64(8242842848))), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewLiteralValue("org1")), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewLiteralValue("u123", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewLiteralValue([]byte{0x00, 0x03}, types.TypeBlob)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bool"), types.NewLiteralValue(true, types.TypeBoolean)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "list_text"), types.NewLiteralValue([]types.GoValue{"item1", "item2", "item1"}, types.NewListType(types.TypeText))), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), types.NewLiteralValue(int32(3), types.TypeInt)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bigint"), types.NewLiteralValue(int64(8242842848), types.TypeBigInt)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewLiteralValue("org1", types.TypeVarchar)), }, AllParams: []*types.ParameterMetadata{}, - UsingTimestamp: types.NewLiteralValue(int64(234242424)), + UsingTimestamp: types.NewLiteralValue(int64(234242424), types.TypeBigInt), }, }, { @@ -226,8 +226,8 @@ func TestSelectTranslator_Translate(t *testing.T) { Table: "test_table", IfNotExists: false, Assignments: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("value0")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("value1")), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewParameterizedValue("value0", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewParameterizedValue("value1", types.TypeVarchar)), }, AllParams: []*types.ParameterMetadata{ { @@ -253,9 +253,9 @@ func TestSelectTranslator_Translate(t *testing.T) { Table: "test_table", Keyspace: "test_keyspace", Assignments: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewLiteralValue("abc")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewLiteralValue("pkval")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "map_text_text"), types.NewLiteralValue(map[types.GoValue]types.GoValue{"foo": "bar", "key:": ":value", "k}": "{v:k}"})), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewLiteralValue("abc", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewLiteralValue("pkval", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "map_text_text"), types.NewLiteralValue(map[types.GoValue]types.GoValue{"foo": "bar", "key:": ":value", "k}": "{v:k}"}, types.NewMapType(types.TypeText, types.TypeText))), }, AllParams: []*types.ParameterMetadata{}, }, @@ -267,9 +267,9 @@ func TestSelectTranslator_Translate(t *testing.T) { Table: "test_table", Keyspace: "test_keyspace", Assignments: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewLiteralValue("abc")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewLiteralValue("pkva'l")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), types.NewLiteralValue(int32(3))), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewLiteralValue("abc", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewLiteralValue("pkva'l", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), types.NewLiteralValue(int32(3), types.TypeInt)), }, AllParams: []*types.ParameterMetadata{}, }, @@ -281,9 +281,9 @@ func TestSelectTranslator_Translate(t *testing.T) { Table: "test_table", Keyspace: "test_keyspace", Assignments: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewLiteralValue("abc")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewLiteralValue("pkval")), - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), types.NewLiteralValue(nil)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), types.NewLiteralValue("abc", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), types.NewLiteralValue("pkval", types.TypeVarchar)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), types.NewLiteralValue(nil, types.TypeInt)), }, AllParams: []*types.ParameterMetadata{}, }, diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/insert_translator/utils.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/insert_translator/utils.go index 632a2d3c..e2c58ae5 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/insert_translator/utils.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/insert_translator/utils.go @@ -49,7 +49,7 @@ func parseInsertColumns(input cql.IInsertColumnSpecContext, tableConfig *schemaM return result, nil } -func parseInsertValues(input cql.IInsertValuesSpecContext, columns []*types.Column, params *types.QueryParameterBuilder) ([]types.Assignment, error) { +func parseInsertValues(input cql.IInsertValuesSpecContext, table *schemaMapping.TableSchema, columns []*types.Column, params *types.QueryParameterBuilder) ([]types.Assignment, error) { if input == nil { return nil, errors.New("insert values clause missing or malformed") } @@ -71,7 +71,7 @@ func parseInsertValues(input cql.IInsertValuesSpecContext, columns []*types.Colu var assignments []types.Assignment for i, v := range allValues { column := columns[i] - value, err := common.ParseValueAny(v, column.CQLType, params, column) + value, err := common.ParseValueAny(v, table, column.CQLType, types.QueryClauseValues, params, column) if err != nil { return nil, err } diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/select_query_builder.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/select_query_builder.go index 62514517..1fb5e990 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/select_query_builder.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/select_query_builder.go @@ -7,129 +7,119 @@ import ( sm "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/metadata" "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/utilities" "github.com/datastax/go-cassandra-native-protocol/datatype" - "github.com/datastax/go-cassandra-native-protocol/primitive" "strings" ) -func createBtqlSelectClause(tableConfig *sm.TableSchema, s *types.SelectClause, isGroupBy bool) (string, error) { +func createBtqlSelectClause(s *types.SelectClause, isGroupBy bool) (string, error) { if s.IsStar { return "*", nil } var columns []string for _, col := range s.Columns { - if col.Func != types.FuncCodeUnknown { - c, err := createBtqlFunc(col, tableConfig) - if err != nil { - return "", err - } - columns = append(columns, c) - } else { - c, err := createBtqlSelectCol(tableConfig, col, isGroupBy) - if err != nil { - return "", err - } - columns = append(columns, c) - } - } - - return strings.Join(columns, ", "), nil -} - -func createBtqlFunc(col types.SelectedColumn, tableConfig *sm.TableSchema) (string, error) { - if col.Func == types.FuncCodeCount && col.ColumnName == "*" { - if col.Alias != "" { - return "count(*) as " + col.Alias, nil - } - return "count(*)", nil - } - - colMeta, found := tableConfig.Columns[col.ColumnName] - if !found { - // Check if the column is an alias - if aliasMeta, aliasFound := tableConfig.Columns[types.ColumnName(col.Alias)]; aliasFound { - colMeta = aliasMeta - } else { - return "", fmt.Errorf("column metadata not found for column '%s' in table '%s' and keyspace '%s'", col.ColumnName, tableConfig.Name, tableConfig.Keyspace) + c, err := toBtql(col.Value) + if err != nil { + return "", err } - } - - if col.Func == types.FuncCodeWriteTime { - // todo what about collections? if col.Alias != "" { - return fmt.Sprintf("UNIX_MICROS(WRITE_TIMESTAMP(%s, '%s')) AS %s", colMeta.ColumnFamily, colMeta.Name, col.Alias), nil + c = fmt.Sprintf("%s AS %s", c, col.Alias) } - return fmt.Sprintf("UNIX_MICROS(WRITE_TIMESTAMP(%s, '%s'))", colMeta.ColumnFamily, colMeta.Name), nil + columns = append(columns, c) } - castValue, castErr := castScalarColumn(colMeta) - if castErr != nil { - return "", castErr - } - column := fmt.Sprintf("%s(%s)", col.Func.String(), castValue) + return strings.Join(columns, ", "), nil +} - if col.Alias != "" { - column = column + " as " + col.Alias +func toBtql(value types.DynamicValue) (string, error) { + switch v := value.(type) { + case *types.SelectStarValue: + return "*", nil + case *types.ColumnValue: + return processRegularColumn(v) + case *types.MapAccessValue: + return fmt.Sprintf("`%s`['%s']", v.Column.Name, v.MapKey), nil + case *types.FunctionValue: + return createBtqlFunc(v) + case *types.LiteralValue: + return utilities.GoToQueryString(v.Value) + case *types.ParameterizedValue: + return "@" + string(v.GetParameter()), nil + default: + return "", fmt.Errorf("unhandled dynamic value type: %T", v) } - - return column, nil } -func createBtqlSelectCol(tableConfig *sm.TableSchema, selectedColumn types.SelectedColumn, isGroupBy bool) (string, error) { - colName := selectedColumn.Sql - if selectedColumn.MapKey != "" { - colName = string(selectedColumn.ColumnName) +func createBtqlFunc(f *types.FunctionValue) (string, error) { + if f.GetParameter() != "" { + return "@" + string(f.GetParameter()), nil } - col, err := tableConfig.GetColumn(types.ColumnName(colName)) - if err != nil { - return "", err - } - var sql string - if isGroupBy { - sql, err = castScalarColumn(col) + + switch f.Func.GetCode() { + case types.FuncCodeCount: + arg0, err := toBtql(f.Args[0]) if err != nil { return "", err } - } else { - sql, err = processRegularColumn(selectedColumn, col) + return fmt.Sprintf("COUNT(%s)", arg0), nil + case types.FuncCodeWriteTime: + col, err := getColumnArg(0, f.Args) if err != nil { return "", err } + return fmt.Sprintf("UNIX_MICROS(WRITE_TIMESTAMP(%s, '%s'))", col.ColumnFamily, col.Name), nil + case types.FuncCodeAvg: + return createSimpleBtqlFunc(f) + case types.FuncCodeSum: + return createSimpleBtqlFunc(f) + case types.FuncCodeMin: + return createSimpleBtqlFunc(f) + case types.FuncCodeMax: + return createSimpleBtqlFunc(f) + default: + return "", fmt.Errorf("unhandled function translation: %s", f.Func.GetName()) } +} - if selectedColumn.Alias != "" { - sql = fmt.Sprintf("%s as %s", sql, selectedColumn.Alias) +func createSimpleBtqlFunc(f *types.FunctionValue) (string, error) { + col, err := getColumnArg(0, f.Args) + if err != nil { + return "", err + } + castValue, err := castScalarColumn(col) + if err != nil { + return "", err } - return sql, nil + return fmt.Sprintf("%s(%s)", f.Func.GetName(), castValue), nil } -/* -processRegularColumn processes the given column based on its metadata and table context. - -It formats the column name differently depending on whether the current table name matches the column metadata's name. -If there is a match, the function qualifies the column name using the table name; otherwise, it formats the column name as standalone. -Additionally, if the column is not a collection, it builds a formatted reference that includes accessing the column within the specified column family; -if the column is a collection, it uses the preformatted column name from the metadata. - -Parameters: - - columnMetadata: Specifies metadata for the selected column, including its name and a field for storing the formatted version. - - tableName: The name of the current table to determine if table-qualified formatting is needed. - - columnFamily: The column family identifier used when constructing the column reference for non-collection types. - - colMeta: A pointer to column configuration containing additional details such as whether the column is a collection. - - columns: A slice of strings that accumulates the formatted column references. +func getColumnArgOrStar(index int, args []types.DynamicValue) (types.DynamicValue, error) { + value := args[index] + star, ok := value.(types.SelectStarValue) + if ok { + return star, nil + } + col, ok := value.(types.ColumnValue) + if ok { + return col, nil + } + return nil, fmt.Errorf("invalid argument: %T expected column or *", value) +} -Returns: +func getColumnArg(index int, args []types.DynamicValue) (*types.Column, error) { + value := args[index] + col, ok := value.(*types.ColumnValue) + if !ok { + return nil, fmt.Errorf("invalid argument: %T expected a column", value) + } + return col.Column, nil +} - An updated slice of strings with the new formatted column reference appended. -*/ -func processRegularColumn(selectedColumn types.SelectedColumn, col *types.Column) (string, error) { - if col.CQLType.DataType().GetDataTypeCode() == primitive.DataTypeCodeList { - return fmt.Sprintf("MAP_VALUES(`%s`)", selectedColumn.Sql), nil - } else if selectedColumn.MapKey != "" { - return fmt.Sprintf("`%s`['%s']", selectedColumn.ColumnName, selectedColumn.MapKey), nil - } else if col.CQLType.IsCollection() { - return fmt.Sprintf("`%s`", selectedColumn.Sql), nil +func processRegularColumn(col *types.ColumnValue) (string, error) { + if col.Column.CQLType.Code() == types.LIST { + return fmt.Sprintf("MAP_VALUES(`%s`)", col.Column.Name), nil + } else if col.Column.CQLType.IsCollection() { + return fmt.Sprintf("`%s`", col.Column.Name), nil } else { - return castScalarColumn(col) + return castScalarColumn(col.Column) } } @@ -149,7 +139,7 @@ func createBigtableSql(t *SelectTranslator, st *types.PreparedSelectQuery) (stri if len(st.GroupByColumns) > 0 { isGroupBy = true } - column, err = createBtqlSelectClause(tableConfig, st.SelectClause, isGroupBy) + column, err = createBtqlSelectClause(st.SelectClause, isGroupBy) if err != nil { return "", err } @@ -164,10 +154,10 @@ func createBigtableSql(t *SelectTranslator, st *types.PreparedSelectQuery) (stri } // Build alias-to-column map - aliasToColumn := make(map[string]string) + aliasToColumn := make(map[string]bool) for _, col := range st.SelectClause.Columns { if col.Alias != "" { - aliasToColumn[col.Alias] = string(col.ColumnName) + aliasToColumn[col.Alias] = true } } @@ -223,7 +213,7 @@ func createBigtableSql(t *SelectTranslator, st *types.PreparedSelectQuery) (stri } if st.LimitValue != nil { - limitString, err := ToBtql(st.LimitValue) + limitString, err := toBtql(st.LimitValue) if err != nil { return "", err } @@ -233,19 +223,6 @@ func createBigtableSql(t *SelectTranslator, st *types.PreparedSelectQuery) (stri return btQuery, nil } -func ToBtql(dynamicValue types.DynamicValue) (string, error) { - switch v := dynamicValue.(type) { - case *types.LiteralValue: - return utilities.GoToString(v.Value) - case *types.ParameterizedValue: - return "@" + string(v.Parameter), nil - case *types.TimestampNowValue: - return "CURRENT_TIMESTAMP()", nil - default: - return "", fmt.Errorf("unhandled value type %T", v) - } -} - // createBtqlWhereClause(): takes a slice of Condition structs and returns a string representing the WHERE clause of a bigtable SQL query. // It iterates over the clauses and constructs the WHERE clause by combining the column name, operator, and value of each clause. // If the operator is "IN", the value is wrapped with the UNNEST function. @@ -267,24 +244,24 @@ func createBtqlWhereClause(conditions []types.Condition, tableConfig *sm.TableSc var btql string if condition.Operator == types.BETWEEN { - v1, err := ToBtql(condition.Value) + v1, err := toBtql(condition.Value) if err != nil { return "", err } - v2, err := ToBtql(condition.Value2) + v2, err := toBtql(condition.Value2) if err != nil { return "", err } btql = fmt.Sprintf("%s BETWEEN %s AND %s", column, v1, v2) } else if condition.Operator == types.IN { - v, err := ToBtql(condition.Value) + v, err := toBtql(condition.Value) if err != nil { return "", err } btql = fmt.Sprintf("%s IN UNNEST(%s)", column, v) } else if condition.Operator == types.CONTAINS || condition.Operator == types.CONTAINS_KEY { - v, err := ToBtql(condition.Value) + v, err := toBtql(condition.Value) if err != nil { return "", err } @@ -294,7 +271,7 @@ func createBtqlWhereClause(conditions []types.Condition, tableConfig *sm.TableSc btql = fmt.Sprintf("ARRAY_INCLUDES(MAP_VALUES(%s), %s)", column, v) } } else { - v, err := ToBtql(condition.Value) + v, err := toBtql(condition.Value) if err != nil { return "", err } @@ -338,7 +315,7 @@ func castScalarColumn(colMeta *types.Column) (string, error) { return fmt.Sprintf("TIMESTAMP_FROM_UNIX_MILLIS(TO_INT64(`%s`['%s']))", colMeta.ColumnFamily, colMeta.Name), nil case datatype.Counter: return fmt.Sprintf("`%s`['']", colMeta.Name), nil - case datatype.Blob: + case datatype.Blob, datatype.Uuid, datatype.Timeuuid: return fmt.Sprintf("`%s`['%s']", colMeta.ColumnFamily, colMeta.Name), nil case datatype.Varchar, datatype.Ascii: return fmt.Sprintf("`%s`['%s']", colMeta.ColumnFamily, colMeta.Name), nil diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/translator_select.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/translator_select.go index 216333e1..d8297855 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/translator_select.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/translator_select.go @@ -21,7 +21,6 @@ import ( "fmt" "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types" "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/common" - "github.com/GoogleCloudPlatform/cloud-bigtable-ecosystem/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/utilities" "github.com/datastax/go-cassandra-native-protocol/primitive" ) @@ -41,13 +40,13 @@ func (t *SelectTranslator) Translate(query *types.RawQuery, sessionKeyspace type return nil, err } - selectClause, err := parseSelectClause(selectObj.SelectElements(), tableConfig) + params := types.NewQueryParameterBuilder() + + selectClause, err := parseSelectClause(selectObj.SelectElements(), tableConfig, params) if err != nil { return nil, err } - - params := types.NewQueryParameterBuilder() - + conditions, err := common.ParseWhereClause(selectObj.WhereSpec(), tableConfig, params) if err != nil { return nil, err @@ -102,7 +101,7 @@ func (t *SelectTranslator) Bind(st types.IPreparedQuery, values *types.QueryPara } if sst.LimitValue != nil { - v, err := utilities.GetValueInt32(sst.LimitValue, values) + v, err := values.GetValueInt32(sst.LimitValue) if err != nil { return nil, err } diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/translator_select_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/translator_select_test.go index 5f830a3d..92b4bf18 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/translator_select_test.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/translator_select_test.go @@ -40,6 +40,17 @@ type Want struct { AllParams []*types.ParameterMetadata } +func NewSelectedColumnFunction(cql string, columnName string, alias string, funcCode types.CqlFuncCode, k types.Keyspace, t types.TableName) types.SelectedColumn { + f, _ := types.GetFunc(funcCode) + var arg types.DynamicValue + if columnName == "*" { + arg = types.NewSelectStarValue() + } else { + arg = types.NewColumnValue(mockdata.GetColumnOrDie(k, t, types.ColumnName(columnName))) + } + return types.NewSelectedColumn(cql, types.NewFunctionValue("", f, arg), alias) +} + func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { tests := []struct { @@ -61,43 +72,43 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), - *types.NewSelectedColumn("col_int", "col_int", "", types.TypeInt), - *types.NewSelectedColumn("col_bool", "col_bool", "", types.TypeBoolean), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), + types.NewSelectedColumn("col_int", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int")), ""), + types.NewSelectedColumn("col_bool", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bool")), ""), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: types.EQ, - Value: types.NewLiteralValue("test"), + Value: types.NewLiteralValue("test", types.TypeVarchar), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bool"), Operator: types.EQ, - Value: types.NewLiteralValue(true), + Value: types.NewLiteralValue(true, types.TypeBoolean), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_ts"), Operator: types.LTE, - Value: types.NewLiteralValue(time.UnixMilli(1430659854234).Truncate(time.Nanosecond).UTC()), + Value: types.NewLiteralValue(time.UnixMilli(1430659854234).Truncate(time.Nanosecond).UTC(), types.TypeTimestamp), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), Operator: types.GTE, - Value: types.NewLiteralValue(int32(123)), + Value: types.NewLiteralValue(int32(123), types.TypeInt), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bigint"), Operator: types.GT, - Value: types.NewLiteralValue(int64(-10000000)), + Value: types.NewLiteralValue(int64(-10000000), types.TypeBigInt), }, }, AllParams: []*types.ParameterMetadata{}, OrderBy: types.OrderBy{ IsOrderBy: false, }, - LimitValue: types.NewLiteralValue(int32(20)), + LimitValue: types.NewLiteralValue(int32(20), types.TypeInt), }, sessionKeyspace: "test_keyspace", }, @@ -105,19 +116,19 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { name: "Select query with list contains clause", query: `select col_int as name from test_keyspace.test_table where list_text CONTAINS 'test';`, want: &Want{ - TranslatedQuery: "SELECT TO_INT64(`cf1`['col_int']) as name FROM test_table WHERE ARRAY_INCLUDES(MAP_VALUES(`list_text`), 'test');", + TranslatedQuery: "SELECT TO_INT64(`cf1`['col_int']) AS name FROM test_table WHERE ARRAY_INCLUDES(MAP_VALUES(`list_text`), 'test');", Table: "test_table", Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("col_int", "col_int", "name", types.TypeInt), + types.NewSelectedColumn("col_int", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int")), "name"), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "list_text"), Operator: types.CONTAINS, - Value: types.NewLiteralValue("test"), + Value: types.NewLiteralValue("test", types.TypeText), }, }, OrderBy: types.OrderBy{ @@ -131,19 +142,19 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { name: "Select query with map contains key clause", query: `select col_int as name from test_keyspace.test_table where map_text_text CONTAINS KEY 'test';`, want: &Want{ - TranslatedQuery: "SELECT TO_INT64(`cf1`['col_int']) as name FROM test_table WHERE MAP_CONTAINS_KEY(`map_text_text`, 'test');", + TranslatedQuery: "SELECT TO_INT64(`cf1`['col_int']) AS name FROM test_table WHERE MAP_CONTAINS_KEY(`map_text_text`, 'test');", Table: "test_table", Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("col_int", "col_int", "name", types.TypeInt), + types.NewSelectedColumn("col_int", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int")), "name"), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "map_text_text"), Operator: types.CONTAINS_KEY, - Value: types.NewLiteralValue("test"), + Value: types.NewLiteralValue("test", types.TypeText), }, }, OrderBy: types.OrderBy{ @@ -156,19 +167,19 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { name: "Select query with set contains clause", query: `select col_int as name from test_keyspace.test_table where set_text CONTAINS 'test';`, want: &Want{ - TranslatedQuery: "SELECT TO_INT64(`cf1`['col_int']) as name FROM test_table WHERE MAP_CONTAINS_KEY(`set_text`, 'test');", + TranslatedQuery: "SELECT TO_INT64(`cf1`['col_int']) AS name FROM test_table WHERE MAP_CONTAINS_KEY(`set_text`, 'test');", Table: "test_table", Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("col_int", "col_int", "name", types.TypeInt), + types.NewSelectedColumn("col_int", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int")), "name"), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "set_text"), Operator: types.CONTAINS, - Value: types.NewLiteralValue("test"), + Value: types.NewLiteralValue("test", types.TypeText), }, }, OrderBy: types.OrderBy{ @@ -186,15 +197,15 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), - *types.NewSelectedColumnFunction("WRITETIME(col_int)", "col_int", "", types.TypeBigInt, types.FuncCodeWriteTime), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), + NewSelectedColumnFunction("WRITETIME(col_int)", "col_int", "", types.FuncCodeWriteTime, "test_keyspace", "test_table"), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "=", - Value: types.NewLiteralValue("test"), + Value: types.NewLiteralValue("test", types.TypeVarchar), }, }, OrderBy: types.OrderBy{ @@ -212,14 +223,14 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "=", - Value: types.NewParameterizedValue("pk1"), + Value: types.NewParameterizedValue("pk1", types.TypeVarchar), }, }, OrderBy: types.OrderBy{ @@ -244,14 +255,14 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "=", - Value: types.NewParameterizedValue("x"), + Value: types.NewParameterizedValue("x", types.TypeVarchar), }, }, OrderBy: types.OrderBy{ @@ -276,14 +287,14 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), Operator: "IN", - Value: types.NewLiteralValue([]any{int32(1), int32(2), int32(3)}), + Value: types.NewLiteralValue([]any{int32(1), int32(2), int32(3)}, types.NewListType(types.TypeInt)), }, }, AllParams: []*types.ParameterMetadata{}}, @@ -298,14 +309,14 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bigint"), Operator: "IN", - Value: types.NewLiteralValue([]any{int64(1234567890), int64(9876543210)}), + Value: types.NewLiteralValue([]any{int64(1234567890), int64(9876543210)}, types.NewListType(types.TypeBigInt)), }, }, AllParams: []*types.ParameterMetadata{}}, @@ -320,14 +331,14 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_float"), Operator: "IN", - Value: types.NewLiteralValue([]any{float32(1.5), float32(2.5), float32(3.5)}), + Value: types.NewLiteralValue([]any{float32(1.5), float32(2.5), float32(3.5)}, types.NewListType(types.TypeFloat)), }, }, AllParams: []*types.ParameterMetadata{}}, @@ -342,14 +353,14 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_double"), Operator: "IN", - Value: types.NewLiteralValue([]any{3.1415926535, 2.7182818284}), + Value: types.NewLiteralValue([]any{3.1415926535, 2.7182818284}, types.NewListType(types.TypeDouble)), }, }, AllParams: []*types.ParameterMetadata{}}, @@ -364,14 +375,14 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bool"), Operator: "IN", - Value: types.NewLiteralValue([]any{true, false}), + Value: types.NewLiteralValue([]any{true, false}, types.NewListType(types.TypeBoolean)), }, }, AllParams: []*types.ParameterMetadata{}}, @@ -393,7 +404,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, AllParams: []*types.ParameterMetadata{ @@ -408,7 +419,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), Operator: "IN", - Value: types.NewParameterizedValue("value0"), + Value: types.NewParameterizedValue("value0", types.NewListType(types.TypeInt)), }, }, }, @@ -429,7 +440,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, AllParams: []*types.ParameterMetadata{ @@ -444,7 +455,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bigint"), Operator: "IN", - Value: types.NewParameterizedValue("value0"), + Value: types.NewParameterizedValue("value0", types.NewListType(types.TypeBigInt)), }, }, }, @@ -459,7 +470,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, AllParams: []*types.ParameterMetadata{ @@ -474,7 +485,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_float"), Operator: "IN", - Value: types.NewParameterizedValue("value0"), + Value: types.NewParameterizedValue("value0", types.NewListType(types.TypeFloat)), }, }, }, @@ -489,7 +500,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, AllParams: []*types.ParameterMetadata{ @@ -504,7 +515,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_double"), Operator: "IN", - Value: types.NewParameterizedValue("value0"), + Value: types.NewParameterizedValue("value0", types.NewListType(types.TypeDouble)), }, }, }, @@ -519,7 +530,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, AllParams: []*types.ParameterMetadata{ @@ -534,7 +545,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bool"), Operator: "IN", - Value: types.NewParameterizedValue("value0"), + Value: types.NewParameterizedValue("value0", types.NewListType(types.TypeBoolean)), }, }, }, @@ -549,7 +560,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, AllParams: []*types.ParameterMetadata{ @@ -564,7 +575,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), Operator: "IN", - Value: types.NewParameterizedValue("value0"), + Value: types.NewParameterizedValue("value0", types.NewListType(types.TypeBlob)), }, }, }, @@ -586,15 +597,15 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), - *types.NewSelectedColumnFunction("WRITETIME(col_int)", "col_int", "name", types.TypeBigInt, types.FuncCodeWriteTime), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), + NewSelectedColumnFunction("WRITETIME(col_int)", "col_int", "name", types.FuncCodeWriteTime, "test_keyspace", "test_table"), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "=", - Value: types.NewLiteralValue("test"), + Value: types.NewLiteralValue("test", types.TypeVarchar), }, }, OrderBy: types.OrderBy{ @@ -607,19 +618,19 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { name: "As CqlQuery", query: `select col_int as name from test_keyspace.test_table where pk1 = 'test';`, want: &Want{ - TranslatedQuery: "SELECT TO_INT64(`cf1`['col_int']) as name FROM test_table WHERE pk1 = 'test';", + TranslatedQuery: "SELECT TO_INT64(`cf1`['col_int']) AS name FROM test_table WHERE pk1 = 'test';", Table: "test_table", Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("col_int", "col_int", "name", types.TypeInt), + types.NewSelectedColumn("col_int", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int")), "name"), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "=", - Value: types.NewLiteralValue("test"), + Value: types.NewLiteralValue("test", types.TypeVarchar), }, }, OrderBy: types.OrderBy{ @@ -665,47 +676,47 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), - *types.NewSelectedColumn("col_int", "col_int", "", types.TypeInt), - *types.NewSelectedColumn("col_bool", "col_bool", "", types.TypeBoolean), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), + types.NewSelectedColumn("col_int", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int")), ""), + types.NewSelectedColumn("col_bool", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bool")), ""), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "=", - Value: types.NewParameterizedValue("value0"), + Value: types.NewParameterizedValue("value0", types.TypeVarchar), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bool"), Operator: "=", - Value: types.NewParameterizedValue("value1"), + Value: types.NewParameterizedValue("value1", types.TypeBoolean), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_ts"), Operator: "<=", - Value: types.NewParameterizedValue("value2"), + Value: types.NewParameterizedValue("value2", types.TypeTimestamp), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), Operator: ">=", - Value: types.NewParameterizedValue("value3"), + Value: types.NewParameterizedValue("value3", types.TypeInt), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bigint"), Operator: ">", - Value: types.NewParameterizedValue("value4"), + Value: types.NewParameterizedValue("value4", types.TypeBigInt), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bigint"), Operator: "<", - Value: types.NewParameterizedValue("value5"), + Value: types.NewParameterizedValue("value5", types.TypeBigInt), }, }, OrderBy: types.OrderBy{ IsOrderBy: false, }, - LimitValue: types.NewLiteralValue(int32(20000)), + LimitValue: types.NewLiteralValue(int32(20000), types.TypeInt), AllParams: []*types.ParameterMetadata{ { Key: "value0", @@ -756,41 +767,41 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), - *types.NewSelectedColumn("col_int", "col_int", "", types.TypeInt), - *types.NewSelectedColumn("col_bool", "col_bool", "", types.TypeBoolean), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), + types.NewSelectedColumn("col_int", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int")), ""), + types.NewSelectedColumn("col_bool", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bool")), ""), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "=", - Value: types.NewParameterizedValue("value0"), + Value: types.NewParameterizedValue("value0", types.TypeVarchar), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), Operator: "=", - Value: types.NewParameterizedValue("value1"), + Value: types.NewParameterizedValue("value1", types.TypeInt), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bool"), Operator: "=", - Value: types.NewParameterizedValue("value2"), + Value: types.NewParameterizedValue("value2", types.TypeBoolean), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_ts"), Operator: "=", - Value: types.NewParameterizedValue("value3"), + Value: types.NewParameterizedValue("value3", types.TypeTimestamp), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), Operator: "=", - Value: types.NewParameterizedValue("value4"), + Value: types.NewParameterizedValue("value4", types.TypeInt), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bigint"), Operator: "=", - Value: types.NewParameterizedValue("value5"), + Value: types.NewParameterizedValue("value5", types.TypeBigInt), }, }, OrderBy: types.OrderBy{ @@ -846,12 +857,12 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), - *types.NewSelectedColumn("col_int", "col_int", "", types.TypeInt), - *types.NewSelectedColumn("col_bool", "col_bool", "", types.TypeBoolean), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), + types.NewSelectedColumn("col_int", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int")), ""), + types.NewSelectedColumn("col_bool", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bool")), ""), }, }, - LimitValue: types.NewLiteralValue(int32(20000)), + LimitValue: types.NewLiteralValue(int32(20000), types.TypeInt), AllParams: []*types.ParameterMetadata{}, OrderBy: types.OrderBy{ IsOrderBy: true, @@ -895,8 +906,8 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Table: "test_table", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), - *types.NewSelectedColumn("col_int", "col_int", "", types.TypeInt), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), + types.NewSelectedColumn("col_int", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int")), ""), }, }, AllParams: []*types.ParameterMetadata{}, @@ -904,12 +915,12 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "=", - Value: types.NewLiteralValue("test"), + Value: types.NewLiteralValue("test", types.TypeVarchar), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "IN", - Value: types.NewLiteralValue([]any{"abc", "xyz"}), + Value: types.NewLiteralValue([]any{"abc", "xyz"}, types.NewListType(types.TypeVarchar)), }, }, }, @@ -924,8 +935,8 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Table: "test_table", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), - *types.NewSelectedColumn("col_int", "col_int", "", types.TypeInt), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), + types.NewSelectedColumn("col_int", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int")), ""), }, }, AllParams: []*types.ParameterMetadata{ @@ -946,12 +957,12 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "=", - Value: types.NewParameterizedValue("value0"), + Value: types.NewParameterizedValue("value0", types.TypeVarchar), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "IN", - Value: types.NewParameterizedValue("value1"), + Value: types.NewParameterizedValue("value1", types.NewListType(types.TypeVarchar)), }, }, }, @@ -966,8 +977,8 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Table: "test_table", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), - *types.NewSelectedColumn("col_int", "col_int", "", types.TypeInt), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), + types.NewSelectedColumn("col_int", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int")), ""), }, }, AllParams: []*types.ParameterMetadata{}, @@ -975,7 +986,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "LIKE", - Value: types.NewLiteralValue("test%"), + Value: types.NewLiteralValue("test%", types.TypeVarchar), }, }, }, @@ -988,8 +999,8 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Table: "test_table", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), - *types.NewSelectedColumn("col_int", "col_int", "", types.TypeInt), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), + types.NewSelectedColumn("col_int", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int")), ""), }, }, AllParams: []*types.ParameterMetadata{}, @@ -997,8 +1008,8 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "BETWEEN", - Value: types.NewLiteralValue("te'st"), - Value2: types.NewLiteralValue("test2"), + Value: types.NewLiteralValue("te'st", types.TypeVarchar), + Value2: types.NewLiteralValue("test2", types.TypeVarchar), }, }, }, @@ -1018,8 +1029,8 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Table: "test_table", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), - *types.NewSelectedColumn("col_int", "col_int", "", types.TypeInt), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), + types.NewSelectedColumn("col_int", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int")), ""), }, }, AllParams: []*types.ParameterMetadata{ @@ -1034,7 +1045,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "LIKE", - Value: types.NewParameterizedValue("value0"), + Value: types.NewParameterizedValue("value0", types.TypeVarchar), }, }, }, @@ -1048,8 +1059,8 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { Table: "test_table", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), - *types.NewSelectedColumn("col_int", "col_int", "", types.TypeInt), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), + types.NewSelectedColumn("col_int", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int")), ""), }, }, AllParams: []*types.ParameterMetadata{ @@ -1070,8 +1081,8 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "BETWEEN", - Value: types.NewParameterizedValue("value0"), - Value2: types.NewParameterizedValue("value1"), + Value: types.NewParameterizedValue("value0", types.TypeVarchar), + Value2: types.NewParameterizedValue("value1", types.TypeVarchar), }, }, }, @@ -1120,11 +1131,11 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { TranslatedQuery: "SELECT pk1 FROM test_table WHERE pk1 = 'abc';", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, AllParams: []*types.ParameterMetadata{}, - Conditions: []types.Condition{{Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "=", Value: types.NewLiteralValue("abc")}}, + Conditions: []types.Condition{{Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "=", Value: types.NewLiteralValue("abc", types.TypeVarchar)}}, }, sessionKeyspace: "other_keyspace", }, @@ -1137,11 +1148,11 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { TranslatedQuery: "SELECT pk1 FROM test_table WHERE pk1 = 'abc';", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, AllParams: []*types.ParameterMetadata{}, - Conditions: []types.Condition{{Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "=", Value: types.NewLiteralValue("abc")}}, + Conditions: []types.Condition{{Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "=", Value: types.NewLiteralValue("abc", types.TypeVarchar)}}, }, sessionKeyspace: "test_keyspace", }, @@ -1175,7 +1186,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { { name: "CqlQuery with multiple aggregate functions", query: `select pk1, avg(col_int) as avg_col2, max(col_bool) as max_col3, min(col_int) as min_col4 from test_keyspace.test_table GROUP BY pk1;`, - wantErr: "invalid aggregate type: boolean", + wantErr: "parameter 0 doesn't accept type boolean", sessionKeyspace: "test_keyspace", }, { @@ -1187,12 +1198,12 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { TranslatedQuery: "SELECT pk1 FROM test_table LIMIT @value0;", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), }, }, OrderBy: types.OrderBy{}, GroupByColumns: nil, - LimitValue: types.NewParameterizedValue("value0"), + LimitValue: types.NewParameterizedValue("value0", types.TypeInt), AllParams: []*types.ParameterMetadata{ { Key: "value0", @@ -1213,14 +1224,14 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { TranslatedQuery: "SELECT MAP_VALUES(`tags`) FROM user_info WHERE ARRAY_INCLUDES(MAP_VALUES(`tags`), @value0);", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("tags", "tags", "", types.NewListType(types.TypeText)), + types.NewSelectedColumn("tags", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "user_info", "tags")), ""), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "user_info", "tags"), Operator: types.CONTAINS, - Value: types.NewParameterizedValue("value0"), + Value: types.NewParameterizedValue("value0", types.TypeText), }, }, OrderBy: types.OrderBy{}, @@ -1239,7 +1250,7 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { { name: "where clause comparison functions not supported yet", query: `SELECT count(*) FROM test_table WHERE name = ? AND col_ts < ToTimestamp(now());`, - wantErr: "parsing error", + wantErr: "unknown column 'name' in table test_keyspace.test_table", sessionKeyspace: "test_keyspace", }, { @@ -1248,17 +1259,17 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { want: &Want{ Keyspace: "test_keyspace", Table: "test_table", - TranslatedQuery: "SELECT count(*) FROM test_table WHERE TIMESTAMP_FROM_UNIX_MILLIS(TO_INT64(`cf1`['col_ts'])) < TIMESTAMP_FROM_UNIX_MILLIS(1764671400000);", + TranslatedQuery: "SELECT COUNT(*) FROM test_table WHERE TIMESTAMP_FROM_UNIX_MILLIS(TO_INT64(`cf1`['col_ts'])) < TIMESTAMP_FROM_UNIX_MILLIS(1764671400000);", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumnFunction("system.count(*)", "*", "", types.TypeBigInt, types.FuncCodeCount), + NewSelectedColumnFunction("system.count(*)", "*", "", types.FuncCodeCount, "test_keyspace", "test_table"), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_ts"), Operator: types.LT, - Value: types.NewLiteralValue(time.Date(2025, 12, 2, 10, 30, 0, 0, time.UTC)), + Value: types.NewLiteralValue(time.Date(2025, 12, 2, 10, 30, 0, 0, time.UTC), types.TypeTimestamp), }, }, OrderBy: types.OrderBy{}, @@ -1273,17 +1284,17 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { want: &Want{ Keyspace: "test_keyspace", Table: "test_table", - TranslatedQuery: "SELECT count(*) FROM test_table WHERE TIMESTAMP_FROM_UNIX_MILLIS(TO_INT64(`cf1`['col_ts'])) < TIMESTAMP_FROM_UNIX_MILLIS(1764671400000);", + TranslatedQuery: "SELECT COUNT(*) FROM test_table WHERE TIMESTAMP_FROM_UNIX_MILLIS(TO_INT64(`cf1`['col_ts'])) < TIMESTAMP_FROM_UNIX_MILLIS(1764671400000);", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumnFunction("system.count(*)", "*", "", types.TypeBigInt, types.FuncCodeCount), + NewSelectedColumnFunction("system.count(*)", "*", "", types.FuncCodeCount, "test_keyspace", "test_table"), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_ts"), Operator: types.LT, - Value: types.NewLiteralValue(time.Date(2025, 12, 2, 10, 30, 0, 0, time.UTC)), + Value: types.NewLiteralValue(time.Date(2025, 12, 2, 10, 30, 0, 0, time.UTC), types.TypeTimestamp), }, }, OrderBy: types.OrderBy{}, @@ -1301,21 +1312,21 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { TranslatedQuery: "SELECT pk, name, `cf1`['val'] FROM blob_table WHERE pk = FROM_BASE64('OTgyM2ZqYXMsdm0yZg==') AND `cf1`['val'] = FROM_BASE64('cGtqeHo=');", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk", "pk", "", types.TypeBlob), - *types.NewSelectedColumn("name", "name", "", types.TypeVarchar), - *types.NewSelectedColumn("val", "val", "", types.TypeBlob), + types.NewSelectedColumn("pk", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "blob_table", "pk")), ""), + types.NewSelectedColumn("name", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "blob_table", "name")), ""), + types.NewSelectedColumn("val", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "blob_table", "val")), ""), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "blob_table", "pk"), Operator: types.EQ, - Value: types.NewLiteralValue([]byte{0x39, 0x38, 0x32, 0x33, 0x66, 0x6a, 0x61, 0x73, 0x2c, 0x76, 0x6d, 0x32, 0x66}), + Value: types.NewLiteralValue([]byte{0x39, 0x38, 0x32, 0x33, 0x66, 0x6a, 0x61, 0x73, 0x2c, 0x76, 0x6d, 0x32, 0x66}, types.TypeBlob), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "blob_table", "val"), Operator: types.EQ, - Value: types.NewLiteralValue([]byte{0x70, 0x6b, 0x6a, 0x78, 0x7a}), + Value: types.NewLiteralValue([]byte{0x70, 0x6b, 0x6a, 0x78, 0x7a}, types.TypeBlob), }, }, OrderBy: types.OrderBy{}, @@ -1333,24 +1344,24 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { TranslatedQuery: "SELECT `cf1`['col_ascii'] FROM test_table WHERE pk1 = 'foo' AND pk2 = 'bar' AND `cf1`['col_ascii'] = 'fizz';", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("col_ascii", "col_ascii", "", types.TypeAscii), + types.NewSelectedColumn("col_ascii", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_ascii")), ""), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: types.EQ, - Value: types.NewLiteralValue("foo"), + Value: types.NewLiteralValue("foo", types.TypeVarchar), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk2"), Operator: types.EQ, - Value: types.NewLiteralValue("bar"), + Value: types.NewLiteralValue("bar", types.TypeVarchar), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_ascii"), Operator: types.EQ, - Value: types.NewLiteralValue("fizz"), + Value: types.NewLiteralValue("fizz", types.TypeAscii), }, }, OrderBy: types.OrderBy{}, @@ -1374,21 +1385,21 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { TranslatedQuery: "SELECT pk, name, `cf1`['val'] FROM blob_table WHERE pk <= FROM_BASE64('Ag==') AND name = 'blob-comparison-operators';", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk", "pk", "", types.TypeBlob), - *types.NewSelectedColumn("name", "name", "", types.TypeVarchar), - *types.NewSelectedColumn("val", "val", "", types.TypeBlob), + types.NewSelectedColumn("pk", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "blob_table", "pk")), ""), + types.NewSelectedColumn("name", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "blob_table", "name")), ""), + types.NewSelectedColumn("val", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "blob_table", "val")), ""), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "blob_table", "pk"), Operator: types.LTE, - Value: types.NewLiteralValue([]byte{0x02}), + Value: types.NewLiteralValue([]byte{0x02}, types.TypeBlob), }, { Column: mockdata.GetColumnOrDie("test_keyspace", "blob_table", "name"), Operator: types.EQ, - Value: types.NewLiteralValue("blob-comparison-operators"), + Value: types.NewLiteralValue("blob-comparison-operators", types.TypeVarchar), }, }, OrderBy: types.OrderBy{}, @@ -1401,20 +1412,20 @@ func TestTranslator_TranslateSelectQuerytoBigtable(t *testing.T) { name: "Valid GROUP BY with aggregate and ORDER BY", query: `select pk1, count(col_int) from test_keyspace.test_table where pk1 = 'test' GROUP BY pk1 ORDER BY pk1;`, want: &Want{ - TranslatedQuery: "SELECT pk1, count(TO_INT64(`cf1`['col_int'])) FROM test_table WHERE pk1 = 'test' GROUP BY pk1 ORDER BY pk1 asc;", + TranslatedQuery: "SELECT pk1, COUNT(TO_INT64(`cf1`['col_int'])) FROM test_table WHERE pk1 = 'test' GROUP BY pk1 ORDER BY pk1 asc;", Table: "test_table", Keyspace: "test_keyspace", SelectClause: &types.SelectClause{ Columns: []types.SelectedColumn{ - *types.NewSelectedColumn("pk1", "pk1", "", types.TypeVarchar), - *types.NewSelectedColumnFunction("system.count(col_int)", "col_int", "", types.TypeBigInt, types.FuncCodeCount), + types.NewSelectedColumn("pk1", types.NewColumnValue(mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1")), ""), + NewSelectedColumnFunction("system.count(col_int)", "col_int", "", types.FuncCodeCount, "test_keyspace", "test_table"), }, }, Conditions: []types.Condition{ { Column: mockdata.GetColumnOrDie("test_keyspace", "test_table", "pk1"), Operator: "=", - Value: types.NewLiteralValue("test"), + Value: types.NewLiteralValue("test", types.TypeVarchar), }, }, AllParams: []*types.ParameterMetadata{}, diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/utils.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/utils.go index 355c5492..62ee00b1 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/utils.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/select_translator/utils.go @@ -17,7 +17,7 @@ import ( // - input: The Select Element context from the antlr Parser. // // Returns: Columns Meta and an error if any. -func parseSelectClause(input cql.ISelectElementsContext, table *sm.TableSchema) (*types.SelectClause, error) { +func parseSelectClause(input cql.ISelectElementsContext, table *sm.TableSchema, params *types.QueryParameterBuilder) (*types.SelectClause, error) { if input == nil { return nil, errors.New("select clause empty") } @@ -40,7 +40,7 @@ func parseSelectClause(input cql.ISelectElementsContext, table *sm.TableSchema) } var selected types.SelectedColumn if val.SelectFunction() != nil { - selected, err = common.ParseSelectFunction(val.SelectFunction(), alias, table) + selected, err = common.ParseSelectFunction(val.SelectFunction(), alias, table, params) } else if val.SelectColumn() != nil { selected, err = common.ParseSelectColumn(val.SelectColumn(), alias, table) } else if val.SelectIndex() != nil { @@ -51,7 +51,7 @@ func parseSelectClause(input cql.ISelectElementsContext, table *sm.TableSchema) if err != nil { return nil, err } - if selected.ResultType == nil { + if selected.GetType() == nil { return nil, fmt.Errorf("unhandled result type") } selectedColumns = append(selectedColumns, selected) @@ -149,7 +149,7 @@ func selectedColumnsToMetadata(table *sm.TableSchema, selectClause *types.Select } var resultColumns []*message.ColumnMetadata for i, c := range selectClause.Columns { - name := c.Sql + name := c.Cql if c.Alias != "" { name = c.Alias } @@ -158,7 +158,7 @@ func selectedColumnsToMetadata(table *sm.TableSchema, selectClause *types.Select Table: string(table.Name), Name: name, Index: int32(i), - Type: c.ResultType.DataType(), + Type: c.GetType().DataType(), } resultColumns = append(resultColumns, &col) } diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/update_translator/translator_update_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/update_translator/translator_update_test.go index ba2f33a6..08c85122 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/update_translator/translator_update_test.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/update_translator/translator_update_test.go @@ -52,11 +52,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Table: "test_table", IfExists: false, Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewLiteralValue([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03})), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewLiteralValue([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, types.TypeBlob)), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -69,11 +69,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Table: "test_table", IfExists: true, Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewLiteralValue([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03})), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewLiteralValue([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, types.TypeBlob)), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -106,11 +106,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { }, }, Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewParameterizedValue("value0")), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewParameterizedValue("value0", types.TypeBlob)), }, RowKeys: []types.DynamicValue{ - types.NewParameterizedValue("value1"), - types.NewParameterizedValue("value2"), + types.NewParameterizedValue("value1", types.TypeVarchar), + types.NewParameterizedValue("value2", types.TypeVarchar), }, }, }, @@ -142,11 +142,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { }, }, Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewParameterizedValue("v1")), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewParameterizedValue("v1", types.TypeBlob)), }, RowKeys: []types.DynamicValue{ - types.NewParameterizedValue("v2"), - types.NewParameterizedValue("v3"), + types.NewParameterizedValue("v2", types.TypeVarchar), + types.NewParameterizedValue("v3", types.TypeVarchar), }, }, }, @@ -178,11 +178,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { }, }, Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewParameterizedValue("value0")), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewParameterizedValue("value0", types.TypeBlob)), }, RowKeys: []types.DynamicValue{ - types.NewParameterizedValue("value2"), - types.NewParameterizedValue("value1"), + types.NewParameterizedValue("value2", types.TypeVarchar), + types.NewParameterizedValue("value1", types.TypeVarchar), }, }, }, @@ -194,11 +194,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Table: "test_table", IfExists: false, Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bool"), types.NewLiteralValue(true)), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bool"), types.NewLiteralValue(true, types.TypeBoolean)), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -210,11 +210,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_ts"), types.NewLiteralValue(time.Date(2024, 8, 12, 12, 34, 56, 0, time.UTC))), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_ts"), types.NewLiteralValue(time.Date(2024, 8, 12, 12, 34, 56, 0, time.UTC), types.TypeTimestamp)), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -226,11 +226,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), types.NewLiteralValue(int32(123))), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_int"), types.NewLiteralValue(int32(123), types.TypeInt)), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -242,11 +242,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "set_text"), types.NewLiteralValue([]types.GoValue{"item1", "item2"})), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "set_text"), types.NewLiteralValue([]types.GoValue{"item1", "item2"}, types.NewSetType(types.TypeText))), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -258,11 +258,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "map_text_bool"), types.NewLiteralValue(map[types.GoValue]types.GoValue{"key1": true, "key2": false})), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "map_text_bool"), types.NewLiteralValue(map[types.GoValue]types.GoValue{"key1": true, "key2": false}, types.NewMapType(types.TypeText, types.TypeBoolean))), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -274,11 +274,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bigint"), types.NewLiteralValue(int64(1234567890))), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_bigint"), types.NewLiteralValue(int64(1234567890), types.TypeBigInt)), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -290,11 +290,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewLiteralValue([]byte{0x01})), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewLiteralValue([]byte{0x01}, types.TypeBlob)), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("abc"), - types.NewLiteralValue("pkval"), + types.NewLiteralValue("abc", types.TypeVarchar), + types.NewLiteralValue("pkval", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -306,11 +306,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewComplexAssignmentAppend(mockdata.GetColumnOrDie("test_keyspace", "test_table", "set_text"), types.PLUS, types.NewLiteralValue([]types.GoValue{"item3"}), false), + types.NewComplexAssignmentAppend(mockdata.GetColumnOrDie("test_keyspace", "test_table", "set_text"), types.PLUS, types.NewLiteralValue([]types.GoValue{"item3"}, types.NewSetType(types.TypeText)), false), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -322,11 +322,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewComplexAssignmentAppend(mockdata.GetColumnOrDie("test_keyspace", "test_table", "set_text"), types.MINUS, types.NewLiteralValue([]types.GoValue{"item2"}), false), + types.NewComplexAssignmentAppend(mockdata.GetColumnOrDie("test_keyspace", "test_table", "set_text"), types.MINUS, types.NewLiteralValue([]types.GoValue{"item2"}, types.NewSetType(types.TypeText)), false), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -338,11 +338,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewAssignmentCounterIncrement(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_counter"), types.PLUS, types.NewLiteralValue(int64(1))), + types.NewAssignmentCounterIncrement(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_counter"), types.PLUS, types.NewLiteralValue(int64(1), types.TypeCounter)), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -359,11 +359,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewAssignmentCounterIncrement(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_counter"), types.MINUS, types.NewLiteralValue(int64(9))), + types.NewAssignmentCounterIncrement(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_counter"), types.MINUS, types.NewLiteralValue(int64(9), types.TypeCounter)), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -375,11 +375,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewAssignmentCounterIncrement(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_counter"), types.PLUS, types.NewLiteralValue(int64(-9))), + types.NewAssignmentCounterIncrement(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_counter"), types.PLUS, types.NewLiteralValue(int64(-9), types.TypeCounter)), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -391,11 +391,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewLiteralValue([]byte{0x01})), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewLiteralValue([]byte{0x01}, types.TypeBlob)), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("abc"), - types.NewLiteralValue("pkval"), + types.NewLiteralValue("abc", types.TypeVarchar), + types.NewLiteralValue("pkval", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -412,11 +412,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "set_text"), types.NewLiteralValue([]types.GoValue{"item1", "item2"})), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "set_text"), types.NewLiteralValue([]types.GoValue{"item1", "item2"}, types.NewSetType(types.TypeText))), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -428,11 +428,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "map_text_bool"), types.NewLiteralValue(map[types.GoValue]types.GoValue{"key1": true, "key2": false})), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "map_text_bool"), types.NewLiteralValue(map[types.GoValue]types.GoValue{"key1": true, "key2": false}, types.NewMapType(types.TypeText, types.TypeBoolean))), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -444,11 +444,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "set_text"), types.NewLiteralValue([]types.GoValue{"item1", "item2"})), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "set_text"), types.NewLiteralValue([]types.GoValue{"item1", "item2"}, types.NewSetType(types.TypeText))), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("testText"), - types.NewLiteralValue("pk2"), + types.NewLiteralValue("testText", types.TypeVarchar), + types.NewLiteralValue("pk2", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, @@ -477,11 +477,11 @@ func TestTranslator_TranslateUpdateQuerytoBigtable(t *testing.T) { Keyspace: "test_keyspace", Table: "test_table", Values: []types.Assignment{ - types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewLiteralValue([]byte{0x01})), + types.NewComplexAssignmentSet(mockdata.GetColumnOrDie("test_keyspace", "test_table", "col_blob"), types.NewLiteralValue([]byte{0x01}, types.TypeBlob)), }, RowKeys: []types.DynamicValue{ - types.NewLiteralValue("abc"), - types.NewLiteralValue("pkval"), + types.NewLiteralValue("abc", types.TypeVarchar), + types.NewLiteralValue("pkval", types.TypeVarchar), }, AllParams: []*types.ParameterMetadata{}, }, diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/update_translator/utils.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/update_translator/utils.go index ce59854a..d21a937b 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/update_translator/utils.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/translators/update_translator/utils.go @@ -22,7 +22,7 @@ func parseUpdateValues(assignments []cql.IAssignmentElementContext, tableConfig if err != nil { return nil, err } - value, err := common.ParseValueAny(assignment.ValueAny(), col.CQLType, params, col) + value, err := common.ParseValueAny(assignment.ValueAny(), tableConfig, col.CQLType, types.QueryClauseValues, params, col) if err != nil { return nil, err } @@ -108,7 +108,7 @@ func ParseAppend(columnContext cql.IColumnContext, op cql.IArithmeticOperatorCon return nil, fmt.Errorf("cannot append on column type: %s", col.CQLType.String()) } - value, err := common.ParseValueAny(valueAny, valueType, params, col) + value, err := common.ParseValueAny(valueAny, tableConfig, valueType, types.QueryClauseValues, params, col) if err != nil { return nil, err } diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/utilities/utils.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/utilities/utils.go index 45a28711..665e6d26 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/utilities/utils.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/utilities/utils.go @@ -20,7 +20,6 @@ import ( "encoding/base64" "encoding/hex" "fmt" - "reflect" "sort" "strconv" "strings" @@ -32,6 +31,7 @@ import ( "github.com/antlr4-go/antlr/v4" "github.com/datastax/go-cassandra-native-protocol/datatype" "github.com/datastax/go-cassandra-native-protocol/primitive" + "github.com/google/uuid" ) // from https://cassandra.apache.org/doc/4.0/cassandra/cql/appendices.html#appendix-A @@ -248,7 +248,7 @@ func IsSupportedPrimaryKeyType(dt types.CqlDataType) bool { } switch dt.DataType() { - case datatype.Int, datatype.Bigint, datatype.Varchar, datatype.Timestamp, datatype.Blob, datatype.Ascii: + case datatype.Int, datatype.Bigint, datatype.Varchar, datatype.Timestamp, datatype.Blob, datatype.Ascii, datatype.Uuid, datatype.Timeuuid: return true default: return false @@ -263,7 +263,7 @@ func ParseBigInt(value string) (int64, error) { return val, err } -func GoToString(value types.GoValue) (string, error) { +func GoToQueryString(value types.GoValue) (string, error) { if value == nil { return "null", nil } @@ -288,6 +288,12 @@ func GoToString(value types.GoValue) (string, error) { } case time.Time: return fmt.Sprintf("TIMESTAMP_FROM_UNIX_MILLIS(%d)", v.UnixMilli()), nil + case uuid.UUID: + encoded := base64.StdEncoding.EncodeToString(v[:]) + return fmt.Sprintf("FROM_BASE64('%s')", encoded), nil + case primitive.UUID: + encoded := base64.StdEncoding.EncodeToString(v[:]) + return fmt.Sprintf("FROM_BASE64('%s')", encoded), nil case []uint8: encoded := base64.StdEncoding.EncodeToString(v) // note: Bigtable limits SQL strings to 1,024k characters while Cassandra has no official limit. We only encode blobs to base64 when a literal is used. Placeholders will not have this issue. @@ -295,7 +301,7 @@ func GoToString(value types.GoValue) (string, error) { case []interface{}: var values []string for _, vi := range v { - s, err := GoToString(vi) + s, err := GoToQueryString(vi) if err != nil { return "", err } @@ -345,6 +351,18 @@ func StringToGo(value string, cqlType types.CqlDataType) (types.GoValue, error) return nil, fmt.Errorf("error converting string to timestamp: %w", err) } return val, nil + case datatype.Uuid: + u, err := uuid.Parse(value) + if err != nil { + return nil, err + } + return primitive.UUID(u), nil + case datatype.Timeuuid: + u, err := uuid.Parse(value) + if err != nil { + return nil, err + } + return primitive.UUID(u), nil case datatype.Blob: // remove the '0x' prefix that CQL requires for blob literals if strings.HasPrefix(value, "0x") || strings.HasPrefix(value, "0X") { @@ -444,7 +462,7 @@ func parseCqlTimestamp(timestampStr string) (time.Time, error) { func isSupportedCollectionElementType(dt datatype.DataType) bool { switch dt { - case datatype.Int, datatype.Bigint, datatype.Varchar, datatype.Float, datatype.Double, datatype.Timestamp, datatype.Boolean, datatype.Ascii: + case datatype.Int, datatype.Bigint, datatype.Varchar, datatype.Float, datatype.Double, datatype.Timestamp, datatype.Boolean, datatype.Ascii, datatype.Uuid, datatype.Timeuuid: return true default: return false @@ -457,7 +475,7 @@ func IsSupportedColumnType(dt types.CqlDataType) bool { } switch dt.DataType().GetDataTypeCode() { - case primitive.DataTypeCodeInt, primitive.DataTypeCodeBigint, primitive.DataTypeCodeBlob, primitive.DataTypeCodeBoolean, primitive.DataTypeCodeDouble, primitive.DataTypeCodeFloat, primitive.DataTypeCodeTimestamp, primitive.DataTypeCodeText, primitive.DataTypeCodeVarchar, primitive.DataTypeCodeCounter, primitive.DataTypeCodeAscii: + case primitive.DataTypeCodeInt, primitive.DataTypeCodeBigint, primitive.DataTypeCodeBlob, primitive.DataTypeCodeBoolean, primitive.DataTypeCodeDouble, primitive.DataTypeCodeFloat, primitive.DataTypeCodeTimestamp, primitive.DataTypeCodeText, primitive.DataTypeCodeVarchar, primitive.DataTypeCodeCounter, primitive.DataTypeCodeAscii, primitive.DataTypeCodeUuid, primitive.DataTypeCodeTimeuuid: return true case primitive.DataTypeCodeMap: mapType := dt.DataType().(datatype.MapType) @@ -680,7 +698,7 @@ func ParseCqlType(dtc cql.IDataTypeContext) (types.CqlDataType, error) { } return types.TypeTinyint, nil default: - return nil, fmt.Errorf("unknown data type name: '%s' in type '%s'", dataTypeName, dtc) + return nil, fmt.Errorf("unknown data type name: '%s'", dataTypeName) } } @@ -709,103 +727,3 @@ func validateDataTypeDefinition(dt cql.IDataTypeContext, expectedTypeCount int) } return nil } - -func GetValueInt32(value types.DynamicValue, values *types.QueryParameterValues) (int32, error) { - v, err := value.GetValue(values) - if err != nil { - return 0, err - } - intVal, ok := v.(int32) - if !ok { - return 0, fmt.Errorf("query value is a %T, not an int32", v) - } - return intVal, nil -} - -func GetValueInt64(value types.DynamicValue, values *types.QueryParameterValues) (int64, error) { - v, err := value.GetValue(values) - if err != nil { - return 0, err - } - intVal, ok := v.(int64) - if !ok { - return 0, fmt.Errorf("query value is a %T, not an int64", v) - } - return intVal, nil -} - -func GetValueSlice(value types.DynamicValue, values *types.QueryParameterValues) ([]types.GoValue, error) { - v, err := value.GetValue(values) - if err != nil { - return nil, err - } - - if v == nil { - return nil, nil - } - - val := reflect.ValueOf(v) - - if val.Kind() != reflect.Slice { - return nil, fmt.Errorf("query value is a %T, not a slice", v) - } - - length := val.Len() - result := make([]types.GoValue, length) - - for i := 0; i < length; i++ { - anyVal := val.Index(i).Interface() - if anyVal == nil { - // don't allow collections to contain null elements to be consistent with Cassandra - return nil, fmt.Errorf("collection items are not allowed to be null") - } - result[i] = anyVal - } - - return result, nil -} - -func GetValueMap(value types.DynamicValue, values *types.QueryParameterValues) (map[types.GoValue]types.GoValue, error) { - v, err := value.GetValue(values) - if err != nil { - return nil, err - } - - if v == nil { - return nil, nil - } - - val := reflect.ValueOf(v) - - if val.Kind() != reflect.Map { - return nil, fmt.Errorf("value is a %T, not a map", v) - } - - result := make(map[types.GoValue]types.GoValue, val.Len()) - - // 3. Iterate over the keys of the original map - iter := val.MapRange() - for iter.Next() { - // Get the reflection Parameter for the key and the value - keyVal := iter.Key() - valueVal := iter.Value() - - // 4. Use .Interface() to convert the concrete key/value to an any (interface{}) - keyAny := keyVal.Interface() - valueAny := valueVal.Interface() - - if keyAny == nil { - // don't allow collections to contain null elements to be consistent with Cassandra - return nil, fmt.Errorf("map keys cannot be null") - } - - if valueAny == nil { - // don't allow collections to contain null elements to be consistent with Cassandra - return nil, fmt.Errorf("map values cannot be null") - } - - // 5. Add to the new map[any]any - result[keyAny] = valueAny - } - return result, nil -} diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/utilities/utils_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/utilities/utils_test.go index 5044bdca..df47d4a0 100644 --- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/utilities/utils_test.go +++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/utilities/utils_test.go @@ -178,8 +178,9 @@ func TestIsSupportedCollectionElementType(t *testing.T) { {"Supported CQLType - Double", datatype.Double, true}, {"Supported CQLType - Timestamp", datatype.Timestamp, true}, {"Supported CQLType - Boolean", datatype.Boolean, true}, + {"Supported CQLType - UUID", datatype.Uuid, true}, + {"Supported CQLType - TimeUUID", datatype.Timeuuid, true}, {"Unsupported CQLType - Blob", datatype.Blob, false}, - {"Unsupported CQLType - UUID", datatype.Uuid, false}, {"Unsupported CQLType - Map", datatype.NewMapType(datatype.Varchar, datatype.Int), false}, {"Unsupported CQLType - Set", datatype.NewSetType(datatype.Varchar), false}, } @@ -207,6 +208,8 @@ func TestIsSupportedColumnType(t *testing.T) { {"Supported Primitive - Float", ParseCqlTypeOrDie("float"), true}, {"Supported Primitive - Timestamp", ParseCqlTypeOrDie("timestamp"), true}, {"Supported Primitive - Varchar", ParseCqlTypeOrDie("varchar"), true}, + {"Supported Primitive - UUID", ParseCqlTypeOrDie("uuid"), true}, + {"Supported Primitive - TimeUUID", ParseCqlTypeOrDie("timeuuid"), true}, // --- Positive Cases: Collection Types --- {"Supported List", ParseCqlTypeOrDie("list"), true}, @@ -215,15 +218,13 @@ func TestIsSupportedColumnType(t *testing.T) { {"Supported Map with Text Key", ParseCqlTypeOrDie("map"), true}, // --- Negative Cases: Primitive Types --- - {"Unsupported Primitive - UUID", ParseCqlTypeOrDie("uuid"), false}, - {"Unsupported Primitive - TimeUUID", ParseCqlTypeOrDie("timeuuid"), false}, // --- Negative Cases: Collection Types --- - {"Unsupported List Element", ParseCqlTypeOrDie("list"), false}, + {"Unsupported List Element", ParseCqlTypeOrDie("list"), false}, {"Unsupported List Element", types.NewListType(types.NewListType(types.TypeInt)), false}, {"Unsupported Set Element", ParseCqlTypeOrDie("set"), false}, {"Unsupported Map Key", ParseCqlTypeOrDie("map"), false}, - {"Unsupported Map Value", ParseCqlTypeOrDie("map"), false}, + {"Unsupported Map Value", ParseCqlTypeOrDie("map"), false}, {"Nested Collection - List of Maps", types.NewListType(types.NewMapType(types.TypeVarchar, types.TypeInt)), false}, // --- Negative Cases: Frozen Types --- {"Frozen List", ParseCqlTypeOrDie("frozen>"), false}, diff --git a/kafka-connect-bigtable-sink/doc/tests.md b/kafka-connect-bigtable-sink/doc/tests.md index 631d4c90..9820665c 100644 --- a/kafka-connect-bigtable-sink/doc/tests.md +++ b/kafka-connect-bigtable-sink/doc/tests.md @@ -43,8 +43,6 @@ Create a service account and grant it Bigtable Administrator (`roles/bigtable.ad Download its key. ##### Configure the permissions for integration tests - - If you want to use Application Default Credentials, configure the machine appropriately (on a workstation, log in with `gcloud` into an account with Bigtable Administrator permissions to the instance created in one of the previous steps). Otherwise, you need to use service account's permissions. @@ -59,12 +57,6 @@ Alternatively, you could point it to [the service account key created before](#o ${user.home}/.config/gcloud/application_default_credentials.json ``` - -- Replace the following TODO values with you GCP project ID and Cloud Bigtable instance ID in `BaseIT#baseConnectorProps()` function: -```java -result.put(GCP_PROJECT_ID_CONFIG, "todotodo"); -result.put(BIGTABLE_INSTANCE_ID_CONFIG, "todotodo"); -``` #### Emulator Start the emulator using `gcloud` directly: @@ -93,7 +85,6 @@ docker compose up -d Ensure that the sink's [pom.xml](../integration-tests/pom.xml) contains the following section in Failsafe's `` section: ```xml - target/test-classes/fake_service_key.json localhost:8086 ``` @@ -111,11 +102,11 @@ cbt -project "$PROJECT" -instance "$INSTANCE" ls | xargs -P 0 -I {} cbt -project ### Command to run the integration tests ```bash -mvn clean verify -DskipUnitTests +mvn -Pintegration-tests clean verify ``` #### To run a specific integration test ```bash -mvn clean verify -DskipUnitTests -Dit.test=InsertUpsertIT#testUpsert +mvn -Pintegration-tests clean verify -Dit.test=InsertUpsertIT#testUpsert ``` diff --git a/kafka-connect-bigtable-sink/integration-tests/pom.xml b/kafka-connect-bigtable-sink/integration-tests/pom.xml index 2acc4ef6..9c1565b0 100644 --- a/kafka-connect-bigtable-sink/integration-tests/pom.xml +++ b/kafka-connect-bigtable-sink/integration-tests/pom.xml @@ -33,8 +33,8 @@ 17 17 ${project.basedir}/integration_test_plugins - ${project.basedir}/../sink/target/ - ${integration.test.plugin.path}/google-sink + ${project.basedir}/../sink/target/sink-${project.version}.jar + ${integration.test.plugin.path}/google-sink @@ -227,10 +227,8 @@ - - - - + + diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseDataGeneratorIT.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseDataGeneratorIT.java index 3042a098..728540c5 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseDataGeneratorIT.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseDataGeneratorIT.java @@ -30,7 +30,6 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.LongStream; - import org.apache.kafka.connect.data.Date; import org.apache.kafka.connect.data.Decimal; import org.apache.kafka.connect.data.Schema; diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseIT.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseIT.java index 9889923a..f424da65 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseIT.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseIT.java @@ -26,11 +26,9 @@ import com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig; import com.google.cloud.kafka.connect.bigtable.util.TestId; import com.google.cloud.kafka.connect.bigtable.wrappers.BigtableTableAdminClientInterface; - import java.util.HashMap; import java.util.Map; import java.util.Objects; - import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.connect.runtime.ConnectorConfig; import org.apache.kafka.connect.storage.StringConverter; @@ -63,11 +61,17 @@ public Map baseConnectorProps() { + ProducerConfig.BUFFER_MEMORY_CONFIG, String.valueOf(maxKafkaMessageSizeBytes)); - result.put(GCP_PROJECT_ID_CONFIG, Objects.requireNonNull(System.getenv(GCP_PROJECT_ID))); - result.put(BIGTABLE_INSTANCE_ID_CONFIG, Objects.requireNonNull(System.getenv(BIGTABLE_INSTANCE_ID))); - result.put( - BigtableSinkConfig.GCP_CREDENTIALS_PATH_CONFIG, - Objects.requireNonNull(System.getenv(CREDENTIALS_PATH_ENV_VAR))); + if (System.getenv().containsKey("BIGTABLE_EMULATOR_HOST")) { + result.put(GCP_PROJECT_ID_CONFIG, "EMULATOR"); + result.put(BIGTABLE_INSTANCE_ID_CONFIG, "EMULATOR"); + } else { + result.put(GCP_PROJECT_ID_CONFIG, Objects.requireNonNull(System.getenv(GCP_PROJECT_ID))); + result.put( + BIGTABLE_INSTANCE_ID_CONFIG, Objects.requireNonNull(System.getenv(BIGTABLE_INSTANCE_ID))); + result.put( + BigtableSinkConfig.GCP_CREDENTIALS_PATH_CONFIG, + Objects.requireNonNull(System.getenv(CREDENTIALS_PATH_ENV_VAR))); + } return result; } diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseKafkaConnectBigtableIT.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseKafkaConnectBigtableIT.java index 3966d4be..34ffe4b4 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseKafkaConnectBigtableIT.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseKafkaConnectBigtableIT.java @@ -15,6 +15,8 @@ */ package com.google.cloud.kafka.connect.bigtable.integration; +import static org.apache.kafka.test.TestUtils.waitForCondition; + import com.google.api.gax.rpc.FailedPreconditionException; import com.google.api.gax.rpc.NotFoundException; import com.google.cloud.bigtable.admin.v2.models.ColumnFamily; @@ -27,12 +29,6 @@ import com.google.cloud.bigtable.data.v2.models.TableId; import com.google.cloud.kafka.connect.bigtable.wrappers.BigtableTableAdminClientInterface; import com.google.protobuf.ByteString; -import org.apache.kafka.test.TestCondition; -import org.junit.After; -import org.junit.Before; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.Collection; @@ -43,8 +39,11 @@ import java.util.concurrent.Future; import java.util.function.Supplier; import java.util.stream.Collectors; - -import static org.apache.kafka.test.TestUtils.waitForCondition; +import org.apache.kafka.test.TestCondition; +import org.junit.After; +import org.junit.Before; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public abstract class BaseKafkaConnectBigtableIT extends BaseKafkaConnectIT { @@ -109,7 +108,9 @@ public Map readAllRows(BigtableDataClient bigtable, String tabl public String[] readAllRowKeys(BigtableDataClient bigtable, String table) { Query query = Query.create(table); - return bigtable.readRows(query).stream().map(r -> r.getKey().toString(StandardCharsets.UTF_8)).toArray(String[]::new); + return bigtable.readRows(query).stream() + .map(r -> r.getKey().toString(StandardCharsets.UTF_8)) + .toArray(String[]::new); } public long cellCount(Map rows) { @@ -176,8 +177,7 @@ public void waitUntilBigtableTableHasExactSetOfColumnFamilies( waitForCondition( testConditionIgnoringTransientErrors( () -> - bigtableAdmin.getTable(tableId).getColumnFamilies() - .stream() + bigtableAdmin.getTable(tableId).getColumnFamilies().stream() .map(ColumnFamily::getId) .collect(Collectors.toSet()) .equals(columnFamilies)), @@ -195,4 +195,4 @@ private TestCondition testConditionIgnoringTransientErrors(Supplier sup } }; } -} \ No newline at end of file +} diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseKafkaConnectIT.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseKafkaConnectIT.java index 94532ff0..9472c334 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseKafkaConnectIT.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BaseKafkaConnectIT.java @@ -37,7 +37,6 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - import org.apache.commons.lang.StringUtils; import org.apache.kafka.clients.admin.Admin; import org.apache.kafka.clients.consumer.ConsumerConfig; @@ -192,6 +191,15 @@ public void sendRecords( Collection> keysAndValues, Converter keyConverter, Converter valueConverter) { + sendRecords(topic, keysAndValues, keyConverter, valueConverter, null); + } + + public void sendRecords( + String topic, + Collection> keysAndValues, + Converter keyConverter, + Converter valueConverter, + Long timestamp) { try (KafkaProducer producer = getKafkaProducer()) { List> produceFutures = new ArrayList<>(); for (Map.Entry keyAndValue : keysAndValues) { @@ -201,7 +209,7 @@ public void sendRecords( byte[] serializedValue = valueConverter.fromConnectData(topic, value.schema(), value.value()); ProducerRecord msg = - new ProducerRecord<>(topic, serializedKey, serializedValue); + new ProducerRecord<>(topic, null, timestamp, serializedKey, serializedValue); Future produceFuture = producer.send(msg); produceFutures.add(produceFuture); } @@ -283,8 +291,8 @@ public void assertSingleDlqEntry( h -> h.key().equals(DeadLetterQueueReporter.ERROR_HEADER_EXCEPTION) && Arrays.equals( - h.value(), - exceptionClass.getName().getBytes(StandardCharsets.UTF_8)))); + h.value(), + exceptionClass.getName().getBytes(StandardCharsets.UTF_8)))); } } } diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BigtableClientIT.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BigtableClientIT.java index bc3390a5..b679210e 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BigtableClientIT.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/BigtableClientIT.java @@ -21,9 +21,7 @@ import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest; import com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig; import com.google.cloud.kafka.connect.bigtable.wrappers.BigtableTableAdminClientInterface; - import java.util.Map; - import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ConfigIT.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ConfigIT.java index 202a53f3..98725624 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ConfigIT.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ConfigIT.java @@ -16,7 +16,6 @@ package com.google.cloud.kafka.connect.bigtable.integration; import java.util.Map; - import org.apache.kafka.connect.runtime.SinkConnectorConfig; import org.apache.kafka.connect.runtime.rest.errors.ConnectRestException; import org.junit.Test; diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/DifferentConvertersIT.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/DifferentConvertersIT.java index 17ea53e9..d4a38373 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/DifferentConvertersIT.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/DifferentConvertersIT.java @@ -19,14 +19,12 @@ import io.confluent.connect.json.JsonSchemaConverter; import io.confluent.connect.protobuf.ProtobufConverter; import io.confluent.kafka.serializers.AbstractKafkaSchemaSerDeConfig; - import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.function.Supplier; - import org.apache.kafka.connect.json.JsonConverter; import org.apache.kafka.connect.json.JsonConverterConfig; import org.apache.kafka.connect.runtime.ConnectorConfig; @@ -44,20 +42,20 @@ public class DifferentConvertersIT extends BaseDataGeneratorIT { @Parameterized.Parameters public static Collection testCases() { return Arrays.asList( - new Object[][]{ - {(Supplier) AvroConverter::new, Map.of(), true}, - {(Supplier) ProtobufConverter::new, Map.of(), true}, - {(Supplier) JsonSchemaConverter::new, Map.of(), true}, - { - (Supplier) JsonConverter::new, - Map.of(JsonConverterConfig.SCHEMAS_ENABLE_CONFIG, String.valueOf(false)), - false - }, - { - (Supplier) JsonConverter::new, - Map.of(JsonConverterConfig.SCHEMAS_ENABLE_CONFIG, String.valueOf(true)), - false - }, + new Object[][] { + {(Supplier) AvroConverter::new, Map.of(), true}, + {(Supplier) ProtobufConverter::new, Map.of(), true}, + {(Supplier) JsonSchemaConverter::new, Map.of(), true}, + { + (Supplier) JsonConverter::new, + Map.of(JsonConverterConfig.SCHEMAS_ENABLE_CONFIG, String.valueOf(false)), + false + }, + { + (Supplier) JsonConverter::new, + Map.of(JsonConverterConfig.SCHEMAS_ENABLE_CONFIG, String.valueOf(true)), + false + }, }); } diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ErrorHandlingIT.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ErrorHandlingIT.java index bbef6049..3a89a112 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ErrorHandlingIT.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ErrorHandlingIT.java @@ -25,9 +25,8 @@ import com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig; import com.google.cloud.kafka.connect.bigtable.config.InsertMode; import com.google.cloud.kafka.connect.bigtable.config.NullValueMode; -import com.google.protobuf.ByteString; import com.google.cloud.kafka.connect.bigtable.util.JsonConverterFactory; - +import com.google.protobuf.ByteString; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.AbstractMap; @@ -38,7 +37,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; import java.util.function.Function; - import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecords; diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ErrorReportingIT.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ErrorReportingIT.java index 30395012..86abedc0 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ErrorReportingIT.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ErrorReportingIT.java @@ -17,9 +17,7 @@ import com.google.cloud.kafka.connect.bigtable.config.BigtableErrorMode; import com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig; - import java.util.Map; - import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/FlattenArrayElementIT.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/FlattenArrayElementIT.java index 2304c275..c290a907 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/FlattenArrayElementIT.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/FlattenArrayElementIT.java @@ -1,5 +1,26 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.google.cloud.kafka.connect.bigtable.integration; +import static com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig.*; +import static org.apache.kafka.connect.runtime.WorkerConfig.KEY_CONVERTER_CLASS_CONFIG; +import static org.apache.kafka.connect.runtime.WorkerConfig.VALUE_CONVERTER_CLASS_CONFIG; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; @@ -9,6 +30,9 @@ import com.google.cloud.kafka.connect.bigtable.config.InsertMode; import com.google.cloud.kafka.connect.bigtable.transformations.FlattenArrayElement; import com.google.protobuf.ByteString; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.ExecutionException; import org.apache.kafka.connect.data.Schema; import org.apache.kafka.connect.data.SchemaBuilder; import org.apache.kafka.connect.data.Struct; @@ -18,30 +42,23 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.ExecutionException; - -import static com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig.*; -import static org.apache.kafka.connect.runtime.WorkerConfig.KEY_CONVERTER_CLASS_CONFIG; -import static org.apache.kafka.connect.runtime.WorkerConfig.VALUE_CONVERTER_CLASS_CONFIG; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - @RunWith(JUnit4.class) - public class FlattenArrayElementIT extends BaseKafkaConnectBigtableIT { private static final String KEY1 = "key1"; @Test - public void testFlattenArrayElementSmt() throws InterruptedException, ExecutionException, JsonProcessingException { + public void testFlattenArrayElementSmt() + throws InterruptedException, ExecutionException, JsonProcessingException { Map props = baseConnectorProps(); props.put(INSERT_MODE_CONFIG, InsertMode.UPSERT.name()); props.put("transforms", "flattenElements"); props.put("transforms.flattenElements.type", FlattenArrayElement.class.getName()); props.put("transforms.flattenElements." + FlattenArrayElement.ARRAY_FIELD_NAME, "products"); - props.put("transforms.flattenElements." + FlattenArrayElement.ARRAY_INNER_WRAPPER_FIELD_NAME, "list"); - props.put("transforms.flattenElements." + FlattenArrayElement.ARRAY_ELEMENT_WRAPPER_FIELD_NAME, "element"); + props.put( + "transforms.flattenElements." + FlattenArrayElement.ARRAY_INNER_WRAPPER_FIELD_NAME, "list"); + props.put( + "transforms.flattenElements." + FlattenArrayElement.ARRAY_ELEMENT_WRAPPER_FIELD_NAME, + "element"); props.put(DEFAULT_COLUMN_FAMILY_CONFIG, "cf"); props.put(ERROR_MODE_CONFIG, BigtableErrorMode.FAIL.name()); props.put(KEY_CONVERTER_CLASS_CONFIG, StringConverter.class.getName()); @@ -50,51 +67,63 @@ public void testFlattenArrayElementSmt() throws InterruptedException, ExecutionE String testId = startSingleTopicConnector(props); createTablesAndColumnFamilies(Map.of(testId, Set.of(testId, "cf", "products"))); - Schema productSchema = SchemaBuilder.struct() - .field("name", Schema.STRING_SCHEMA) - .field("id", Schema.STRING_SCHEMA) - .field("quantity", Schema.INT32_SCHEMA) - .build(); + Schema productSchema = + SchemaBuilder.struct() + .field("name", Schema.STRING_SCHEMA) + .field("id", Schema.STRING_SCHEMA) + .field("quantity", Schema.INT32_SCHEMA) + .build(); Schema elementSchema = SchemaBuilder.struct().field("element", productSchema).build(); - Schema schema = SchemaBuilder.struct().optional() - .field("orderId", Schema.STRING_SCHEMA) - .field("userId", Schema.STRING_SCHEMA) - .field("products", - SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema)).build() - ) - .build(); + Schema schema = + SchemaBuilder.struct() + .optional() + .field("orderId", Schema.STRING_SCHEMA) + .field("userId", Schema.STRING_SCHEMA) + .field( + "products", + SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema)).build()) + .build(); JsonConverter converter = new JsonConverter(); converter.configure(Collections.singletonMap("schemas.enable", "true"), false); - Struct productElement1 = new Struct(elementSchema).put("element", new Struct(productSchema) - .put("name", "Ball") - .put("id", "PROD-123") - .put("quantity", 5) - ); - Struct productElement2 = new Struct(elementSchema).put("element", new Struct(productSchema) - .put("name", "Car") - .put("id", "PROD-456") - .put("quantity", 1) - ); - Struct productElement3 = new Struct(elementSchema).put("element", new Struct(productSchema) - .put("name", "Tambourine") - .put("id", "PROD-789") - .put("quantity", 2) - ); - - List productList = Arrays.stream(new Struct[]{productElement1, productElement2, productElement3}).toList(); - - Struct productsWrapper = new Struct(schema.field("products").schema()) - .put("list", productList); - - Struct value = new Struct(schema) - .put("orderId", "ORD-999") - .put("userId", "USER-42") - .put("products", productsWrapper); - + Struct productElement1 = + new Struct(elementSchema) + .put( + "element", + new Struct(productSchema) + .put("name", "Ball") + .put("id", "PROD-123") + .put("quantity", 5)); + Struct productElement2 = + new Struct(elementSchema) + .put( + "element", + new Struct(productSchema) + .put("name", "Car") + .put("id", "PROD-456") + .put("quantity", 1)); + Struct productElement3 = + new Struct(elementSchema) + .put( + "element", + new Struct(productSchema) + .put("name", "Tambourine") + .put("id", "PROD-789") + .put("quantity", 2)); + + List productList = + Arrays.stream(new Struct[] {productElement1, productElement2, productElement3}).toList(); + + Struct productsWrapper = new Struct(schema.field("products").schema()).put("list", productList); + + Struct value = + new Struct(schema) + .put("orderId", "ORD-999") + .put("userId", "USER-42") + .put("products", productsWrapper); byte[] schemaAsJson = converter.fromConnectData(testId, schema, value); diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/InsertUpsertIT.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/InsertModeIT.java similarity index 55% rename from kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/InsertUpsertIT.java rename to kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/InsertModeIT.java index 5998ab54..b69615f5 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/InsertUpsertIT.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/InsertModeIT.java @@ -15,43 +15,53 @@ */ package com.google.cloud.kafka.connect.bigtable.integration; +import static com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig.*; +import static org.apache.kafka.connect.runtime.WorkerConfig.KEY_CONVERTER_CLASS_CONFIG; +import static org.apache.kafka.connect.runtime.WorkerConfig.VALUE_CONVERTER_CLASS_CONFIG; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.cloud.bigtable.data.v2.models.Row; import com.google.cloud.bigtable.data.v2.models.RowCell; import com.google.cloud.kafka.connect.bigtable.config.BigtableErrorMode; +import com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig; import com.google.cloud.kafka.connect.bigtable.config.InsertMode; import com.google.cloud.kafka.connect.bigtable.config.NullValueMode; -import com.google.cloud.kafka.connect.bigtable.mapping.ByteUtils; import com.google.cloud.kafka.connect.bigtable.transformations.ApplyJsonSchema; import com.google.cloud.kafka.connect.bigtable.transformations.FlattenArrayElement; +import com.google.cloud.kafka.connect.bigtable.util.JsonConverterFactory; import com.google.cloud.kafka.connect.bigtable.util.TestDataUtil; +import com.google.cloud.kafka.connect.bigtable.utils.ByteUtils; import com.google.protobuf.ByteString; -import org.apache.kafka.connect.errors.DataException; -import org.apache.kafka.connect.json.JsonConverter; -import org.apache.kafka.connect.storage.StringConverter; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.time.Instant; +import java.util.AbstractMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; - -import static com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig.*; -import static org.apache.kafka.connect.runtime.WorkerConfig.KEY_CONVERTER_CLASS_CONFIG; -import static org.apache.kafka.connect.runtime.WorkerConfig.VALUE_CONVERTER_CLASS_CONFIG; -import static org.junit.Assert.*; +import org.apache.kafka.connect.data.Schema; +import org.apache.kafka.connect.data.SchemaAndValue; +import org.apache.kafka.connect.data.SchemaBuilder; +import org.apache.kafka.connect.data.Struct; +import org.apache.kafka.connect.errors.DataException; +import org.apache.kafka.connect.json.JsonConverter; +import org.apache.kafka.connect.runtime.ConnectorConfig; +import org.apache.kafka.connect.storage.Converter; +import org.apache.kafka.connect.storage.StringConverter; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; @RunWith(JUnit4.class) -public class InsertUpsertIT extends BaseKafkaConnectBigtableIT { +public class InsertModeIT extends BaseKafkaConnectBigtableIT { private static final ObjectMapper objectMapper = new ObjectMapper(); private String readResource(String path) { @@ -67,10 +77,13 @@ private String readResource(String path) { private static final String KEY1 = "key1"; private static final String KEY2 = "key2"; + private static final String KEY3 = "key3"; private static final ByteString KEY1_BYTES = ByteString.copyFrom(KEY1.getBytes(StandardCharsets.UTF_8)); private static final ByteString KEY2_BYTES = ByteString.copyFrom(KEY2.getBytes(StandardCharsets.UTF_8)); + private static final ByteString KEY3_BYTES = + ByteString.copyFrom(KEY3.getBytes(StandardCharsets.UTF_8)); private static final String VALUE1 = "value1"; private static final String VALUE2 = "value2"; private static final String VALUE3 = "value3"; @@ -174,7 +187,8 @@ public void testUpsertWithRowKeyFromValue() throws InterruptedException, Executi } @Test - public void testUpsertWithRowKeyFromValueNoSchema() throws InterruptedException, ExecutionException, JsonProcessingException { + public void testUpsertWithRowKeyFromValueNoSchema() + throws InterruptedException, ExecutionException, JsonProcessingException { Map props = baseConnectorProps(); props.put(INSERT_MODE_CONFIG, InsertMode.UPSERT.name()); props.put(ROW_KEY_DEFINITION_CONFIG, "orderId,product"); @@ -202,11 +216,13 @@ public void testUpsertWithRowKeyFromValueNoSchema() throws InterruptedException, List cells = row1.getCells("cf", "KAFKA_VALUE"); assertEquals(1, cells.size()); - assertEquals(parseJson(json), parseJson(cells.get(0).getValue().toString(StandardCharsets.UTF_8))); + assertEquals( + parseJson(json), parseJson(cells.get(0).getValue().toString(StandardCharsets.UTF_8))); } @Test - public void testUpsertWithRowKeyFromValueMissingField() throws InterruptedException, ExecutionException { + public void testUpsertWithRowKeyFromValueMissingField() + throws InterruptedException, ExecutionException { String dlqTopic = createDlq(); Map props = baseConnectorProps(); props.put(INSERT_MODE_CONFIG, InsertMode.UPSERT.name()); @@ -229,7 +245,8 @@ public void testUpsertWithRowKeyFromValueMissingField() throws InterruptedExcept } @Test - public void testUpsertWithRowKeyFromValueNullValue() throws InterruptedException, ExecutionException { + public void testUpsertWithRowKeyFromValueNullValue() + throws InterruptedException, ExecutionException { String dlqTopic = createDlq(); Map props = baseConnectorProps(); props.put(INSERT_MODE_CONFIG, InsertMode.UPSERT.name()); @@ -253,7 +270,8 @@ public void testUpsertWithRowKeyFromValueNullValue() throws InterruptedException } @Test - public void testUpsertAppliedSchema() throws InterruptedException, ExecutionException, JsonProcessingException { + public void testUpsertAppliedSchema() + throws InterruptedException, ExecutionException, JsonProcessingException { Map props = baseConnectorProps(); props.put(INSERT_MODE_CONFIG, InsertMode.UPSERT.name()); props.put(ROW_KEY_DEFINITION_CONFIG, "userId,orderId"); @@ -265,8 +283,11 @@ public void testUpsertAppliedSchema() throws InterruptedException, ExecutionExce props.put("transforms.createKey.fields", "userId,orderId"); props.put("transforms.flattenElements.type", FlattenArrayElement.class.getName()); props.put("transforms.flattenElements." + FlattenArrayElement.ARRAY_FIELD_NAME, "products"); - props.put("transforms.flattenElements." + FlattenArrayElement.ARRAY_INNER_WRAPPER_FIELD_NAME, "list"); - props.put("transforms.flattenElements." + FlattenArrayElement.ARRAY_ELEMENT_WRAPPER_FIELD_NAME, "element"); + props.put( + "transforms.flattenElements." + FlattenArrayElement.ARRAY_INNER_WRAPPER_FIELD_NAME, "list"); + props.put( + "transforms.flattenElements." + FlattenArrayElement.ARRAY_ELEMENT_WRAPPER_FIELD_NAME, + "element"); props.put(EXPAND_ROOT_LEVEL_ARRAYS, "true"); props.put(ROW_KEY_DELIMITER_CONFIG, "#"); props.put(DEFAULT_COLUMN_FAMILY_CONFIG, "cf"); @@ -290,15 +311,18 @@ public void testUpsertAppliedSchema() throws InterruptedException, ExecutionExce assertEquals("ORD-999", orderResult.orderId()); assertEquals("USER-42", orderResult.userId()); - assertArrayEquals(new TestDataUtil.OrderProduct[]{ - new TestDataUtil.OrderProduct("Ball", "PROD-123", 5), - new TestDataUtil.OrderProduct("Car", "PROD-456", 1), - new TestDataUtil.OrderProduct("Tambourine", "PROD-789", 2) - }, orderResult.products()); + assertArrayEquals( + new TestDataUtil.OrderProduct[] { + new TestDataUtil.OrderProduct("Ball", "PROD-123", 5), + new TestDataUtil.OrderProduct("Car", "PROD-456", 1), + new TestDataUtil.OrderProduct("Tambourine", "PROD-789", 2) + }, + orderResult.products()); } @Test - public void testUpsertWithRowKeyWithRootLevelArrayExpanded() throws InterruptedException, ExecutionException, JsonProcessingException { + public void testUpsertWithRowKeyWithRootLevelArrayExpanded() + throws InterruptedException, ExecutionException, JsonProcessingException { Map props = baseConnectorProps(); props.put(INSERT_MODE_CONFIG, InsertMode.UPSERT.name()); props.put(ROW_KEY_DEFINITION_CONFIG, "userId,orderId"); @@ -308,8 +332,11 @@ public void testUpsertWithRowKeyWithRootLevelArrayExpanded() throws InterruptedE props.put("transforms.createKey.fields", "userId,orderId"); props.put("transforms.flattenElements.type", FlattenArrayElement.class.getName()); props.put("transforms.flattenElements." + FlattenArrayElement.ARRAY_FIELD_NAME, "products"); - props.put("transforms.flattenElements." + FlattenArrayElement.ARRAY_INNER_WRAPPER_FIELD_NAME, "list"); - props.put("transforms.flattenElements." + FlattenArrayElement.ARRAY_ELEMENT_WRAPPER_FIELD_NAME, "element"); + props.put( + "transforms.flattenElements." + FlattenArrayElement.ARRAY_INNER_WRAPPER_FIELD_NAME, "list"); + props.put( + "transforms.flattenElements." + FlattenArrayElement.ARRAY_ELEMENT_WRAPPER_FIELD_NAME, + "element"); props.put(EXPAND_ROOT_LEVEL_ARRAYS, "true"); props.put(DEFAULT_COLUMN_FAMILY_CONFIG, "cf"); @@ -320,16 +347,20 @@ public void testUpsertWithRowKeyWithRootLevelArrayExpanded() throws InterruptedE String testId = startSingleTopicConnector(props); createTablesAndColumnFamilies(Map.of(testId, Set.of("cf", "products"))); - TestDataUtil.Order order1 = new TestDataUtil.Order("ORD-999", "USER-42", new TestDataUtil.OrderProduct[]{ - new TestDataUtil.OrderProduct("Ball", "PROD-123", 5), - new TestDataUtil.OrderProduct("Car", "PROD-456", 1), - new TestDataUtil.OrderProduct("Tambourine", "PROD-789", 2) - }); + TestDataUtil.Order order1 = + new TestDataUtil.Order( + "ORD-999", + "USER-42", + new TestDataUtil.OrderProduct[] { + new TestDataUtil.OrderProduct("Ball", "PROD-123", 5), + new TestDataUtil.OrderProduct("Car", "PROD-456", 1), + new TestDataUtil.OrderProduct("Tambourine", "PROD-789", 2) + }); TestDataUtil.writeOrder(connect, testId, KEY1, order1); waitUntilBigtableContainsNumberOfRows(testId, 1); - assertArrayEquals(new String[]{"USER-42#ORD-999"}, readAllRowKeys(bigtableData, testId)); + assertArrayEquals(new String[] {"USER-42#ORD-999"}, readAllRowKeys(bigtableData, testId)); Map rows = readAllRows(bigtableData, testId); ByteString key = ByteString.copyFrom("USER-42#ORD-999".getBytes(StandardCharsets.UTF_8)); Row row1 = rows.get(key); @@ -341,17 +372,22 @@ public void testUpsertWithRowKeyWithRootLevelArrayExpanded() throws InterruptedE assertEquals(order1.userId(), orderResult.userId()); assertArrayEquals(order1.products(), orderResult.products()); - // overwrite the first order with a smaller products collection to ensure the existing array is deleted - TestDataUtil.Order order2 = new TestDataUtil.Order(order1.orderId(), order1.userId(), new TestDataUtil.OrderProduct[]{ - new TestDataUtil.OrderProduct("Drum", "PROD-ABC", 1), - new TestDataUtil.OrderProduct("Balloons", "PROD-DEF", 5), - }); + // overwrite the first order with a smaller products collection to ensure the existing array is + // deleted + TestDataUtil.Order order2 = + new TestDataUtil.Order( + order1.orderId(), + order1.userId(), + new TestDataUtil.OrderProduct[] { + new TestDataUtil.OrderProduct("Drum", "PROD-ABC", 1), + new TestDataUtil.OrderProduct("Balloons", "PROD-DEF", 5), + }); Instant writeTime2 = Instant.now(); TestDataUtil.writeOrder(connect, testId, KEY1, order2); waitUntilBigtableWriteTimeLaterThan(testId, writeTime2); - assertArrayEquals(new String[]{"USER-42#ORD-999"}, readAllRowKeys(bigtableData, testId)); + assertArrayEquals(new String[] {"USER-42#ORD-999"}, readAllRowKeys(bigtableData, testId)); Map rows2 = readAllRows(bigtableData, testId); Row row2 = rows2.get(key); assertNotNull(row2); @@ -364,9 +400,9 @@ public void testUpsertWithRowKeyWithRootLevelArrayExpanded() throws InterruptedE assertArrayEquals(order2.products(), orderResult2.products()); } - @Test - public void testRootLevelArrayExpandedWriteNull() throws InterruptedException, ExecutionException, JsonProcessingException { + public void testRootLevelArrayExpandedWriteNull() + throws InterruptedException, ExecutionException, JsonProcessingException { Map props = baseConnectorProps(); props.put(INSERT_MODE_CONFIG, InsertMode.UPSERT.name()); props.put(ROW_KEY_DEFINITION_CONFIG, "userId,orderId"); @@ -376,8 +412,11 @@ public void testRootLevelArrayExpandedWriteNull() throws InterruptedException, E props.put("transforms.createKey.fields", "userId,orderId"); props.put("transforms.flattenElements.type", FlattenArrayElement.class.getName()); props.put("transforms.flattenElements." + FlattenArrayElement.ARRAY_FIELD_NAME, "products"); - props.put("transforms.flattenElements." + FlattenArrayElement.ARRAY_INNER_WRAPPER_FIELD_NAME, "list"); - props.put("transforms.flattenElements." + FlattenArrayElement.ARRAY_ELEMENT_WRAPPER_FIELD_NAME, "element"); + props.put( + "transforms.flattenElements." + FlattenArrayElement.ARRAY_INNER_WRAPPER_FIELD_NAME, "list"); + props.put( + "transforms.flattenElements." + FlattenArrayElement.ARRAY_ELEMENT_WRAPPER_FIELD_NAME, + "element"); props.put(EXPAND_ROOT_LEVEL_ARRAYS, "true"); props.put(VALUE_NULL_MODE_CONFIG, NullValueMode.WRITE.name()); @@ -394,7 +433,7 @@ public void testRootLevelArrayExpandedWriteNull() throws InterruptedException, E TestDataUtil.writeOrder(connect, testId, KEY1, order1); waitUntilBigtableContainsNumberOfRows(testId, 1); - assertArrayEquals(new String[]{"USER-42#ORD-999"}, readAllRowKeys(bigtableData, testId)); + assertArrayEquals(new String[] {"USER-42#ORD-999"}, readAllRowKeys(bigtableData, testId)); Map rows = readAllRows(bigtableData, testId); ByteString key = ByteString.copyFrom("USER-42#ORD-999".getBytes(StandardCharsets.UTF_8)); Row row1 = rows.get(key); @@ -407,6 +446,237 @@ public void testRootLevelArrayExpandedWriteNull() throws InterruptedException, E assertArrayEquals(new TestDataUtil.OrderProduct[0], orderResult.products()); } + @Test + public void testReplaceIfNewestWrites() throws InterruptedException, ExecutionException { + Converter keyConverter = new StringConverter(); + Converter valueConverter = JsonConverterFactory.create(true, false); + + Map props = baseConnectorProps(); + props.put(ConnectorConfig.VALUE_CONVERTER_CLASS_CONFIG, valueConverter.getClass().getName()); + props.put(BigtableSinkConfig.INSERT_MODE_CONFIG, InsertMode.REPLACE_IF_NEWEST.name()); + // Let's ignore `null`s to ensure that we observe `InsertMode.REPLACE_IF_NEWEST`'s behavior + // rather than `NullValueMode.DELETE`'s. + props.put(BigtableSinkConfig.VALUE_NULL_MODE_CONFIG, NullValueMode.IGNORE.name()); + + String testId = startSingleTopicConnector(props); + createTablesAndColumnFamilies(testId); + + String field1 = "f1"; + String field2 = "f2"; + + Schema schema1 = SchemaBuilder.struct().field(field1, Schema.STRING_SCHEMA).build(); + Schema schema2 = SchemaBuilder.struct().field(field2, Schema.STRING_SCHEMA).build(); + + Struct value1 = new Struct(schema1).put(field1, VALUE1); + Struct value2 = new Struct(schema2).put(field2, VALUE2); + + SchemaAndValue schemaAndValue1 = new SchemaAndValue(value1.schema(), value1); + SchemaAndValue schemaAndValue2 = new SchemaAndValue(value2.schema(), value2); + + SchemaAndValue schemaAndKey1 = new SchemaAndValue(Schema.STRING_SCHEMA, KEY1); + SchemaAndValue schemaAndKey2 = new SchemaAndValue(Schema.STRING_SCHEMA, KEY2); + SchemaAndValue schemaAndKey3 = new SchemaAndValue(Schema.STRING_SCHEMA, KEY3); + + long preexistingRowsTimestamp = 10000L; + + // Set initial values of the preexisting rows. + sendRecords( + testId, + List.of( + new AbstractMap.SimpleImmutableEntry<>(schemaAndKey1, schemaAndValue1), + new AbstractMap.SimpleImmutableEntry<>(schemaAndKey2, schemaAndValue1)), + keyConverter, + valueConverter, + preexistingRowsTimestamp); + waitUntilBigtableContainsNumberOfRows(testId, 2); + + // Successfully try to replace a record using the same timestamp. + sendRecords( + testId, + List.of(new AbstractMap.SimpleImmutableEntry<>(schemaAndKey1, schemaAndValue2)), + keyConverter, + valueConverter, + preexistingRowsTimestamp); + // Unsuccessfully try to replace a record using an earlier timestamp. + sendRecords( + testId, + List.of(new AbstractMap.SimpleImmutableEntry<>(schemaAndKey2, schemaAndValue2)), + keyConverter, + valueConverter, + preexistingRowsTimestamp - 1L); + // Test writing to a row that didn't exist before using the lowest possible timestamp. + sendRecords( + testId, + List.of(new AbstractMap.SimpleImmutableEntry<>(schemaAndKey3, schemaAndValue1)), + keyConverter, + valueConverter, + 0L); + waitUntilBigtableContainsNumberOfRows(testId, 3); + assertConnectorAndAllTasksAreRunning(testId); + + Map rows = readAllRows(bigtableData, testId); + Row row1 = rows.get(KEY1_BYTES); + Row row2 = rows.get(KEY2_BYTES); + Row row3 = rows.get(KEY3_BYTES); + assertEquals(1, row1.getCells().size()); + assertEquals(VALUE2_BYTES, row1.getCells().get(0).getValue()); + assertEquals(ByteString.copyFromUtf8(field2), row1.getCells().get(0).getQualifier()); + assertEquals(1, row2.getCells().size()); + assertEquals(VALUE1_BYTES, row2.getCells().get(0).getValue()); + assertEquals(ByteString.copyFromUtf8(field1), row2.getCells().get(0).getQualifier()); + assertEquals(1, row3.getCells().size()); + assertEquals(VALUE1_BYTES, row3.getCells().get(0).getValue()); + assertEquals(ByteString.copyFromUtf8(field1), row3.getCells().get(0).getQualifier()); + } + + @Test + public void testReplaceIfNewestDeletes() throws InterruptedException, ExecutionException { + Converter keyConverter = new StringConverter(); + Converter valueConverter = new StringConverter(); + + Map props = baseConnectorProps(); + props.put(ConnectorConfig.VALUE_CONVERTER_CLASS_CONFIG, valueConverter.getClass().getName()); + props.put(BigtableSinkConfig.INSERT_MODE_CONFIG, InsertMode.REPLACE_IF_NEWEST.name()); + // `REPLACE_IF_NEWEST` mode empties the row before setting the new cells irregardless of + // configured NullValueMode. + props.put(BigtableSinkConfig.VALUE_NULL_MODE_CONFIG, NullValueMode.IGNORE.name()); + + String testId = startSingleTopicConnector(props); + createTablesAndColumnFamilies(testId); + + SchemaAndValue writeSchemaAndValue = new SchemaAndValue(Schema.STRING_SCHEMA, VALUE1); + SchemaAndValue deleteSchemaAndValue = new SchemaAndValue(Schema.OPTIONAL_STRING_SCHEMA, null); + + SchemaAndValue schemaAndKey1 = new SchemaAndValue(Schema.STRING_SCHEMA, KEY1); + SchemaAndValue schemaAndKey2 = new SchemaAndValue(Schema.STRING_SCHEMA, KEY2); + SchemaAndValue schemaAndKey3 = new SchemaAndValue(Schema.STRING_SCHEMA, KEY3); + + long preexistingRowsTimestamp = 10000L; + + // Set initial values of the preexisting rows. + sendRecords( + testId, + List.of( + new AbstractMap.SimpleImmutableEntry<>(schemaAndKey1, writeSchemaAndValue), + new AbstractMap.SimpleImmutableEntry<>(schemaAndKey2, writeSchemaAndValue)), + keyConverter, + valueConverter, + preexistingRowsTimestamp); + waitUntilBigtableContainsNumberOfRows(testId, 2); + + // Test deleting a row that didn't exist before. + sendRecords( + testId, + List.of(new AbstractMap.SimpleImmutableEntry<>(schemaAndKey3, deleteSchemaAndValue)), + keyConverter, + valueConverter, + preexistingRowsTimestamp); + // Unsuccessfully try to delete a row using an earlier timestamp. + sendRecords( + testId, + List.of(new AbstractMap.SimpleImmutableEntry<>(schemaAndKey2, deleteSchemaAndValue)), + keyConverter, + valueConverter, + preexistingRowsTimestamp - 1L); + // Successfully try to delete a row using the same timestamp. + sendRecords( + testId, + List.of(new AbstractMap.SimpleImmutableEntry<>(schemaAndKey1, deleteSchemaAndValue)), + keyConverter, + valueConverter, + preexistingRowsTimestamp); + waitUntilBigtableContainsNumberOfRows(testId, 1); + assertConnectorAndAllTasksAreRunning(testId); + + Map rows = readAllRows(bigtableData, testId); + Row row2 = rows.get(KEY2_BYTES); + assertEquals(1, row2.getCells().size()); + assertEquals(VALUE1_BYTES, row2.getCells().get(0).getValue()); + } + + // This test ensures that deletion of row caused by REPLACE_IF_NEWEST works well when combined + // with DELETE null handling mode. + @Test + public void testReplaceIfNewestDeletesWorkWithNullDeletes() + throws InterruptedException, ExecutionException { + Converter keyConverter = new StringConverter(); + Converter valueConverter = JsonConverterFactory.create(true, false); + + Map props = baseConnectorProps(); + props.put(ConnectorConfig.VALUE_CONVERTER_CLASS_CONFIG, valueConverter.getClass().getName()); + props.put(BigtableSinkConfig.INSERT_MODE_CONFIG, InsertMode.REPLACE_IF_NEWEST.name()); + props.put(BigtableSinkConfig.VALUE_NULL_MODE_CONFIG, NullValueMode.DELETE.name()); + + String testId = startSingleTopicConnector(props); + createTablesAndColumnFamilies(testId); + + SchemaAndValue writeSchemaAndValue = new SchemaAndValue(Schema.STRING_SCHEMA, VALUE1); + + SchemaAndValue deleteSchemaAndValue1 = new SchemaAndValue(Schema.OPTIONAL_STRING_SCHEMA, null); + + Schema schema2 = + SchemaBuilder.struct().optional().field(testId, Schema.OPTIONAL_STRING_SCHEMA).build(); + SchemaAndValue deleteSchemaAndValue2 = + new SchemaAndValue(schema2, new Struct(schema2).put(testId, null)); + + Schema innerSchema3 = + SchemaBuilder.struct() + .optional() + .field("KAFKA_CONNECT", Schema.OPTIONAL_STRING_SCHEMA) + .build(); + Schema schema3 = SchemaBuilder.struct().optional().field(testId, innerSchema3).build(); + SchemaAndValue deleteSchemaAndValue3 = + new SchemaAndValue( + schema3, + new Struct(schema3).put(testId, new Struct(innerSchema3).put("KAFKA_CONNECT", null))); + + SchemaAndValue schemaAndKey1 = new SchemaAndValue(Schema.STRING_SCHEMA, KEY1); + SchemaAndValue schemaAndKey2 = new SchemaAndValue(Schema.STRING_SCHEMA, KEY2); + SchemaAndValue schemaAndKey3 = new SchemaAndValue(Schema.STRING_SCHEMA, KEY3); + SchemaAndValue nonexistentSchemaAndKey = + new SchemaAndValue(Schema.STRING_SCHEMA, "nonexistent"); + + long lowestPossibleTimestamp = 0L; + long deleteTimestamp = 10000L; + + // Set initial values of the preexisting rows. + sendRecords( + testId, + List.of( + new AbstractMap.SimpleImmutableEntry<>(schemaAndKey1, writeSchemaAndValue), + new AbstractMap.SimpleImmutableEntry<>(schemaAndKey2, writeSchemaAndValue), + new AbstractMap.SimpleImmutableEntry<>(schemaAndKey3, writeSchemaAndValue)), + keyConverter, + valueConverter, + lowestPossibleTimestamp); + waitUntilBigtableContainsNumberOfRows(testId, 3); + + // Test that no kind of delete breaks on a nonexistent row. + sendRecords( + testId, + List.of( + new AbstractMap.SimpleImmutableEntry<>(nonexistentSchemaAndKey, deleteSchemaAndValue1), + new AbstractMap.SimpleImmutableEntry<>(nonexistentSchemaAndKey, deleteSchemaAndValue2), + new AbstractMap.SimpleImmutableEntry<>(nonexistentSchemaAndKey, deleteSchemaAndValue3)), + keyConverter, + valueConverter, + deleteTimestamp); + + // Test that all kinds of delete work on existing rows. + sendRecords( + testId, + List.of( + new AbstractMap.SimpleImmutableEntry<>(schemaAndKey1, deleteSchemaAndValue1), + new AbstractMap.SimpleImmutableEntry<>(schemaAndKey2, deleteSchemaAndValue2), + new AbstractMap.SimpleImmutableEntry<>(schemaAndKey3, deleteSchemaAndValue3)), + keyConverter, + valueConverter, + deleteTimestamp); + + waitUntilBigtableContainsNumberOfRows(testId, 0); + assertConnectorAndAllTasksAreRunning(testId); + } + public JsonNode parseJson(String json) throws JsonProcessingException { return objectMapper.readTree(json); } diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/MultipleConnectorTasksIT.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/MultipleConnectorTasksIT.java index 2487ee1e..3598ca7f 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/MultipleConnectorTasksIT.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/MultipleConnectorTasksIT.java @@ -21,11 +21,9 @@ import com.google.cloud.kafka.connect.bigtable.config.InsertMode; import io.confluent.connect.avro.AvroConverter; import io.confluent.kafka.serializers.AbstractKafkaSchemaSerDeConfig; - import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; - import org.apache.kafka.connect.runtime.ConnectorConfig; import org.apache.kafka.connect.storage.Converter; import org.junit.Test; diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/NullHandlingIT.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/NullHandlingIT.java index 36aeac9d..30d30570 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/NullHandlingIT.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/NullHandlingIT.java @@ -15,8 +15,6 @@ */ package com.google.cloud.kafka.connect.bigtable.integration; -import com.google.cloud.kafka.connect.bigtable.util.NestedNullStructFactory; - import static com.google.cloud.kafka.connect.bigtable.util.NestedNullStructFactory.NESTED_NULL_STRUCT_FIELD_NAME; import static com.google.cloud.kafka.connect.bigtable.util.NestedNullStructFactory.NESTED_NULL_STRUCT_FIELD_NAME_BYTES; import static com.google.cloud.kafka.connect.bigtable.util.NestedNullStructFactory.getStructWithNullOnNthNestingLevel; @@ -30,7 +28,6 @@ import com.google.cloud.kafka.connect.bigtable.config.InsertMode; import com.google.cloud.kafka.connect.bigtable.config.NullValueMode; import com.google.protobuf.ByteString; - import java.nio.charset.StandardCharsets; import java.util.AbstractMap; import java.util.ArrayList; @@ -40,7 +37,6 @@ import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; - import org.apache.kafka.connect.data.Schema; import org.apache.kafka.connect.data.SchemaAndValue; import org.apache.kafka.connect.data.SchemaBuilder; @@ -242,9 +238,9 @@ public void testDeleteMode() throws InterruptedException, ExecutionException { SchemaBuilder.struct().field(deletedColumn.getValue(), Schema.OPTIONAL_INT8_SCHEMA); Struct deleteColumn = new Struct( - SchemaBuilder.struct() - .field(deletedColumn.getKey(), innerDeleteColumnSchema) - .build()) + SchemaBuilder.struct() + .field(deletedColumn.getKey(), innerDeleteColumnSchema) + .build()) .put( deletedColumn.getKey(), new Struct(innerDeleteColumnSchema).put(deletedColumn.getValue(), null)); @@ -326,9 +322,9 @@ public void testDeleteMode() throws InterruptedException, ExecutionException { c -> !(c.getFamily().equals(deletedColumn.getKey()) && c.getQualifier() - .equals( - ByteString.copyFrom( - deletedColumn.getValue().getBytes(StandardCharsets.UTF_8))))) + .equals( + ByteString.copyFrom( + deletedColumn.getValue().getBytes(StandardCharsets.UTF_8))))) .collect(Collectors.toSet()), new HashSet<>(rowDeletedColumn.getCells())); } diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ResourceAutoCreationIT.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ResourceAutoCreationIT.java index 16dfe224..98bf2e50 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ResourceAutoCreationIT.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/ResourceAutoCreationIT.java @@ -25,9 +25,8 @@ import com.google.cloud.kafka.connect.bigtable.config.InsertMode; import com.google.cloud.kafka.connect.bigtable.config.NullValueMode; import com.google.cloud.kafka.connect.bigtable.exception.InvalidBigtableSchemaModificationException; -import com.google.protobuf.ByteString; import com.google.cloud.kafka.connect.bigtable.util.JsonConverterFactory; - +import com.google.protobuf.ByteString; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Arrays; @@ -37,7 +36,6 @@ import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; import java.util.stream.StreamSupport; - import org.apache.kafka.clients.consumer.ConsumerRecords; import org.apache.kafka.connect.data.Schema; import org.apache.kafka.connect.data.SchemaBuilder; @@ -117,8 +115,7 @@ public void testDisabledResourceAutoCreation() .anyMatch(r -> Arrays.equals(KEY3.getBytes(StandardCharsets.UTF_8), r.key()))); assertConnectorAndAllTasksAreRunning(testId); // With the column family created. - bigtableAdmin.modifyFamilies( - ModifyColumnFamiliesRequest.of(testId).addFamily(COLUMN_FAMILY2)); + bigtableAdmin.modifyFamilies(ModifyColumnFamiliesRequest.of(testId).addFamily(COLUMN_FAMILY2)); connect.kafka().produce(testId, KEY4, serializedValue2); waitUntilBigtableContainsNumberOfRows(testId, 2); assertTrue( @@ -148,8 +145,7 @@ public void testTableAutoCreationDisabledColumnFamilyAutoCreationEnabled() assertSingleDlqEntry(dlqTopic, KEY1, value, null); createTablesAndColumnFamilies(Map.of(testId, Set.of())); - assertTrue( - bigtableAdmin.getTable(testId).getColumnFamilies().isEmpty()); + assertTrue(bigtableAdmin.getTable(testId).getColumnFamilies().isEmpty()); connect.kafka().produce(testId, KEY2, value); waitUntilBigtableTableHasExactSetOfColumnFamilies(testId, Set.of(testId)); waitUntilBigtableContainsNumberOfRows(testId, 1); @@ -223,8 +219,7 @@ public void testRowDeletionCreatesTableWhenAutoCreationEnabled() throws Interrup assertFalse(bigtableAdmin.listTables().contains(testId)); connect.kafka().produce(testId, KEY1, rowDeletionValue); waitUntilBigtableTableExists(testId); - assertTrue( - bigtableAdmin.getTable(testId).getColumnFamilies().isEmpty()); + assertTrue(bigtableAdmin.getTable(testId).getColumnFamilies().isEmpty()); assertSingleDlqEntry(dlqTopic, KEY1, null, null); assertConnectorAndAllTasksAreRunning(testId); @@ -294,10 +289,9 @@ public void testColumnDeletionCreatesTableAndColumnFamilyWhenAutoCreationEnabled } /** - * This test checks consequences of design choices described in comments in - * {@link com.google.cloud.kafka.connect.bigtable.mapping.MutationDataBuilder#deleteCells(String, - * ByteString, Range.TimestampRange)} and - * {@link + * This test checks consequences of design choices described in comments in {@link + * com.google.cloud.kafka.connect.bigtable.mapping.MutationDataBuilder#deleteCells(String, + * ByteString, Range.TimestampRange)} and {@link * com.google.cloud.kafka.connect.bigtable.mapping.MutationDataBuilder#deleteFamily(String)}. */ @Test diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/VersionIT.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/VersionIT.java index 987c694b..d253b7bc 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/VersionIT.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/integration/VersionIT.java @@ -20,14 +20,12 @@ import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.cloud.kafka.connect.bigtable.version.PackageMetadata; - import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.util.Arrays; - import org.apache.kafka.connect.runtime.rest.entities.PluginInfo; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/util/SchemaRegistryTestUtil.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/util/SchemaRegistryTestUtil.java index 752fd5ac..85fd2de1 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/util/SchemaRegistryTestUtil.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/util/SchemaRegistryTestUtil.java @@ -27,11 +27,9 @@ import io.confluent.kafka.schemaregistry.CompatibilityLevel; import io.confluent.kafka.schemaregistry.RestApp; - import java.io.IOException; import java.net.ServerSocket; import java.util.Properties; - import org.apache.kafka.test.TestUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/util/TestDataUtil.java b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/util/TestDataUtil.java index 72400c53..611b1c32 100644 --- a/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/util/TestDataUtil.java +++ b/kafka-connect-bigtable-sink/integration-tests/src/test/java/com/google/cloud/kafka/connect/bigtable/util/TestDataUtil.java @@ -1,40 +1,60 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.google.cloud.kafka.connect.bigtable.util; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.cloud.bigtable.data.v2.models.Row; import com.google.cloud.bigtable.data.v2.models.RowCell; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; import org.apache.kafka.connect.data.Schema; import org.apache.kafka.connect.data.SchemaBuilder; import org.apache.kafka.connect.data.Struct; import org.apache.kafka.connect.json.JsonConverter; import org.apache.kafka.connect.util.clusters.EmbeddedConnectCluster; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - public class TestDataUtil { private static final ObjectMapper objectMapper = new ObjectMapper(); - public static final Schema orderProductSchema = SchemaBuilder.struct() - .field("name", Schema.STRING_SCHEMA) - .field("id", Schema.STRING_SCHEMA) - .field("quantity", Schema.INT32_SCHEMA) - .build(); - - - public static final Schema orderElementSchema = SchemaBuilder.struct().field("element", orderProductSchema).optional().build(); - - public static final Schema orderSchema = SchemaBuilder.struct().optional() - .field("orderId", Schema.STRING_SCHEMA) - .field("userId", Schema.STRING_SCHEMA) - .field("products", - SchemaBuilder.struct().field("list", SchemaBuilder.array(orderElementSchema).optional()).build() - ) - .build(); - - public static void writeOrder(EmbeddedConnectCluster connect, String topic, String key, Order order) { + public static final Schema orderProductSchema = + SchemaBuilder.struct() + .field("name", Schema.STRING_SCHEMA) + .field("id", Schema.STRING_SCHEMA) + .field("quantity", Schema.INT32_SCHEMA) + .build(); + + public static final Schema orderElementSchema = + SchemaBuilder.struct().field("element", orderProductSchema).optional().build(); + + public static final Schema orderSchema = + SchemaBuilder.struct() + .optional() + .field("orderId", Schema.STRING_SCHEMA) + .field("userId", Schema.STRING_SCHEMA) + .field( + "products", + SchemaBuilder.struct() + .field("list", SchemaBuilder.array(orderElementSchema).optional()) + .build()) + .build(); + + public static void writeOrder( + EmbeddedConnectCluster connect, String topic, String key, Order order) { JsonConverter converter = new JsonConverter(); converter.configure(Collections.singletonMap("schemas.enable", "true"), false); @@ -46,28 +66,33 @@ public static void writeOrder(EmbeddedConnectCluster connect, String topic, Stri productList.add(null); continue; } - Struct productStruct = new Struct(orderElementSchema).put("element", new Struct(orderProductSchema) - .put("name", product.name) - .put("id", product.id) - .put("quantity", product.quantity) - ); + Struct productStruct = + new Struct(orderElementSchema) + .put( + "element", + new Struct(orderProductSchema) + .put("name", product.name) + .put("id", product.id) + .put("quantity", product.quantity)); productList.add(productStruct); } } - Struct productsWrapper = new Struct(orderSchema.field("products").schema()) - .put("list", productList); + Struct productsWrapper = + new Struct(orderSchema.field("products").schema()).put("list", productList); - Struct value = new Struct(orderSchema) - .put("orderId", order.orderId) - .put("userId", order.userId) - .put("products", productsWrapper); + Struct value = + new Struct(orderSchema) + .put("orderId", order.orderId) + .put("userId", order.userId) + .put("products", productsWrapper); byte[] schemaAsJson = converter.fromConnectData(topic, orderSchema, value); connect.kafka().produce(topic, key, new String(schemaAsJson)); } - public static TestDataUtil.Order extractExpandedOrderFromRow(Row row) throws JsonProcessingException { + public static TestDataUtil.Order extractExpandedOrderFromRow(Row row) + throws JsonProcessingException { String orderId = getValue(row, "cf", "orderId"); String userId = getValue(row, "cf", "userId"); @@ -77,15 +102,13 @@ public static TestDataUtil.Order extractExpandedOrderFromRow(Row row) throws Jso List productList = new ArrayList<>(); for (RowCell cell : productCells) { String json = cell.getValue().toStringUtf8(); - TestDataUtil.OrderProduct product = objectMapper.readValue(json, TestDataUtil.OrderProduct.class); + TestDataUtil.OrderProduct product = + objectMapper.readValue(json, TestDataUtil.OrderProduct.class); productList.add(product); } return new TestDataUtil.Order( - orderId, - userId, - productList.toArray(new TestDataUtil.OrderProduct[0]) - ); + orderId, userId, productList.toArray(new TestDataUtil.OrderProduct[0])); } private static String getValue(Row row, String family, String qualifier) { @@ -97,9 +120,7 @@ private static String getValue(Row row, String family, String qualifier) { return cells.get(0).getValue().toStringUtf8(); } - public record Order(String orderId, String userId, OrderProduct[] products) { - } + public record Order(String orderId, String userId, OrderProduct[] products) {} - public record OrderProduct(String name, String id, int quantity) { - } + public record OrderProduct(String name, String id, int quantity) {} } diff --git a/kafka-connect-bigtable-sink/pom.xml b/kafka-connect-bigtable-sink/pom.xml index 1c949129..2e024fc0 100644 --- a/kafka-connect-bigtable-sink/pom.xml +++ b/kafka-connect-bigtable-sink/pom.xml @@ -12,7 +12,6 @@ sink - integration-tests 26.53.0 @@ -35,6 +34,8 @@ 3.5.2 3.5.2 3.4.2 + 3.3.0 + 3.5.0 11 11 @@ -63,6 +64,9 @@ .gitignore + + third_party + @@ -72,6 +76,9 @@ + + third_party + ${google.java.format.version} @@ -125,4 +132,15 @@ + + + integration-tests + + integration-tests + + + true + + + \ No newline at end of file diff --git a/kafka-connect-bigtable-sink/sink/pom.xml b/kafka-connect-bigtable-sink/sink/pom.xml index 5883bb46..49752d71 100644 --- a/kafka-connect-bigtable-sink/sink/pom.xml +++ b/kafka-connect-bigtable-sink/sink/pom.xml @@ -78,7 +78,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.3.0 + ${maven-build-helper.version} add-source @@ -90,7 +90,7 @@ - ./third_party/apache_hbase_common/src/main/java/com/google/cloud/kafka/connect/bigtable/utils/ByteUtils.java + ./third_party/apache_hbase_common/src/main/java @@ -99,7 +99,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.5.0 + ${maven-shade.version} package @@ -136,11 +136,31 @@ classes true - target/test-classes/fake_service_key.json + + + integration-tests + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven-jar.version} + + + + test-jar + + + + + + + + \ No newline at end of file diff --git a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/BigtableSinkTask.java b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/BigtableSinkTask.java index fb5f35dc..8e3533ca 100644 --- a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/BigtableSinkTask.java +++ b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/BigtableSinkTask.java @@ -40,6 +40,7 @@ import com.google.cloud.kafka.connect.bigtable.wrappers.BigtableTableAdminClientInterface; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; +import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.ByteString; import java.util.ArrayList; import java.util.Collection; @@ -51,6 +52,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.apache.kafka.connect.data.SchemaAndValue; import org.apache.kafka.connect.errors.ConnectException; @@ -186,6 +188,9 @@ public void put(Collection records) { case UPSERT: upsertRows(mutations, perRecordResults); break; + case REPLACE_IF_NEWEST: + replaceRows(mutations, perRecordResults); + break; } handleResults(perRecordResults); } @@ -233,9 +238,10 @@ Optional createRecordMutationData(SinkRecord record) { "The record's key converts into an illegal empty Cloud Bigtable row key."); } SchemaAndValue kafkaValue = new SchemaAndValue(record.valueSchema(), record.value()); - long timestamp = getTimestampMicros(record); + long timestampMicros = getTimestampMicros(record); MutationDataBuilder mutationDataBuilder = - valueMapper.getRecordMutationDataBuilder(kafkaValue, record.topic(), timestamp); + valueMapper.getRecordMutationDataBuilder( + kafkaValue, record.topic(), config.getInsertMode(), timestampMicros); return mutationDataBuilder.maybeBuild(recordTableId, rowKey); } @@ -272,7 +278,7 @@ long getTimestampMicros(SinkRecord record) { logger.debug("Used wall clock for a record missing timestamp."); timestampMillis = System.currentTimeMillis(); } - return 1000 * timestampMillis; + return TimeUnit.MILLISECONDS.toMicros(timestampMillis); } /** @@ -434,7 +440,7 @@ void performUpsertBatch( Batcher batcher = batchers.computeIfAbsent(recordTableName, (k) -> bigtableData.newBulkMutationBatcher(k)); - perRecordResults.put(record, batcher.add(recordMutationData.getUpsertMutation())); + perRecordResults.put(record, batcher.add(recordMutationData.getRowMutationEntry())); } for (Batcher batcher : batchers.values()) { // We must flush the batchers to respect CONFIG_MAX_BATCH_SIZE. @@ -443,6 +449,72 @@ void performUpsertBatch( } } + /** + * Applies the mutations using replace-if-newest logic. + * + *

See {@link BigtableSinkConfig#INSERT_MODE_CONFIG} option's description for details. + * + * @param mutations Mutations to be applied. + * @param perRecordResults {@link Map} the per-record results will be written to. + */ + @VisibleForTesting + void replaceRows( + Map mutations, Map> perRecordResults) { + List> mutationsToApply = + new ArrayList<>(mutations.entrySet()); + int maxBatchSize = config.getInt(BigtableSinkTaskConfig.MAX_BATCH_SIZE_CONFIG); + List>> batches = + Lists.partition(mutationsToApply, maxBatchSize); + + for (List> batch : batches) { + performReplaceBatch(batch, perRecordResults); + } + } + + /** + * Applies a single mutation batch using replace-if-newest logic. + * + *

See {@link BigtableSinkConfig#INSERT_MODE_CONFIG} option's description for details. + * + * @param batch Batch of mutations to be applied. + * @param perRecordResults A {@link Map} the per-record results will be written to. + */ + @VisibleForTesting + void performReplaceBatch( + List> batch, + Map> perRecordResults) { + logger.trace("replaceBatch(#records={})", batch.size()); + + for (Map.Entry recordEntry : batch) { + SinkRecord record = recordEntry.getKey(); + MutationData recordMutationData = recordEntry.getValue(); + String recordTableName = recordMutationData.getTargetTable(); + + Filters.TimestampRangeFilter timestampRange = + Filters.FILTERS + .timestamp() + .range() + .startOpen(recordMutationData.getTimestampMicros()) + .endUnbounded(); + + // Execute the mutation (which is assumed to contain deleteRow as its first element) + // if the bigtable row contains no cell fresher than this record. + // In other words, replace the row if the current new timestamp is greater or equal + // to the current one. + ConditionalRowMutation crm = + ConditionalRowMutation.create(recordTableName, recordMutationData.getRowKey()) + .condition(timestampRange) + .otherwise(recordMutationData.getMutation()); + + ApiFuture result = bigtableData.checkAndMutateRowAsync(crm); + // We don't care if the row was really written, the only interesting aspect is whether it + // failed. + ApiFuture resultIgnoringSuccess = + ApiFutures.transform(result, x -> null, MoreExecutors.directExecutor()); + perRecordResults.put(record, resultIgnoringSuccess); + } + } + /** * Applies the mutations using inserts. * @@ -467,7 +539,7 @@ void insertRows( // We first check if any cell of this row exists... .condition(Filters.FILTERS.pass()) // ... and perform the mutation only if no cell exists. - .otherwise(recordMutationData.getInsertMutation()); + .otherwise(recordMutationData.getMutation()); boolean insertSuccessful; Optional exceptionThrown = Optional.empty(); try { diff --git a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/config/BigtableSinkConfig.java b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/config/BigtableSinkConfig.java index 67f40fbe..44874a44 100644 --- a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/config/BigtableSinkConfig.java +++ b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/config/BigtableSinkConfig.java @@ -33,6 +33,12 @@ import com.google.cloud.kafka.connect.bigtable.wrappers.BigtableTableAdminClientWrapper; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Sets; +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.function.Function; import org.apache.kafka.common.config.*; import org.apache.kafka.common.utils.Utils; import org.apache.kafka.connect.errors.RetriableException; @@ -41,13 +47,6 @@ import org.threeten.bp.Duration; import org.threeten.bp.temporal.ChronoUnit; -import java.io.ByteArrayInputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.function.Function; - /** * A class defining the configuration of {@link * com.google.cloud.kafka.connect.bigtable.BigtableSinkConnector}. @@ -113,10 +112,10 @@ public static Config validate(Map props) { /** * Validates that a valid {@link BigtableSinkConfig} can be created using the input properties. * - * @param props The properties provided by the user. + * @param props The properties provided by the user. * @param accessBigtableToValidateConfiguration If set to true, validation includes checking - * whether the Cloud Bigtable configuration is valid by connecting to Cloud Bigtable and - * attempting to execute a simple read-only operation. + * whether the Cloud Bigtable configuration is valid by connecting to Cloud Bigtable and + * attempting to execute a simple read-only operation. * @return {@link Config} containing validation results. */ @VisibleForTesting @@ -214,7 +213,7 @@ static Config validate(Map props, boolean accessBigtableToValida /** * @return {@link ConfigDef} used by Kafka Connect to advertise configuration options to the user - * and by us to perform basic validation of the user-provided values. + * and by us to perform basic validation of the user-provided values. */ public static ConfigDef getDefinition() { return new ConfigDef() @@ -267,11 +266,13 @@ public static ConfigDef getDefinition() { InsertMode.INSERT.name(), enumValidator(InsertMode.values()), ConfigDef.Importance.HIGH, - "Defines the insertion mode to use. Supported modes are:" - + "\n- insert - Insert new record only." - + " If the row to be written already exists in the table, an error is thrown." - + "\n- upsert - If the row to be written already exists," - + " then its column values are overwritten with the ones provided.") + "Defines the insertion mode to use. Supported modes are:\n" + + "- insert - Insert new record only. If the row to be written already exists in" + + " the table, an error is thrown.\n" + + "- upsert - If the row to be written already exists, then its column values are" + + " overwritten with the ones provided.\n" + + "- replace_if_newest - If there are no cells newer than this record within the" + + " target row of the table, clear the row and then insert new record.") .define( MAX_BATCH_SIZE_CONFIG, ConfigDef.Type.INT, @@ -355,11 +356,12 @@ public static ConfigDef getDefinition() { ConfigDef.Type.BOOLEAN, false, ConfigDef.Importance.MEDIUM, - "Determines whether root level arrays should be expanded to a column family or serialized to " + - "a single column. If true, root level array fields will be mapped to a Bigtable column family where " + - "each element is stored in an individual column with its index as column qualifier, padded with " + - "zeros to a length of 6. If false, root level array fields will be serialized as a JSON string to " + - "a single column.") + "Determines whether root level arrays should be expanded to a column family or" + + " serialized to a single column. If true, root level array fields will be mapped" + + " to a Bigtable column family where each element is stored in an individual" + + " column with its index as column qualifier, padded with zeros to a length of 6." + + " If false, root level array fields will be serialized as a JSON string to a" + + " single column.") .define( AUTO_CREATE_TABLES_CONFIG, ConfigDef.Type.BOOLEAN, @@ -420,9 +422,9 @@ public static ConfigDef getDefinition() { * Adds a validation error in the format expected by {@link BigtableSinkConfig#validate(Map)}. * * @param validatedConfig Input/output parameter containing current validation result. - * @param name Configuration parameter name. - * @param value Configuration parameter value. - * @param errorMessage Error message to be added. + * @param name Configuration parameter name. + * @param value Configuration parameter value. + * @param errorMessage Error message to be added. */ private static void addErrorMessage( Map validatedConfig, String name, String value, String errorMessage) { @@ -445,8 +447,8 @@ public InsertMode getInsertMode() { } /** - * @return {@link BigtableTableAdminClientInterface} connected to a Cloud Bigtable instance configured as - * described in {@link BigtableSinkConfig#getDefinition()}. + * @return {@link BigtableTableAdminClientInterface} connected to a Cloud Bigtable instance + * configured as described in {@link BigtableSinkConfig#getDefinition()}. */ public BigtableTableAdminClientInterface getBigtableAdminClient() { Duration totalTimeout = getTotalRetryTimeout(); @@ -502,7 +504,8 @@ BigtableTableAdminClientInterface getBigtableAdminClient( StatusCode.Code.FAILED_PRECONDITION))); try { - return new BigtableTableAdminClientWrapper(BigtableTableAdminClient.create(adminSettingsBuilder.build())); + return new BigtableTableAdminClientWrapper( + BigtableTableAdminClient.create(adminSettingsBuilder.build())); } catch (IOException e) { throw new RetriableException(e); } @@ -510,7 +513,7 @@ BigtableTableAdminClientInterface getBigtableAdminClient( /** * @return {@link BigtableDataClient} connected to Cloud Bigtable instance configured as described - * in {@link BigtableSinkConfig#getDefinition()}. + * in {@link BigtableSinkConfig#getDefinition()}. */ public BigtableDataClient getBigtableDataClient() { Duration totalTimeout = getTotalRetryTimeout(); @@ -622,7 +625,7 @@ boolean isBigtableConfigurationValid() { /** * @return {@link RetrySettings} of Cloud Bigtable clients configured with exponential backoff and - * specified timeout and retry delay. + * specified timeout and retry delay. */ protected RetrySettings getRetrySettings(Duration totalTimeout, Duration initialDelay) { return RetrySettings.newBuilder() @@ -635,7 +638,7 @@ protected RetrySettings getRetrySettings(Duration totalTimeout, Duration initial /** * @return Maximal time for Cloud Bigtable clients as described in {@link - * BigtableSinkConfig#getDefinition()}. + * BigtableSinkConfig#getDefinition()}. */ private Duration getTotalRetryTimeout() { return Duration.of(getLong(RETRY_TIMEOUT_MILLIS_CONFIG), ChronoUnit.MILLIS); @@ -645,9 +648,9 @@ private Duration getTotalRetryTimeout() { * Extracts typed enum value from this object. * * @param configName Enum parameter name in {@link BigtableSinkConfig}. - * @param converter Function that parses parameter value into an enum value. It's assumed to throw - * only {@link NullPointerException} and {@link IllegalArgumentException}. - * @param Enum type. + * @param converter Function that parses parameter value into an enum value. It's assumed to throw + * only {@link NullPointerException} and {@link IllegalArgumentException}. + * @param Enum type. * @return Parsed enum value. */ private T getEnum(String configName, Function converter) { @@ -666,8 +669,8 @@ private static ConfigDef.Validator enumValidator(Enum[] enumValues) { /** * @return {@link Optional#empty()} if the user didn't configure the Cloud Bigtable credentials, - * {@link Optional} containing {@link CredentialsProvider} configured as described in {@link - * BigtableSinkConfig#getDefinition()} otherwise. + * {@link Optional} containing {@link CredentialsProvider} configured as described in {@link + * BigtableSinkConfig#getDefinition()} otherwise. */ protected Optional getUserConfiguredBigtableCredentialsProvider() { String credentialsJson = getString(GCP_CREDENTIALS_JSON_CONFIG); @@ -698,10 +701,10 @@ protected Optional getUserConfiguredBigtableCredentialsProv /** * @return {@link HeaderProvider} allowing the service provider to monitor the usage of this - * connector. + * connector. */ private static HeaderProvider getHeaderProvider() { return FixedHeaderProvider.create( "user-agent", "bigtable-java/kafka-connect-sink/" + PackageMetadata.getVersion()); } -} \ No newline at end of file +} diff --git a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/config/InsertMode.java b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/config/InsertMode.java index a34481aa..b1e6a179 100644 --- a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/config/InsertMode.java +++ b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/config/InsertMode.java @@ -18,4 +18,5 @@ public enum InsertMode { INSERT, UPSERT, + REPLACE_IF_NEWEST, } diff --git a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/ByteUtils.java b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/ByteUtils.java deleted file mode 100644 index 2d9eca9f..00000000 --- a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/ByteUtils.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.cloud.kafka.connect.bigtable.mapping; - -import java.io.UnsupportedEncodingException; -import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; - -/** - * This code is copied from hbase-common using Apache 2.0 License. This code has been modified to - * remove functions that we don't need. - */ -public class ByteUtils { - - private static final String UTF8_CSN; - - static { - UTF8_CSN = StandardCharsets.UTF_8.name(); - } - - public static byte[] toBytes(double d) { - return toBytes(Double.doubleToRawLongBits(d)); - } - - public static byte[] toBytes(float f) { - return toBytes(Float.floatToRawIntBits(f)); - } - - public static byte[] toBytes(int val) { - byte[] b = new byte[4]; - - for (int i = 3; i > 0; --i) { - b[i] = (byte) val; - val >>>= 8; - } - - b[0] = (byte) val; - return b; - } - - public static byte[] toBytes(short val) { - byte[] b = new byte[]{0, (byte) val}; - val = (short) (val >> 8); - b[0] = (byte) val; - return b; - } - - public static byte[] toBytes(BigDecimal val) { - byte[] valueBytes = val.unscaledValue().toByteArray(); - byte[] result = new byte[valueBytes.length + 4]; - int offset = putInt(result, 0, val.scale()); - System.arraycopy(valueBytes, 0, result, offset, valueBytes.length); - return result; - } - - public static int putInt(byte[] bytes, int offset, int val) { - if (bytes.length - offset < 4) { - throw new IllegalArgumentException( - "Not enough room to put an int at offset " + offset + " in a " + bytes.length - + " byte array"); - } else { - for (int i = offset + 3; i > offset; --i) { - bytes[i] = (byte) val; - val >>>= 8; - } - - bytes[offset] = (byte) val; - return offset + 4; - } - } - - public static byte[] toBytes(String s) { - try { - return s.getBytes(UTF8_CSN); - } catch (UnsupportedEncodingException var2) { - throw new IllegalArgumentException("UTF8 decoding is not supported", var2); - } - } - - public static byte[] toBytes(boolean b) { - return new byte[]{(byte) (b ? -1 : 0)}; - } - - public static byte[] toBytes(long val) { - byte[] b = new byte[8]; - - for (int i = 7; i > 0; --i) { - b[i] = (byte) ((int) val); - val >>>= 8; - } - - b[0] = (byte) ((int) val); - return b; - } -} diff --git a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/MutationData.java b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/MutationData.java index 65d4fc1c..b7074e86 100644 --- a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/MutationData.java +++ b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/MutationData.java @@ -29,16 +29,19 @@ public class MutationData { private final ByteString rowKey; private final Mutation mutation; private final Set requiredColumnFamilies; + private final long timestampMicros; public MutationData( String targetTable, ByteString rowKey, Mutation mutation, - Set requiredColumnFamilies) { + Set requiredColumnFamilies, + long timestampMicros) { this.targetTable = targetTable; this.rowKey = rowKey; this.mutation = mutation; this.requiredColumnFamilies = requiredColumnFamilies; + this.timestampMicros = timestampMicros; } public String getTargetTable() { @@ -49,11 +52,15 @@ public ByteString getRowKey() { return rowKey; } - public RowMutationEntry getUpsertMutation() { + public long getTimestampMicros() { + return this.timestampMicros; + } + + public RowMutationEntry getRowMutationEntry() { return RowMutationEntry.createFromMutationUnsafe(this.rowKey, this.mutation); } - public Mutation getInsertMutation() { + public Mutation getMutation() { return mutation; } diff --git a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/MutationDataBuilder.java b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/MutationDataBuilder.java index 75fab665..1f86feaa 100644 --- a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/MutationDataBuilder.java +++ b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/MutationDataBuilder.java @@ -28,16 +28,18 @@ public class MutationDataBuilder { private final Mutation mutation; private boolean mutationIsEmpty; private final Set requiredColumnFamilies; + private final long timestampMicros; @VisibleForTesting - MutationDataBuilder(Mutation mutation) { + MutationDataBuilder(Mutation mutation, long timestampMicros) { this.mutation = mutation; mutationIsEmpty = true; requiredColumnFamilies = new HashSet<>(); + this.timestampMicros = timestampMicros; } - public MutationDataBuilder() { - this(Mutation.create()); + public MutationDataBuilder(long timestampMicros) { + this(Mutation.create(), timestampMicros); } /** @@ -50,10 +52,11 @@ public MutationDataBuilder() { * mutation ready to be written to Cloud Bigtable otherwise. */ public Optional maybeBuild(String targetTable, ByteString rowKey) { - return this.mutationIsEmpty + return mutationIsEmpty ? Optional.empty() : Optional.of( - new MutationData(targetTable, rowKey, this.mutation, this.requiredColumnFamilies)); + new MutationData( + targetTable, rowKey, mutation, requiredColumnFamilies, timestampMicros)); } public void deleteRow() { @@ -90,8 +93,7 @@ public void deleteCells( mutation.deleteCells(columnFamily, columnQualifier, timestampRange); } - public void setCell( - String columnFamily, ByteString columnQualifier, long timestampMicros, ByteString value) { + public void setCell(String columnFamily, ByteString columnQualifier, ByteString value) { mutationIsEmpty = false; requiredColumnFamilies.add(columnFamily); mutation.setCell(columnFamily, columnQualifier, timestampMicros, value); diff --git a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/ValueMapper.java b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/ValueMapper.java index 2c73e273..0002b061 100644 --- a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/ValueMapper.java +++ b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/mapping/ValueMapper.java @@ -15,6 +15,8 @@ */ package com.google.cloud.kafka.connect.bigtable.mapping; +import static com.google.cloud.kafka.connect.bigtable.mapping.LogicalTypeUtils.logIfLogicalTypeUnsupported; + import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -23,23 +25,22 @@ import com.fasterxml.jackson.databind.ser.std.StdSerializer; import com.google.cloud.bigtable.data.v2.models.Range; import com.google.cloud.kafka.connect.bigtable.config.ConfigInterpolation; +import com.google.cloud.kafka.connect.bigtable.config.InsertMode; import com.google.cloud.kafka.connect.bigtable.config.NullValueMode; +import com.google.cloud.kafka.connect.bigtable.utils.ByteUtils; import com.google.common.annotations.VisibleForTesting; import com.google.protobuf.ByteString; -import org.apache.kafka.common.utils.Utils; -import org.apache.kafka.connect.data.*; -import org.apache.kafka.connect.errors.DataException; - -import javax.annotation.Nonnull; import java.io.IOException; import java.math.BigDecimal; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.util.Date; import java.util.*; +import java.util.Date; import java.util.stream.Collectors; - -import static com.google.cloud.kafka.connect.bigtable.mapping.LogicalTypeUtils.logIfLogicalTypeUnsupported; +import javax.annotation.Nonnull; +import org.apache.kafka.common.utils.Utils; +import org.apache.kafka.connect.data.*; +import org.apache.kafka.connect.errors.DataException; /** * A class responsible for converting Kafka {@link org.apache.kafka.connect.sink.SinkRecord @@ -48,7 +49,8 @@ */ public class ValueMapper { private static final int ROOT_LEVEL_ARRAY_INDEX_PADDING_WIDTH = 6; - private static final String ROOT_LEVEL_ARRAY_INDEX_FORMAT = "%0" + ROOT_LEVEL_ARRAY_INDEX_PADDING_WIDTH + "d"; + private static final String ROOT_LEVEL_ARRAY_INDEX_FORMAT = + "%0" + ROOT_LEVEL_ARRAY_INDEX_PADDING_WIDTH + "d"; public final String defaultColumnFamilyTemplate; public final ByteString defaultColumnQualifier; private final NullValueMode nullMode; @@ -58,13 +60,16 @@ public class ValueMapper { /** * The main constructor. * - * @param defaultColumnFamily Default column family as per {@link - * com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig#DEFAULT_COLUMN_FAMILY_CONFIG}. + * @param defaultColumnFamily Default column family as per {@link + * com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig#DEFAULT_COLUMN_FAMILY_CONFIG}. * @param defaultColumnQualifier Default column as per {@link - * com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig#ROW_KEY_DELIMITER_CONFIG}. + * com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig#ROW_KEY_DELIMITER_CONFIG}. */ public ValueMapper( - String defaultColumnFamily, String defaultColumnQualifier, @Nonnull NullValueMode nullMode, boolean expandRootLevelArrays) { + String defaultColumnFamily, + String defaultColumnQualifier, + @Nonnull NullValueMode nullMode, + boolean expandRootLevelArrays) { this.defaultColumnFamilyTemplate = Utils.isBlank(defaultColumnFamily) ? null : defaultColumnFamily; this.defaultColumnQualifier = @@ -80,17 +85,21 @@ public ValueMapper( * representing the input Kafka Connect value as Cloud Bigtable mutations that need to be applied. * * @param kafkaValueAndSchema The value to be converted into Cloud Bigtable {@link - * com.google.cloud.bigtable.data.v2.models.Mutation Mutation(s)} and its optional {@link - * Schema}. - * @param topic The name of Kafka topic this value originates from. - * @param timestampMicros The timestamp the mutations will be created at in microseconds. + * com.google.cloud.bigtable.data.v2.models.Mutation Mutation(s)} and its optional {@link + * Schema}. + * @param topic The name of Kafka topic this value originates from. + * @param timestampMicros The timestamp the mutations will be created at in microseconds. */ public MutationDataBuilder getRecordMutationDataBuilder( - SchemaAndValue kafkaValueAndSchema, String topic, long timestampMicros) { + SchemaAndValue kafkaValueAndSchema, + String topic, + InsertMode insertMode, + long timestampMicros) { Object rootKafkaValue = kafkaValueAndSchema.value(); Optional rootKafkaSchema = Optional.ofNullable(kafkaValueAndSchema.schema()); logIfLogicalTypeUnsupported(rootKafkaSchema); - MutationDataBuilder mutationDataBuilder = createMutationDataBuilder(); + MutationDataBuilder mutationDataBuilder = + createMutationDataBuilder(insertMode, timestampMicros); if (rootKafkaValue == null && nullMode == NullValueMode.IGNORE) { // Do nothing } else if (rootKafkaValue == null && nullMode == NullValueMode.DELETE) { @@ -107,7 +116,7 @@ public MutationDataBuilder getRecordMutationDataBuilder( } else if (kafkaFieldValue == null && nullMode == NullValueMode.DELETE) { mutationDataBuilder.deleteFamily(kafkaFieldName); } else if (expandRootLevelArrays && kafkaFieldValue instanceof List) { - writeRootLevelArray(mutationDataBuilder, kafkaFieldName, kafkaFieldValue, timestampMicros); + writeRootLevelArray(mutationDataBuilder, kafkaFieldName, kafkaFieldValue); } else if (kafkaFieldValue instanceof Struct) { for (Map.Entry subfield : getChildren((Struct) kafkaFieldValue, kafkaFieldSchema)) { @@ -128,7 +137,6 @@ public MutationDataBuilder getRecordMutationDataBuilder( mutationDataBuilder.setCell( kafkaFieldName, kafkaSubfieldName, - timestampMicros, ByteString.copyFrom(serialize(kafkaSubfieldValue))); } } @@ -137,7 +145,6 @@ public MutationDataBuilder getRecordMutationDataBuilder( mutationDataBuilder.setCell( getDefaultColumnFamily(topic), ByteString.copyFrom(kafkaFieldName.getBytes(StandardCharsets.UTF_8)), - timestampMicros, ByteString.copyFrom(serialize(kafkaFieldValue))); } } @@ -147,14 +154,14 @@ public MutationDataBuilder getRecordMutationDataBuilder( mutationDataBuilder.setCell( getDefaultColumnFamily(topic), defaultColumnQualifier, - timestampMicros, ByteString.copyFrom(serialize(rootKafkaValue))); } } return mutationDataBuilder; } - private void writeRootLevelArray(MutationDataBuilder mutationDataBuilder, String columnFamily, Object value, long timestampMicros) { + private void writeRootLevelArray( + MutationDataBuilder mutationDataBuilder, String columnFamily, Object value) { List listValue = (List) value; // clear the previous value in case it has more elements than this one mutationDataBuilder.deleteFamily(columnFamily); @@ -163,16 +170,24 @@ private void writeRootLevelArray(MutationDataBuilder mutationDataBuilder, String mutationDataBuilder.setCell( columnFamily, // pad element names with leading zeros for easier sorting: '000001' - ByteString.copyFrom(String.format(ROOT_LEVEL_ARRAY_INDEX_FORMAT, i).getBytes(StandardCharsets.UTF_8)), - timestampMicros, + ByteString.copyFrom( + String.format(ROOT_LEVEL_ARRAY_INDEX_FORMAT, i).getBytes(StandardCharsets.UTF_8)), ByteString.copyFrom(serialize(o))); } } @VisibleForTesting - // Method only needed for use in tests. It could be inlined otherwise. - protected MutationDataBuilder createMutationDataBuilder() { - return new MutationDataBuilder(); + protected MutationDataBuilder createMutationDataBuilder( + InsertMode insertMode, long timestampMicros) { + MutationDataBuilder builder = new MutationDataBuilder(timestampMicros); + // Note that we call the method on the builder instead of passing it a set up mutation via + // a constructor. This way we ensure that even for an empty (empty Struct, `null` when + // the mapper is configured to ignore nulls) input value, the row is deleted, which + // is needed for cleaner semantics of the REPLACE_IF_NEWEST mode. + if (insertMode == InsertMode.REPLACE_IF_NEWEST) { + builder.deleteRow(); + } + return builder; } protected String getDefaultColumnFamily(String topic) { @@ -182,7 +197,7 @@ protected String getDefaultColumnFamily(String topic) { /** * @param struct {@link Struct} whose children we want to list * @return {@link List} of pairs of field names and values (with optional schemas) of {@code - * struct}'s fields. + * struct}'s fields. */ private static List> getChildren( Struct struct, Optional schema) { @@ -201,7 +216,7 @@ private static List> getChildren( /** * @param value Input value. * @return Input value's serialization's bytes that will be written to Cloud Bigtable as a cell's - * value. + * value. */ private static byte[] serialize(Object value) { if (value == null) { diff --git a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/transformations/ApplyJsonSchema.java b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/transformations/ApplyJsonSchema.java index 88f3af27..b26e4cbc 100644 --- a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/transformations/ApplyJsonSchema.java +++ b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/transformations/ApplyJsonSchema.java @@ -1,6 +1,23 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.google.cloud.kafka.connect.bigtable.transformations; import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.*; import org.apache.kafka.common.config.ConfigDef; import org.apache.kafka.connect.connector.ConnectRecord; import org.apache.kafka.connect.data.Schema; @@ -10,9 +27,6 @@ import org.apache.kafka.connect.transforms.Transformation; import org.apache.kafka.connect.transforms.util.SimpleConfig; -import java.io.IOException; -import java.util.*; - public abstract class ApplyJsonSchema> implements Transformation { public static final String OVERVIEW_DOC = @@ -21,8 +35,15 @@ public abstract class ApplyJsonSchema> implements Tra public static final String SCHEMA_CONFIG = "schema.json"; private static final String SCHEMA_DOC = "The schema definition in JSON format."; - private static final ConfigDef CONFIG_DEF = new ConfigDef() - .define(SCHEMA_CONFIG, ConfigDef.Type.STRING, ConfigDef.NO_DEFAULT_VALUE, new org.apache.kafka.common.config.ConfigDef.NonEmptyString(), ConfigDef.Importance.HIGH, SCHEMA_DOC); + private static final ConfigDef CONFIG_DEF = + new ConfigDef() + .define( + SCHEMA_CONFIG, + ConfigDef.Type.STRING, + ConfigDef.NO_DEFAULT_VALUE, + new org.apache.kafka.common.config.ConfigDef.NonEmptyString(), + ConfigDef.Importance.HIGH, + SCHEMA_DOC); private Schema targetSchema; private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @@ -56,8 +77,8 @@ public R apply(R record) { protected abstract R newRecord(R record, Schema schema, Object value); /** - * Recursively converts a Java Object (Map, List, or Primitive) into a Connect Struct/Array - * based on the provided Schema. + * Recursively converts a Java Object (Map, List, or Primitive) into a Connect Struct/Array based + * on the provided Schema. */ private Object convertToConnectData(String name, Object input, Schema schema) { if (input == null) { @@ -73,7 +94,9 @@ private Object convertToConnectData(String name, Object input, Schema schema) { switch (schema.type()) { case STRUCT: if (!(input instanceof Map)) { - throw new DataException(String.format("Expected Map for STRUCT schema for field %s, found %s", name, input.getClass())); + throw new DataException( + String.format( + "Expected Map for STRUCT schema for field %s, found %s", name, input.getClass())); } Struct struct = new Struct(schema); Map inputMap = (Map) input; @@ -85,7 +108,9 @@ private Object convertToConnectData(String name, Object input, Schema schema) { return struct; case ARRAY: if (!(input instanceof List)) { - throw new DataException(String.format("Expected List for ARRAY schema for field %s, found %s", name, input.getClass())); + throw new DataException( + String.format( + "Expected List for ARRAY schema for field %s, found %s", name, input.getClass())); } List inputList = (List) input; List outputList = new ArrayList<>(); @@ -98,7 +123,9 @@ private Object convertToConnectData(String name, Object input, Schema schema) { return outputList; case MAP: if (!(input instanceof Map)) { - throw new DataException(String.format("Expected Map for MAP schema for field %s, found %s", name, input.getClass())); + throw new DataException( + String.format( + "Expected Map for MAP schema for field %s, found %s", name, input.getClass())); } Map inputMapForMap = (Map) input; Map outputMap = new HashMap<>(); @@ -107,8 +134,7 @@ private Object convertToConnectData(String name, Object input, Schema schema) { for (Map.Entry entry : inputMapForMap.entrySet()) { outputMap.put( convertToConnectData(name + "(key)", entry.getKey(), mapKeySchema), - convertToConnectData(name + "(value)", entry.getValue(), mapValueSchema) - ); + convertToConnectData(name + "(value)", entry.getValue(), mapValueSchema)); } return outputMap; default: @@ -166,10 +192,13 @@ private Object getPrimitiveValue(Object input, Schema schema) { if (input instanceof byte[]) { return input; } - throw new DataException("Expected a Base64-encoded String or byte[] for BYTES field, but found " + input.getClass().getName()); + throw new DataException( + "Expected a Base64-encoded String or byte[] for BYTES field, but found " + + input.getClass().getName()); case STRING: if (input instanceof Map || input instanceof List) { - throw new DataException("Expected a primitive for STRING field, but found " + input.getClass().getName()); + throw new DataException( + "Expected a primitive for STRING field, but found " + input.getClass().getName()); } return input.toString(); default: @@ -197,9 +226,13 @@ protected Object operatingValue(R record) { @Override protected R newRecord(R record, Schema schema, Object value) { return record.newRecord( - record.topic(), record.kafkaPartition(), - schema, value, - record.valueSchema(), record.value(), record.timestamp()); + record.topic(), + record.kafkaPartition(), + schema, + value, + record.valueSchema(), + record.value(), + record.timestamp()); } } @@ -212,9 +245,13 @@ protected Object operatingValue(R record) { @Override protected R newRecord(R record, Schema schema, Object value) { return record.newRecord( - record.topic(), record.kafkaPartition(), - record.keySchema(), record.key(), - schema, value, record.timestamp()); + record.topic(), + record.kafkaPartition(), + record.keySchema(), + record.key(), + schema, + value, + record.timestamp()); } } -} \ No newline at end of file +} diff --git a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/transformations/FlattenArrayElement.java b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/transformations/FlattenArrayElement.java index 52573e78..54445e85 100644 --- a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/transformations/FlattenArrayElement.java +++ b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/transformations/FlattenArrayElement.java @@ -1,6 +1,25 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.google.cloud.kafka.connect.bigtable.transformations; import com.google.common.annotations.VisibleForTesting; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; import org.apache.kafka.common.config.ConfigDef; import org.apache.kafka.connect.connector.ConnectRecord; import org.apache.kafka.connect.data.Field; @@ -11,14 +30,11 @@ import org.apache.kafka.connect.transforms.Transformation; import org.apache.kafka.connect.transforms.util.SimpleConfig; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; - /** - * This SMT is used to flatten nested array fields that can be generated by some serialization libraries. - * Given the following input message value, with `array.field="products"` `array.inner.wrapper="list"` `array.element.wrapper="element"` + * This SMT is used to flatten nested array fields that can be generated by some serialization + * libraries. Given the following input message value, with `array.field="products"` + * `array.inner.wrapper="list"` `array.element.wrapper="element"` + * *
{@code
  * {
  *   "orderId": "order1",
@@ -34,7 +50,9 @@
  *   }
  * }
  * }
+ * * The resulting output would be: + * *
{@code
  * {
  *   "orderId": "order1",
@@ -55,10 +73,23 @@ public class FlattenArrayElement> implements Transfor
   public static final String ARRAY_INNER_WRAPPER_FIELD_NAME = "array.inner.wrapper";
   public static final String ARRAY_ELEMENT_WRAPPER_FIELD_NAME = "array.element.wrapper";
 
-  public static final ConfigDef CONFIG_DEF = new ConfigDef()
-      .define(ARRAY_FIELD_NAME, ConfigDef.Type.STRING, ConfigDef.Importance.HIGH, "The name of the root level array field.")
-      .define(ARRAY_INNER_WRAPPER_FIELD_NAME, ConfigDef.Type.STRING, ConfigDef.Importance.HIGH, "The name of the inner array wrapper field.")
-      .define(ARRAY_ELEMENT_WRAPPER_FIELD_NAME, ConfigDef.Type.STRING, ConfigDef.Importance.HIGH, "The name of the wrapper field around each array element.");
+  public static final ConfigDef CONFIG_DEF =
+      new ConfigDef()
+          .define(
+              ARRAY_FIELD_NAME,
+              ConfigDef.Type.STRING,
+              ConfigDef.Importance.HIGH,
+              "The name of the root level array field.")
+          .define(
+              ARRAY_INNER_WRAPPER_FIELD_NAME,
+              ConfigDef.Type.STRING,
+              ConfigDef.Importance.HIGH,
+              "The name of the inner array wrapper field.")
+          .define(
+              ARRAY_ELEMENT_WRAPPER_FIELD_NAME,
+              ConfigDef.Type.STRING,
+              ConfigDef.Importance.HIGH,
+              "The name of the wrapper field around each array element.");
 
   private String arrayFieldName;
   private String innerWrapperFieldName;
@@ -76,7 +107,14 @@ public void configure(Map configs) {
   public R apply(R record) {
     Schema schema = convertSchema(record.valueSchema());
     Object value = convertValue(schema, record.value());
-    return record.newRecord(record.topic(), record.kafkaPartition(), record.keySchema(), record.key(), schema, value, record.timestamp());
+    return record.newRecord(
+        record.topic(),
+        record.kafkaPartition(),
+        record.keySchema(),
+        record.key(),
+        schema,
+        value,
+        record.timestamp());
   }
 
   @Override
@@ -85,8 +123,7 @@ public ConfigDef config() {
   }
 
   @Override
-  public void close() {
-  }
+  public void close() {}
 
   private Field getArrayElementField(Schema schema) {
     if (schema == null) {
@@ -110,7 +147,8 @@ private Field getArrayElementField(Schema schema) {
     if (innerElementField == null) {
       throw new DataException("Missing array element field: '" + elementWrapperFieldName + "'");
     } else if (innerElementField.schema().type() != Schema.Type.STRUCT) {
-      throw new DataException("Array element wrapper: '" + elementWrapperFieldName + "' is not a struct");
+      throw new DataException(
+          "Array element wrapper: '" + elementWrapperFieldName + "' is not a struct");
     }
     return innerElementField;
   }
diff --git a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/wrappers/BigtableTableAdminClientInterface.java b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/wrappers/BigtableTableAdminClientInterface.java
index dda12d48..81283c55 100644
--- a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/wrappers/BigtableTableAdminClientInterface.java
+++ b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/wrappers/BigtableTableAdminClientInterface.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2026 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.cloud.kafka.connect.bigtable.wrappers;
 
 import com.google.api.core.ApiFuture;
@@ -6,7 +21,6 @@
 import com.google.cloud.bigtable.admin.v2.models.Table;
 import java.util.List;
 
-
 /**
  * This is an interface for com.google.cloud.bigtable.admin.v2.BigtableTableAdminClient which makes
  * mocking easier.
@@ -28,5 +42,4 @@ public interface BigtableTableAdminClientInterface {
   Table modifyFamilies(ModifyColumnFamiliesRequest request);
 
   void close();
-
 }
diff --git a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/wrappers/BigtableTableAdminClientWrapper.java b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/wrappers/BigtableTableAdminClientWrapper.java
index 25665f1a..87241ca9 100644
--- a/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/wrappers/BigtableTableAdminClientWrapper.java
+++ b/kafka-connect-bigtable-sink/sink/src/main/java/com/google/cloud/kafka/connect/bigtable/wrappers/BigtableTableAdminClientWrapper.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2026 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.cloud.kafka.connect.bigtable.wrappers;
 
 import com.google.api.core.ApiFuture;
diff --git a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/BigtableSinkConnectorTest.java b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/BigtableSinkConnectorTest.java
index d5a177d4..9d04c010 100644
--- a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/BigtableSinkConnectorTest.java
+++ b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/BigtableSinkConnectorTest.java
@@ -18,14 +18,11 @@
 import static com.google.cloud.kafka.connect.bigtable.config.BigtableSinkTaskConfig.TASK_ID_CONFIG;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
 
 import com.google.cloud.kafka.connect.bigtable.util.BasicPropertiesFactory;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.ServiceLoader;
-import org.apache.kafka.connect.sink.SinkConnector;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/BigtableSinkTaskTest.java b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/BigtableSinkTaskTest.java
index 523af9a4..799c6abd 100644
--- a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/BigtableSinkTaskTest.java
+++ b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/BigtableSinkTaskTest.java
@@ -15,6 +15,32 @@
  */
 package com.google.cloud.kafka.connect.bigtable;
 
+import static com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig.*;
+import static com.google.cloud.kafka.connect.bigtable.util.FutureUtil.completedApiFuture;
+import static com.google.cloud.kafka.connect.bigtable.util.FutureUtil.failedApiFuture;
+import static com.google.cloud.kafka.connect.bigtable.util.MockUtil.assertTotalNumberOfInvocations;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.argThat;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.MockitoAnnotations.openMocks;
+
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -43,6 +69,13 @@
 import com.google.cloud.kafka.connect.bigtable.wrappers.BigtableTableAdminClientInterface;
 import com.google.common.collect.Collections2;
 import com.google.protobuf.ByteString;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 import org.apache.kafka.common.record.TimestampType;
 import org.apache.kafka.connect.data.Schema;
 import org.apache.kafka.connect.data.SchemaBuilder;
@@ -58,40 +91,18 @@
 import org.mockito.Mock;
 import org.slf4j.Logger;
 
-import java.nio.charset.StandardCharsets;
-import java.util.*;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-
-import static com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig.*;
-import static com.google.cloud.kafka.connect.bigtable.util.FutureUtil.completedApiFuture;
-import static com.google.cloud.kafka.connect.bigtable.util.MockUtil.assertTotalNumberOfInvocations;
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.*;
-import static org.mockito.MockitoAnnotations.openMocks;
-
 @RunWith(JUnit4.class)
 public class BigtableSinkTaskTest {
 
   TestBigtableSinkTask task;
   BigtableSinkTaskConfig config;
-  @Mock
-  BigtableDataClient bigtableData;
-  @Mock
-  BigtableTableAdminClientInterface bigtableAdmin;
-  @Mock
-  KeyMapper keyMapper;
-  @Mock
-  ValueMapper valueMapper;
-  @Mock
-  BigtableSchemaManager schemaManager;
-  @Mock
-  SinkTaskContext context;
-  @Mock
-  ErrantRecordReporter errorReporter;
+  @Mock BigtableDataClient bigtableData;
+  @Mock BigtableTableAdminClientInterface bigtableAdmin;
+  @Mock KeyMapper keyMapper;
+  @Mock ValueMapper valueMapper;
+  @Mock BigtableSchemaManager schemaManager;
+  @Mock SinkTaskContext context;
+  @Mock ErrantRecordReporter errorReporter;
 
   @Before
   public void setUp() {
@@ -173,17 +184,16 @@ public void testCreateRecordMutationDataNonemptyKey() {
     assertTrue(task.createRecordMutationData(okRecord).isPresent());
   }
 
-  private final Schema valueSchema = SchemaBuilder.struct()
-      .name("com.example.User")
-      .field("id", Schema.INT32_SCHEMA)
-      .field("name", Schema.STRING_SCHEMA)
-      .build();
+  private final Schema valueSchema =
+      SchemaBuilder.struct()
+          .name("com.example.User")
+          .field("id", Schema.INT32_SCHEMA)
+          .field("name", Schema.STRING_SCHEMA)
+          .build();
 
   @Test
   public void testCreateRecordMutationData() throws JsonProcessingException {
-    Struct value = new Struct(valueSchema)
-        .put("id", 42)
-        .put("name", "John Doe");
+    Struct value = new Struct(valueSchema).put("id", 42).put("name", "John Doe");
     SinkRecord okRecord = new SinkRecord("topic", 1, null, "key", valueSchema, value, 2);
 
     keyMapper = new KeyMapper("#", List.of());
@@ -196,16 +206,22 @@ public void testCreateRecordMutationData() throws JsonProcessingException {
 
     ObjectMapper mapper = new ObjectMapper();
     JsonNode actual = mapper.readTree(proto);
-    assertEquals("projects/project/instances/instance/tables/topic", actual.get("tableName").asText());
+    assertEquals(
+        "projects/project/instances/instance/tables/topic", actual.get("tableName").asText());
     assertEquals("a2V5", actual.get("rowKey").asText());
     ArrayNode mutations = (ArrayNode) actual.get("mutations");
     assertEquals(2, mutations.size());
     assertEquals("default", mutations.get(0).get("setCell").get("familyName").textValue());
-    assertEquals("id", ProtoUtil.fromBase64(mutations.get(0).get("setCell").get("columnQualifier").textValue()));
+    assertEquals(
+        "id",
+        ProtoUtil.fromBase64(mutations.get(0).get("setCell").get("columnQualifier").textValue()));
     assertEquals(ProtoUtil.toBase64(42), mutations.get(0).get("setCell").get("value").textValue());
     assertEquals("default", mutations.get(1).get("setCell").get("familyName").textValue());
-    assertEquals("name", ProtoUtil.fromBase64(mutations.get(1).get("setCell").get("columnQualifier").textValue()));
-    assertEquals(ProtoUtil.toBase64("John Doe"), mutations.get(1).get("setCell").get("value").textValue());
+    assertEquals(
+        "name",
+        ProtoUtil.fromBase64(mutations.get(1).get("setCell").get("columnQualifier").textValue()));
+    assertEquals(
+        ProtoUtil.toBase64("John Doe"), mutations.get(1).get("setCell").get("value").textValue());
   }
 
   @Test
@@ -452,7 +468,7 @@ public void testInsertRows() throws ExecutionException, InterruptedException {
     doReturn(ByteString.copyFrom("ignored".getBytes(StandardCharsets.UTF_8)))
         .when(commonMutationData)
         .getRowKey();
-    doReturn(Mutation.create()).when(commonMutationData).getInsertMutation();
+    doReturn(Mutation.create()).when(commonMutationData).getMutation();
 
     // LinkedHashMap, because we mock consecutive return values of Bigtable client mock and thus
     // rely on the order.
@@ -484,11 +500,11 @@ public void testUpsertRows() {
     String batcherTable = "batcherTable";
     Batcher batcher = mock(Batcher.class);
     doAnswer(
-        invocation -> {
-          TestBigtableSinkTask task = (TestBigtableSinkTask) invocation.getMock();
-          task.getBatchers().computeIfAbsent(batcherTable, ignored -> batcher);
-          return null;
-        })
+            invocation -> {
+              TestBigtableSinkTask task = (TestBigtableSinkTask) invocation.getMock();
+              task.getBatchers().computeIfAbsent(batcherTable, ignored -> batcher);
+              return null;
+            })
         .when(task)
         .performUpsertBatch(any(), any());
 
@@ -532,10 +548,10 @@ public void testPerformUpsertBatch() throws ExecutionException, InterruptedExcep
 
     MutationData okMutationData = mock(MutationData.class);
     doReturn(okTable).when(okMutationData).getTargetTable();
-    doReturn(mock(RowMutationEntry.class)).when(okMutationData).getUpsertMutation();
+    doReturn(mock(RowMutationEntry.class)).when(okMutationData).getRowMutationEntry();
     MutationData errorMutationData = mock(MutationData.class);
     doReturn(errorTable).when(errorMutationData).getTargetTable();
-    doReturn(mock(RowMutationEntry.class)).when(errorMutationData).getUpsertMutation();
+    doReturn(mock(RowMutationEntry.class)).when(errorMutationData).getRowMutationEntry();
 
     Map input =
         Map.of(
@@ -561,45 +577,128 @@ public void testPerformUpsertBatch() throws ExecutionException, InterruptedExcep
     assertThrows(ExecutionException.class, () -> output.get(errorRecord).get());
   }
 
+  @Test
+  public void testReplaceRows() {
+    Map props = BasicPropertiesFactory.getTaskProps();
+    int maxBatchSize = 3;
+    int totalRecords = 1000;
+    props.put(BigtableSinkTaskConfig.MAX_BATCH_SIZE_CONFIG, Integer.toString(maxBatchSize));
+    BigtableSinkTaskConfig config = new BigtableSinkTaskConfig(props);
+
+    task = spy(new TestBigtableSinkTask(config, null, null, null, null, null, null));
+    MutationData commonMutationData = mock(MutationData.class);
+    doNothing().when(task).performReplaceBatch(any(), any());
+
+    Map input =
+        IntStream.range(0, totalRecords)
+            .mapToObj(i -> new SinkRecord("", 1, null, null, null, null, i))
+            .collect(Collectors.toMap(i -> i, ignored -> commonMutationData));
+
+    Map> fakeMutationData = mock(Map.class);
+    task.replaceRows(input, fakeMutationData);
+
+    int expectedFullBatches = totalRecords / maxBatchSize;
+    int expectedPartialBatches = totalRecords % maxBatchSize == 0 ? 0 : 1;
+    int replaceRowsCalls = 1;
+
+    verify(task, times(expectedFullBatches))
+        .performReplaceBatch(argThat(v -> v.size() == maxBatchSize), any());
+    verify(task, times(expectedPartialBatches))
+        .performReplaceBatch(argThat(v -> v.size() != maxBatchSize), any());
+    assertTotalNumberOfInvocations(
+        task, expectedFullBatches + expectedPartialBatches + replaceRowsCalls);
+  }
+
+  @Test
+  public void testPerformReplaceBatch() throws ExecutionException, InterruptedException {
+    ApiException exception = ApiExceptionFactory.create();
+    doReturn(completedApiFuture(false))
+        .doReturn(completedApiFuture(true))
+        .doReturn(failedApiFuture(exception))
+        .when(bigtableData)
+        .checkAndMutateRowAsync(any());
+    task = new TestBigtableSinkTask(null, bigtableData, null, null, null, null, null);
+
+    SinkRecord falseRecord = new SinkRecord("", 1, null, null, null, null, 1);
+    SinkRecord trueRecord = new SinkRecord("", 1, null, null, null, null, 2);
+    SinkRecord exceptionRecord = new SinkRecord("", 1, null, null, null, null, 3);
+
+    MutationData commonMutationData = mock(MutationData.class);
+    doReturn("ignored").when(commonMutationData).getTargetTable();
+    doReturn(ByteString.copyFrom("ignored".getBytes(StandardCharsets.UTF_8)))
+        .when(commonMutationData)
+        .getRowKey();
+    doReturn(0L).when(commonMutationData).getTimestampMicros();
+    doReturn(Mutation.create()).when(commonMutationData).getMutation();
+
+    // LinkedHashMap, because we mock consecutive return values of Bigtable client mock and thus
+    // rely on the order.
+    Map input = new LinkedHashMap<>();
+    input.put(falseRecord, commonMutationData);
+    input.put(trueRecord, commonMutationData);
+    input.put(exceptionRecord, commonMutationData);
+
+    Map> output = new HashMap<>();
+    task.performReplaceBatch(new ArrayList<>(input.entrySet()), output);
+    output.get(falseRecord).get();
+    output.get(trueRecord).get();
+    assertThrows(ExecutionException.class, () -> output.get(exceptionRecord).get());
+  }
+
+  private static class PutBranchesTestCase {
+    public final boolean autoCreateTables;
+    public final boolean autoCreateColumnFamilies;
+    public final InsertMode insertMode;
+
+    public PutBranchesTestCase(
+        boolean autoCreateTables, boolean autoCreateColumnFamilies, InsertMode insertMode) {
+      this.autoCreateTables = autoCreateTables;
+      this.autoCreateColumnFamilies = autoCreateColumnFamilies;
+      this.insertMode = insertMode;
+    }
+  }
+
   @Test
   public void testPutBranches() {
     SinkRecord record1 = new SinkRecord("table1", 1, null, null, null, null, 1);
     SinkRecord record2 = new SinkRecord("table2", 1, null, null, null, null, 2);
 
-    for (List test :
+    for (PutBranchesTestCase testCase :
         List.of(
-            List.of(false, false, false),
-            List.of(false, false, true),
-            List.of(false, true, false),
-            List.of(false, true, true),
-            List.of(true, false, false),
-            List.of(true, false, true),
-            List.of(true, true, false),
-            List.of(true, true, true))) {
-      boolean autoCreateTables = test.get(0);
-      boolean autoCreateColumnFamilies = test.get(1);
-      boolean useInsertMode = test.get(2);
-
+            new PutBranchesTestCase(false, false, InsertMode.INSERT),
+            new PutBranchesTestCase(false, true, InsertMode.INSERT),
+            new PutBranchesTestCase(true, false, InsertMode.INSERT),
+            new PutBranchesTestCase(true, true, InsertMode.INSERT),
+            new PutBranchesTestCase(false, false, InsertMode.UPSERT),
+            new PutBranchesTestCase(false, true, InsertMode.UPSERT),
+            new PutBranchesTestCase(true, false, InsertMode.UPSERT),
+            new PutBranchesTestCase(true, true, InsertMode.UPSERT),
+            new PutBranchesTestCase(false, false, InsertMode.REPLACE_IF_NEWEST),
+            new PutBranchesTestCase(false, true, InsertMode.REPLACE_IF_NEWEST),
+            new PutBranchesTestCase(true, false, InsertMode.REPLACE_IF_NEWEST),
+            new PutBranchesTestCase(true, true, InsertMode.REPLACE_IF_NEWEST))) {
       Map props = BasicPropertiesFactory.getTaskProps();
-      props.put(AUTO_CREATE_TABLES_CONFIG, Boolean.toString(autoCreateTables));
-      props.put(AUTO_CREATE_COLUMN_FAMILIES_CONFIG, Boolean.toString(autoCreateColumnFamilies));
-      props.put(INSERT_MODE_CONFIG, (useInsertMode ? InsertMode.INSERT : InsertMode.UPSERT).name());
+      props.put(AUTO_CREATE_TABLES_CONFIG, Boolean.toString(testCase.autoCreateTables));
+      props.put(
+          AUTO_CREATE_COLUMN_FAMILIES_CONFIG, Boolean.toString(testCase.autoCreateColumnFamilies));
+      props.put(INSERT_MODE_CONFIG, testCase.insertMode.name());
       config = new BigtableSinkTaskConfig(props);
 
       byte[] rowKey = "rowKey".getBytes(StandardCharsets.UTF_8);
       doReturn(rowKey).when(keyMapper).getKey(any());
       doAnswer(
-          i -> {
-            MutationDataBuilder builder = new MutationDataBuilder();
-            builder.deleteRow();
-            return builder;
-          })
+              i -> {
+                MutationDataBuilder builder = new MutationDataBuilder(0);
+                builder.deleteRow();
+                return builder;
+              })
           .when(valueMapper)
-          .getRecordMutationDataBuilder(any(), anyString(), anyLong());
+          .getRecordMutationDataBuilder(any(), anyString(), any(), anyLong());
 
       Batcher batcher = mock(Batcher.class);
       doReturn(completedApiFuture(null)).when(batcher).add(any());
       doReturn(batcher).when(bigtableData).newBulkMutationBatcher(anyString());
+      doReturn(completedApiFuture(true)).when(bigtableData).checkAndMutateRowAsync(any());
       doReturn(new ResourceCreationResult(Collections.emptySet(), Collections.emptySet()))
           .when(schemaManager)
           .ensureTablesExist(any());
@@ -615,11 +714,15 @@ public void testPutBranches() {
       task.put(List.of(record1, record2));
 
       verify(task, times(1)).prepareRecords(any());
-      verify(schemaManager, times(autoCreateTables ? 1 : 0)).ensureTablesExist(any());
-      verify(schemaManager, times(autoCreateColumnFamilies ? 1 : 0))
+      verify(schemaManager, times(testCase.autoCreateTables ? 1 : 0)).ensureTablesExist(any());
+      verify(schemaManager, times(testCase.autoCreateColumnFamilies ? 1 : 0))
           .ensureColumnFamiliesExist(any());
-      verify(task, times(useInsertMode ? 1 : 0)).insertRows(any(), any());
-      verify(task, times(useInsertMode ? 0 : 1)).upsertRows(any(), any());
+      verify(task, times(testCase.insertMode == InsertMode.INSERT ? 1 : 0))
+          .insertRows(any(), any());
+      verify(task, times(testCase.insertMode == InsertMode.UPSERT ? 1 : 0))
+          .upsertRows(any(), any());
+      verify(task, times(testCase.insertMode == InsertMode.REPLACE_IF_NEWEST ? 1 : 0))
+          .replaceRows(any(), any());
       verify(task, times(1)).handleResults(any());
 
       reset(task);
diff --git a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/autocreate/BigtableSchemaManagerTest.java b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/autocreate/BigtableSchemaManagerTest.java
index dfbd7319..22e36179 100644
--- a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/autocreate/BigtableSchemaManagerTest.java
+++ b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/autocreate/BigtableSchemaManagerTest.java
@@ -22,8 +22,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.argThat;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
@@ -36,8 +34,6 @@
 import static org.mockito.Mockito.verifyNoInteractions;
 
 import com.google.api.core.ApiFuture;
-import com.google.bigtable.admin.v2.GcRule;
-import com.google.cloud.bigtable.admin.v2.models.ColumnFamily;
 import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest;
 import com.google.cloud.bigtable.admin.v2.models.GCRules;
 import com.google.cloud.bigtable.admin.v2.models.ModifyColumnFamiliesRequest;
@@ -442,15 +438,15 @@ public void testEnsureColumnFamiliesExistAllCreatedSuccessfully() {
     int expectedBigtableInteractions =
         1 // listTables()
             + tablesAndColumnFamilies.values().stream()
-            .mapToInt(Set::size)
-            .sum() // modifyColumnFamily()
+                .mapToInt(Set::size)
+                .sum() // modifyColumnFamily()
             + tablesAndColumnFamilies.keySet().size(); // getTable()
     assertTotalNumberOfInvocations(bigtable, expectedBigtableInteractions);
   }
 
   @Test
   public void
-  testEnsureColumnFamiliesExistSomeCreatedSuccessfullySomeErrorsDueToRacesOrInvalidRequests() {
+      testEnsureColumnFamiliesExistSomeCreatedSuccessfullySomeErrorsDueToRacesOrInvalidRequests() {
     String successTable = "table1";
     String bigtableErrorTable = "table2";
     String dataErrorTable = "table3";
@@ -516,8 +512,8 @@ public void testEnsureColumnFamiliesExistAllCreatedSuccessfully() {
     int expectedBigtableInteractions =
         1 // listTables()
             + tablesAndColumnFamilies.values().stream()
-            .mapToInt(Set::size)
-            .sum() // modifyColumnFamily()
+                .mapToInt(Set::size)
+                .sum() // modifyColumnFamily()
             + tablesAndColumnFamilies.keySet().size(); // getTable()
     assertTotalNumberOfInvocations(bigtable, expectedBigtableInteractions);
   }
@@ -570,8 +566,8 @@ public void testEnsureColumnFamiliesExistSomeSomeErrorsDueToConcurrentColumnFami
     int expectedBigtableInteractions =
         1 // listTables()
             + tablesAndColumnFamilies.values().stream()
-            .mapToInt(Set::size)
-            .sum() // modifyColumnFamily()
+                .mapToInt(Set::size)
+                .sum() // modifyColumnFamily()
             + tablesAndColumnFamilies.keySet().size(); // getTable()
     assertTotalNumberOfInvocations(bigtable, expectedBigtableInteractions);
   }
@@ -628,8 +624,8 @@ public void testEnsureColumnFamiliesExistMissingTable() {
     int expectedBigtableInteractions =
         1 // listTables()
             + tablesAndColumnFamilies.values().stream()
-            .mapToInt(Set::size)
-            .sum() // modifyColumnFamily()
+                .mapToInt(Set::size)
+                .sum() // modifyColumnFamily()
             + 1; // getTable()
     assertTotalNumberOfInvocations(bigtable, expectedBigtableInteractions);
   }
@@ -652,8 +648,10 @@ public void testAwaitResourceCreationAndHandleInvalidInputErrors() {
 
     Map, ResourceAndRecords> input =
         Map.of(
-            completedApiFuture(null), ok,
-            failedApiFuture(ApiExceptionFactory.create(Status.Code.INVALID_ARGUMENT)), dataError,
+            completedApiFuture(null),
+            ok,
+            failedApiFuture(ApiExceptionFactory.create(Status.Code.INVALID_ARGUMENT)),
+            dataError,
             failedApiFuture(ApiExceptionFactory.create(Status.Code.RESOURCE_EXHAUSTED)),
             bigtableError);
 
@@ -680,7 +678,7 @@ private static SinkRecord spoofSinkRecord(String topic, int uniqueKafkaOffset) {
 
   private static MutationData spoofSinkRecordOutput(
       String targetTable, Set columnFamilies) {
-    return new MutationData(targetTable, null, null, columnFamilies);
+    return new MutationData(targetTable, null, null, columnFamilies, 0);
   }
 
   private boolean createTableMockRefersTable(String tableName, CreateTableRequest ctr) {
@@ -700,13 +698,14 @@ private boolean createColumnFamilyMockRefersTableAndColumnFamily(
         mcfr.toProto("unused", "unused").getModificationsList();
     return refersTable
         && modifications.stream()
-        .filter(
-            com.google.bigtable.admin.v2.ModifyColumnFamiliesRequest.Modification::hasCreate)
-        .anyMatch(m -> columnFamily.equals(m.getId()));
+            .filter(
+                com.google.bigtable.admin.v2.ModifyColumnFamiliesRequest.Modification::hasCreate)
+            .anyMatch(m -> columnFamily.equals(m.getId()));
   }
 
   private void mockCreateTableSuccess(
-      BigtableTableAdminClientInterface bigtable, String tableName,
+      BigtableTableAdminClientInterface bigtable,
+      String tableName,
       Set tableColumnFamilies) {
     Table table = mockTable(tableName, tableColumnFamilies);
     doAnswer(ignored -> completedApiFuture(table))
@@ -715,7 +714,8 @@ private void mockCreateTableSuccess(
   }
 
   private void mockCreateColumnFamilySuccess(
-      BigtableTableAdminClientInterface bigtable, String tableName,
+      BigtableTableAdminClientInterface bigtable,
+      String tableName,
       Set tableColumnFamilies) {
     Table table = mockTable(tableName, tableColumnFamilies);
     doAnswer(ignored -> completedApiFuture(table))
@@ -724,7 +724,8 @@ private void mockCreateColumnFamilySuccess(
   }
 
   private void mockGetTableSuccess(
-      BigtableTableAdminClientInterface bigtable, String tableName,
+      BigtableTableAdminClientInterface bigtable,
+      String tableName,
       Set tableColumnFamilies) {
     Table table = mockTable(tableName, tableColumnFamilies);
     doAnswer(ignored -> completedApiFuture(table)).when(bigtable).getTableAsync(tableName);
@@ -733,11 +734,13 @@ private void mockGetTableSuccess(
   private Table mockTable(String tableName, Set tableColumnFamilies) {
     com.google.bigtable.admin.v2.Table.Builder builder =
         com.google.bigtable.admin.v2.Table.newBuilder()
-            .setName("projects/unused/instances/unused/tables/"+tableName);
+            .setName("projects/unused/instances/unused/tables/" + tableName);
     for (String tableColumnFamily : tableColumnFamilies) {
       GCRules.GCRule gcRule = GCRULES.maxVersions(1);
-      com.google.bigtable.admin.v2.ColumnFamily columnFamily = com.google.bigtable.admin.v2.ColumnFamily.newBuilder()
-          .setGcRule(gcRule.toProto()).build();
+      com.google.bigtable.admin.v2.ColumnFamily columnFamily =
+          com.google.bigtable.admin.v2.ColumnFamily.newBuilder()
+              .setGcRule(gcRule.toProto())
+              .build();
       builder.putColumnFamilies(tableColumnFamily, columnFamily);
     }
 
diff --git a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/mapping/KeyMapperTest.java b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/mapping/KeyMapperTest.java
index 5d48efa1..59650242 100644
--- a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/mapping/KeyMapperTest.java
+++ b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/mapping/KeyMapperTest.java
@@ -596,7 +596,7 @@ public void testStringArray() {
   @Test
   public void testBytes() {
     final String fieldName = "Bytes";
-    final byte[] fieldBytes = new byte[]{42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54};
+    final byte[] fieldBytes = new byte[] {42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54};
     final ByteBuffer fieldValueKafkaConnect = ByteBuffer.wrap(fieldBytes);
     Schema kafkaConnectSchema =
         SchemaBuilder.struct().field(fieldName, Schema.BYTES_SCHEMA).build();
@@ -788,25 +788,25 @@ public void testSchemalessRecordSuccesses() {
         List.of(
             // Default key definition and all kinds of types.
             // Note that logical types cannot be used without schema.
-            new Object[]{List.of(), "2.130", "2.13"},
-            new Object[]{List.of(), "7", "7"},
-            new Object[]{List.of(), "\"x\"", "x"},
-            new Object[]{List.of(), "true", "true"},
-            new Object[]{List.of(), "[]", "[]"},
-            new Object[]{List.of(), "[1,\"s\",true]", "[1, s, true]"},
+            new Object[] {List.of(), "2.130", "2.13"},
+            new Object[] {List.of(), "7", "7"},
+            new Object[] {List.of(), "\"x\"", "x"},
+            new Object[] {List.of(), "true", "true"},
+            new Object[] {List.of(), "[]", "[]"},
+            new Object[] {List.of(), "[1,\"s\",true]", "[1, s, true]"},
             // Default key definition when using on a map (schemaless data is converted into a Map
             // rather than a Struct, so its fields are not accessed when serializing!).
-            new Object[]{List.of(), "{\"a\":1,\"b\":true,\"c\":\"str\"}", "{a=1, b=true, c=str}"},
-            new Object[]{List.of(), "{\"b\":1,\"a\":3}", "{a=3, b=1}"},
-            new Object[]{
-                List.of(),
-                "{\"b\":[1,2],\"a\":3,\"c\":{\"x\":\"D\",\"y\":2137}}",
-                "{a=3, b=[1, 2], c={x=D, y=2137}}"
+            new Object[] {List.of(), "{\"a\":1,\"b\":true,\"c\":\"str\"}", "{a=1, b=true, c=str}"},
+            new Object[] {List.of(), "{\"b\":1,\"a\":3}", "{a=3, b=1}"},
+            new Object[] {
+              List.of(),
+              "{\"b\":[1,2],\"a\":3,\"c\":{\"x\":\"D\",\"y\":2137}}",
+              "{a=3, b=[1, 2], c={x=D, y=2137}}"
             }
             // Note that there are no tests for accessing fields of the values. Maps, to which
             // schemaless JSON data deserializes when using JsonConverter, does not support
             // accessing its values by keys.
-        )) {
+            )) {
       KeyMapper mapper = new KeyMapper(delimiter, (List) testCase[0]);
       SchemaAndValue connectData =
           jsonConverter.toConnectData(
diff --git a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/mapping/MutationDataBuilderTest.java b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/mapping/MutationDataBuilderTest.java
index 33bfb80d..d47ea80c 100644
--- a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/mapping/MutationDataBuilderTest.java
+++ b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/mapping/MutationDataBuilderTest.java
@@ -17,6 +17,9 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import com.google.cloud.bigtable.data.v2.models.Mutation;
 import com.google.cloud.bigtable.data.v2.models.Range;
@@ -40,17 +43,18 @@ public class MutationDataBuilderTest {
       ByteString.copyFrom("COLUMN".getBytes(StandardCharsets.UTF_8));
   private static final ByteString VALUE =
       ByteString.copyFrom("VALUE".getBytes(StandardCharsets.UTF_8));
-  private static final Long TIMESTAMP = 2024L;
+  private static final Long TIMESTAMP = 100000L;
+  private static final Long TIMESTAMP_END = 2024L;
   private static final Range.TimestampRange TIMESTAMP_RANGE =
-      Range.TimestampRange.create(0, TIMESTAMP);
+      Range.TimestampRange.create(0, TIMESTAMP_END);
 
   Mutation mutation;
   MutationDataBuilder mutationDataBuilder;
 
   @Before
   public void setUp() {
-    mutation = Mutation.create();
-    mutationDataBuilder = new MutationDataBuilder(mutation);
+    mutation = spy(Mutation.create());
+    mutationDataBuilder = new MutationDataBuilder(mutation, TIMESTAMP);
   }
 
   @Test
@@ -66,6 +70,7 @@ public void testDeleteRow() {
         mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
     assertTrue(mutationData.isPresent());
     assertTrue(mutationData.get().getRequiredColumnFamilies().isEmpty());
+    verify(mutation, times(1)).deleteRow();
   }
 
   @Test
@@ -76,6 +81,7 @@ public void testDeleteCells() {
         mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
     assertTrue(mutationData.isPresent());
     assertEquals(Set.of(COLUMN_FAMILY), mutationData.get().getRequiredColumnFamilies());
+    verify(mutation, times(1)).deleteCells(COLUMN_FAMILY, COLUMN_QUALIFIER, TIMESTAMP_RANGE);
   }
 
   @Test
@@ -87,15 +93,17 @@ public void testDeleteFamily() {
 
     assertTrue(mutationData.isPresent());
     assertEquals(Set.of(COLUMN_FAMILY), mutationData.get().getRequiredColumnFamilies());
+    verify(mutation, times(1)).deleteFamily(COLUMN_FAMILY);
   }
 
   @Test
   public void testSetCell() {
-    mutationDataBuilder.setCell(COLUMN_FAMILY, COLUMN_QUALIFIER, TIMESTAMP, VALUE);
+    mutationDataBuilder.setCell(COLUMN_FAMILY, COLUMN_QUALIFIER, VALUE);
 
     Optional mutationData =
         mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
     assertTrue(mutationData.isPresent());
     assertEquals(Set.of(COLUMN_FAMILY), mutationData.get().getRequiredColumnFamilies());
+    verify(mutation, times(1)).setCell(COLUMN_FAMILY, COLUMN_QUALIFIER, TIMESTAMP, VALUE);
   }
 }
diff --git a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/mapping/ValueMapperTest.java b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/mapping/ValueMapperTest.java
index b0b948cf..74c0e199 100644
--- a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/mapping/ValueMapperTest.java
+++ b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/mapping/ValueMapperTest.java
@@ -15,6 +15,16 @@
  */
 package com.google.cloud.kafka.connect.bigtable.mapping;
 
+import static com.google.cloud.kafka.connect.bigtable.util.MockUtil.assertTotalNumberOfInvocations;
+import static com.google.cloud.kafka.connect.bigtable.util.NestedNullStructFactory.NESTED_NULL_STRUCT_FIELD_NAME;
+import static com.google.cloud.kafka.connect.bigtable.util.NestedNullStructFactory.NESTED_NULL_STRUCT_FIELD_NAME_BYTES;
+import static com.google.cloud.kafka.connect.bigtable.util.NestedNullStructFactory.getStructWithNullOnNthNestingLevel;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -22,9 +32,21 @@
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.google.cloud.bigtable.data.v2.models.Range;
 import com.google.cloud.kafka.connect.bigtable.config.ConfigInterpolation;
+import com.google.cloud.kafka.connect.bigtable.config.InsertMode;
 import com.google.cloud.kafka.connect.bigtable.config.NullValueMode;
 import com.google.cloud.kafka.connect.bigtable.util.ProtoUtil;
+import com.google.cloud.kafka.connect.bigtable.utils.ByteUtils;
 import com.google.protobuf.ByteString;
+import java.math.BigDecimal;
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 import org.apache.kafka.connect.data.Schema;
 import org.apache.kafka.connect.data.SchemaAndValue;
 import org.apache.kafka.connect.data.SchemaBuilder;
@@ -33,18 +55,6 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.math.BigDecimal;
-import java.nio.charset.StandardCharsets;
-import java.time.Instant;
-import java.time.temporal.ChronoUnit;
-import java.util.*;
-
-import static com.google.cloud.kafka.connect.bigtable.util.MockUtil.assertTotalNumberOfInvocations;
-import static com.google.cloud.kafka.connect.bigtable.util.NestedNullStructFactory.*;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.*;
-
 @RunWith(JUnit4.class)
 public class ValueMapperTest {
 
@@ -68,7 +78,7 @@ public void testBoolean() {
         new TestValueMapper(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN, NullValueMode.IGNORE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, value);
     verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, TIMESTAMP, expected);
+        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, expected);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
 
@@ -80,7 +90,7 @@ public void testString() {
         new TestValueMapper(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN, NullValueMode.IGNORE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, value);
     verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, TIMESTAMP, expected);
+        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, expected);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
 
@@ -92,7 +102,7 @@ public void testLong() {
         new TestValueMapper(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN, NullValueMode.IGNORE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, value);
     verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, TIMESTAMP, expected);
+        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, expected);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
 
@@ -104,7 +114,7 @@ public void testInteger() {
         new TestValueMapper(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN, NullValueMode.IGNORE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, value);
     verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, TIMESTAMP, expected);
+        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, expected);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
 
@@ -116,7 +126,7 @@ public void testShort() {
         new TestValueMapper(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN, NullValueMode.IGNORE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, value);
     verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, TIMESTAMP, expected);
+        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, expected);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
 
@@ -128,19 +138,19 @@ public void testByte() {
         new TestValueMapper(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN, NullValueMode.IGNORE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, value);
     verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, TIMESTAMP, expected);
+        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, expected);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
 
   @Test
   public void testBytes() {
-    byte[] value = new byte[]{(byte) 37, (byte) 21};
+    byte[] value = new byte[] {(byte) 37, (byte) 21};
     ByteString expected = ByteString.copyFrom(value);
     ValueMapper mapper =
         new TestValueMapper(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN, NullValueMode.IGNORE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, value);
     verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, TIMESTAMP, expected);
+        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, expected);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
 
@@ -152,7 +162,7 @@ public void testFloat() {
         new TestValueMapper(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN, NullValueMode.IGNORE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, value);
     verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, TIMESTAMP, expected);
+        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, expected);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
 
@@ -164,7 +174,7 @@ public void testDouble() {
         new TestValueMapper(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN, NullValueMode.IGNORE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, value);
     verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, TIMESTAMP, expected);
+        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, expected);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
 
@@ -176,7 +186,7 @@ public void testDoubleSpecial() {
         new TestValueMapper(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN, NullValueMode.IGNORE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, value);
     verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, TIMESTAMP, expected);
+        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, expected);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
 
@@ -188,7 +198,7 @@ public void testDate() {
         new TestValueMapper(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN, NullValueMode.IGNORE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, date);
     verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, TIMESTAMP, expected);
+        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, expected);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
 
@@ -200,7 +210,7 @@ public void testDecimal() {
         new TestValueMapper(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN, NullValueMode.IGNORE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, value);
     verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, TIMESTAMP, expected);
+        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, expected);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
 
@@ -214,7 +224,6 @@ public void testArray() {
         .setCell(
             DEFAULT_COLUMN_FAMILY,
             DEFAULT_COLUMN_BYTES,
-            TIMESTAMP,
             ByteString.copyFrom("[\"1\",2,true]".getBytes(StandardCharsets.UTF_8)));
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
@@ -232,7 +241,6 @@ public void testRootValueNeedsBothDefaultColumns() {
           .setCell(
               DEFAULT_COLUMN_FAMILY,
               DEFAULT_COLUMN_BYTES,
-              TIMESTAMP,
               ByteString.copyFrom(ByteUtils.toBytes(value)));
     }
     ValueMapper mapper =
@@ -242,7 +250,6 @@ public void testRootValueNeedsBothDefaultColumns() {
         .setCell(
             DEFAULT_COLUMN_FAMILY,
             DEFAULT_COLUMN_BYTES,
-            TIMESTAMP,
             ByteString.copyFrom(ByteUtils.toBytes(value)));
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
@@ -254,13 +261,13 @@ public void testValueNestedOnceNeedsOnlyDefaultColumnFamily() {
     Struct struct = new Struct(SchemaBuilder.struct().field(key, Schema.INT64_SCHEMA));
     struct.put(key, value);
 
-    ValueMapper mapper = new TestValueMapper(DEFAULT_COLUMN_FAMILY, null, NullValueMode.WRITE, false);
+    ValueMapper mapper =
+        new TestValueMapper(DEFAULT_COLUMN_FAMILY, null, NullValueMode.WRITE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, struct);
     verify(mutationDataBuilder, times(1))
         .setCell(
             DEFAULT_COLUMN_FAMILY,
             ByteString.copyFrom(key.getBytes(StandardCharsets.UTF_8)),
-            TIMESTAMP,
             ByteString.copyFrom(ByteUtils.toBytes(value)));
 
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
@@ -270,13 +277,14 @@ public void testValueNestedOnceNeedsOnlyDefaultColumnFamily() {
   public void testDefaultColumnFamilyInterpolation() {
     String topic = "TOPIC";
     String value = "value";
-    ValueMapper mapper = new TestValueMapper("${topic}", DEFAULT_COLUMN, NullValueMode.WRITE, false);
-    MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, value, topic);
+    ValueMapper mapper =
+        new TestValueMapper("${topic}", DEFAULT_COLUMN, NullValueMode.WRITE, false);
+    MutationDataBuilder mutationDataBuilder =
+        getRecordMutationDataBuilder(mapper, value, topic, InsertMode.INSERT);
     verify(mutationDataBuilder, times(1))
         .setCell(
             topic,
             DEFAULT_COLUMN_BYTES,
-            TIMESTAMP,
             ByteString.copyFrom(value.getBytes(StandardCharsets.UTF_8)));
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
@@ -301,11 +309,11 @@ public void testMultipleOperationsAtOnce() {
             .put(deleteColumn, null);
     Struct struct =
         new Struct(
-            SchemaBuilder.struct()
-                .field(setColumnFamily, createStruct.schema())
-                .field(setRoot, Schema.BOOLEAN_SCHEMA)
-                .field(deleteColumnFamily, deleteStruct.schema())
-                .field(deleteRoot, Schema.OPTIONAL_INT8_SCHEMA))
+                SchemaBuilder.struct()
+                    .field(setColumnFamily, createStruct.schema())
+                    .field(setRoot, Schema.BOOLEAN_SCHEMA)
+                    .field(deleteColumnFamily, deleteStruct.schema())
+                    .field(deleteRoot, Schema.OPTIONAL_INT8_SCHEMA))
             .put(setColumnFamily, createStruct)
             .put(setRoot, rootValue)
             .put(deleteColumnFamily, deleteStruct)
@@ -318,13 +326,11 @@ public void testMultipleOperationsAtOnce() {
         .setCell(
             setColumnFamily,
             ByteString.copyFrom(setColumn.getBytes(StandardCharsets.UTF_8)),
-            TIMESTAMP,
             ByteString.copyFrom(ByteUtils.toBytes(value)));
     verify(mutationDataBuilder, times(1))
         .setCell(
             DEFAULT_COLUMN_FAMILY,
             ByteString.copyFrom(setRoot.getBytes(StandardCharsets.UTF_8)),
-            TIMESTAMP,
             ByteString.copyFrom(ByteUtils.toBytes(rootValue)));
     verify(mutationDataBuilder, times(1))
         .deleteCells(
@@ -369,8 +375,7 @@ public void testMap() throws JsonProcessingException {
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, outerMap);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
     verify(mutationDataBuilder, times(1))
-        .setCell(
-            DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, TIMESTAMP, expectedJsonificationBytes);
+        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, expectedJsonificationBytes);
   }
 
   @Test
@@ -390,15 +395,15 @@ public void testJsonificationOfNonJsonNativeTypes() {
 
     Struct structToBeJsonified =
         new Struct(
-            SchemaBuilder.struct()
-                .field(dateFieldName, org.apache.kafka.connect.data.Date.SCHEMA)
-                .field(timestampFieldName, org.apache.kafka.connect.data.Timestamp.SCHEMA)
-                .field(timeFieldName, org.apache.kafka.connect.data.Timestamp.SCHEMA)
-                .field(
-                    decimalFieldName,
-                    org.apache.kafka.connect.data.Decimal.schema(decimalScale))
-                .field(bytesFieldName, Schema.BYTES_SCHEMA)
-                .build())
+                SchemaBuilder.struct()
+                    .field(dateFieldName, org.apache.kafka.connect.data.Date.SCHEMA)
+                    .field(timestampFieldName, org.apache.kafka.connect.data.Timestamp.SCHEMA)
+                    .field(timeFieldName, org.apache.kafka.connect.data.Timestamp.SCHEMA)
+                    .field(
+                        decimalFieldName,
+                        org.apache.kafka.connect.data.Decimal.schema(decimalScale))
+                    .field(bytesFieldName, Schema.BYTES_SCHEMA)
+                    .build())
             .put(dateFieldName, date)
             .put(timestampFieldName, timestamp)
             .put(timeFieldName, time)
@@ -425,7 +430,6 @@ public void testJsonificationOfNonJsonNativeTypes() {
         .setCell(
             outerField,
             ByteString.copyFrom(innerField.getBytes(StandardCharsets.UTF_8)),
-            TIMESTAMP,
             expectedStringificationBytes);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
   }
@@ -494,21 +498,20 @@ public void testStruct() {
         new TestValueMapper(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN, NullValueMode.DELETE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, struct);
     verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_COLUMN_FAMILY, valueFieldNameBytes, TIMESTAMP, ByteString.copyFrom(value));
+        .setCell(DEFAULT_COLUMN_FAMILY, valueFieldNameBytes, ByteString.copyFrom(value));
     verify(mutationDataBuilder, times(1)).deleteFamily(optionalFieldName);
     verify(mutationDataBuilder, times(1))
-        .setCell(structFieldName, valueFieldNameBytes, TIMESTAMP, ByteString.copyFrom(value));
+        .setCell(structFieldName, valueFieldNameBytes, ByteString.copyFrom(value));
     verify(mutationDataBuilder, times(1))
         .deleteCells(
             structFieldName, optionalFieldNameBytes, Range.TimestampRange.create(0, TIMESTAMP));
     verify(mutationDataBuilder, times(1))
-        .setCell(
-            structFieldName,
-            structFieldNameBytes,
-            TIMESTAMP,
-            expectedInnermostStringificationBytes);
+        .setCell(structFieldName, structFieldNameBytes, expectedInnermostStringificationBytes);
     assertTotalNumberOfInvocations(mutationDataBuilder, 5);
-    assertTrue(mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY).isPresent());
+    Optional maybeMutationData =
+        mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
+    assertTrue(maybeMutationData.isPresent());
+    assertEquals(TIMESTAMP.longValue(), maybeMutationData.get().getTimestampMicros());
   }
 
   @Test
@@ -541,10 +544,12 @@ public void testSimpleCase1() {
         .setCell(
             outerField,
             ByteString.copyFrom(innerField.getBytes(StandardCharsets.UTF_8)),
-            TIMESTAMP,
             ByteString.copyFrom(ByteUtils.toBytes(value)));
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
-    assertTrue(mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY).isPresent());
+    Optional maybeMutationData =
+        mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
+    assertTrue(maybeMutationData.isPresent());
+    assertEquals(TIMESTAMP.longValue(), maybeMutationData.get().getTimestampMicros());
   }
 
   @Test
@@ -570,10 +575,12 @@ public void testSimpleCase2() {
         .setCell(
             outerField,
             ByteString.copyFrom(middleField.getBytes(StandardCharsets.UTF_8)),
-            TIMESTAMP,
             ByteString.copyFrom(
                 ("{\"" + innerField + "\":" + value + "}").getBytes(StandardCharsets.UTF_8)));
-    assertTrue(mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY).isPresent());
+    Optional maybeMutationData =
+        mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
+    assertTrue(maybeMutationData.isPresent());
+    assertEquals(TIMESTAMP.longValue(), maybeMutationData.get().getTimestampMicros());
   }
 
   @Test
@@ -583,16 +590,19 @@ public void testSimpleCase3() {
     Struct struct =
         new Struct(SchemaBuilder.struct().field(field, Schema.INT32_SCHEMA)).put(field, value);
 
-    ValueMapper mapper = new TestValueMapper(DEFAULT_COLUMN_FAMILY, null, NullValueMode.IGNORE, false);
+    ValueMapper mapper =
+        new TestValueMapper(DEFAULT_COLUMN_FAMILY, null, NullValueMode.IGNORE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, struct);
     verify(mutationDataBuilder, times(1))
         .setCell(
             DEFAULT_COLUMN_FAMILY,
             ByteString.copyFrom(field.getBytes(StandardCharsets.UTF_8)),
-            TIMESTAMP,
             ByteString.copyFrom(ByteUtils.toBytes(value)));
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
-    assertTrue(mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY).isPresent());
+    Optional maybeMutationData =
+        mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
+    assertTrue(maybeMutationData.isPresent());
+    assertEquals(TIMESTAMP.longValue(), maybeMutationData.get().getTimestampMicros());
   }
 
   @Test
@@ -612,26 +622,26 @@ public void testComplicatedCase() {
 
     Struct innermostStruct =
         new Struct(
-            SchemaBuilder.struct()
-                .field(valueKey, Schema.STRING_SCHEMA)
-                .field(innermostNullKey, Schema.OPTIONAL_INT8_SCHEMA))
+                SchemaBuilder.struct()
+                    .field(valueKey, Schema.STRING_SCHEMA)
+                    .field(innermostNullKey, Schema.OPTIONAL_INT8_SCHEMA))
             .put(valueKey, value)
             .put(innermostNullKey, null);
     Struct innerStruct =
         new Struct(
-            SchemaBuilder.struct()
-                .field(innerStructKey, innermostStruct.schema())
-                .field(valueKey, Schema.STRING_SCHEMA)
-                .field(columnToBeDeleted, Schema.OPTIONAL_INT8_SCHEMA))
+                SchemaBuilder.struct()
+                    .field(innerStructKey, innermostStruct.schema())
+                    .field(valueKey, Schema.STRING_SCHEMA)
+                    .field(columnToBeDeleted, Schema.OPTIONAL_INT8_SCHEMA))
             .put(innerStructKey, innermostStruct)
             .put(valueKey, value)
             .put(columnToBeDeleted, null);
     Struct outerStruct =
         new Struct(
-            SchemaBuilder.struct()
-                .field(outerStructKey, innerStruct.schema())
-                .field(valueKey, Schema.STRING_SCHEMA)
-                .field(familyToBeDeleted, Schema.OPTIONAL_INT8_SCHEMA))
+                SchemaBuilder.struct()
+                    .field(outerStructKey, innerStruct.schema())
+                    .field(valueKey, Schema.STRING_SCHEMA)
+                    .field(familyToBeDeleted, Schema.OPTIONAL_INT8_SCHEMA))
             .put(outerStructKey, innerStruct)
             .put(valueKey, value)
             .put(familyToBeDeleted, null);
@@ -658,24 +668,46 @@ public void testComplicatedCase() {
         new TestValueMapper(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN, NullValueMode.DELETE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, outerStruct);
     verify(mutationDataBuilder, times(1)).deleteFamily(familyToBeDeleted);
-    verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_COLUMN_FAMILY, valueKeyBytes, TIMESTAMP, valueBytes);
+    verify(mutationDataBuilder, times(1)).setCell(DEFAULT_COLUMN_FAMILY, valueKeyBytes, valueBytes);
     verify(mutationDataBuilder, times(1))
         .deleteCells(
             outerStructKey.toString(),
             columnToBeDeletedBytes,
             Range.TimestampRange.create(0, TIMESTAMP));
     verify(mutationDataBuilder, times(1))
-        .setCell(outerStructKey.toString(), valueKeyBytes, TIMESTAMP, valueBytes);
+        .setCell(outerStructKey.toString(), valueKeyBytes, valueBytes);
     verify(mutationDataBuilder, times(1))
         .setCell(
             outerStructKey.toString(),
             ByteString.copyFrom(innerStructKey.toString().getBytes(StandardCharsets.UTF_8)),
-            TIMESTAMP,
             expectedJsonificationBytes);
     assertTotalNumberOfInvocations(mutationDataBuilder, 5);
   }
 
+  @Test
+  public void testCreateMutationDataBuilder() {
+    ValueMapper mapper =
+        new ValueMapper(DEFAULT_COLUMN, DEFAULT_COLUMN_FAMILY, NullValueMode.IGNORE, false);
+    assertTrue(
+        mapper
+            .createMutationDataBuilder(InsertMode.INSERT, TIMESTAMP)
+            .maybeBuild(TARGET_TABLE_NAME, ROW_KEY)
+            .isEmpty());
+    assertTrue(
+        mapper
+            .createMutationDataBuilder(InsertMode.UPSERT, TIMESTAMP)
+            .maybeBuild(TARGET_TABLE_NAME, ROW_KEY)
+            .isEmpty());
+
+    Optional maybeMutationData =
+        mapper
+            .createMutationDataBuilder(InsertMode.REPLACE_IF_NEWEST, TIMESTAMP)
+            .maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
+    // It's not empty, because it contains a deleteRow.
+    assertTrue(maybeMutationData.isPresent());
+    assertEquals(TIMESTAMP.longValue(), maybeMutationData.get().getTimestampMicros());
+  }
+
   @Test
   public void testNullModeIgnoreRoot() {
     ValueMapper mapper =
@@ -711,9 +743,12 @@ public void testNullModeWriteRoot() {
         new TestValueMapper(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN, NullValueMode.WRITE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, null);
     verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, TIMESTAMP, ByteString.empty());
+        .setCell(DEFAULT_COLUMN_FAMILY, DEFAULT_COLUMN_BYTES, ByteString.empty());
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
-    assertTrue(mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY).isPresent());
+    Optional maybeMutationData =
+        mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
+    assertTrue(maybeMutationData.isPresent());
+    assertEquals(TIMESTAMP.longValue(), maybeMutationData.get().getTimestampMicros());
   }
 
   @Test
@@ -723,13 +758,12 @@ public void testNullModeWriteNestedOnce() {
     MutationDataBuilder mutationDataBuilder =
         getRecordMutationDataBuilder(mapper, getStructWithNullOnNthNestingLevel(1));
     verify(mutationDataBuilder, times(1))
-        .setCell(
-            DEFAULT_COLUMN_FAMILY,
-            NESTED_NULL_STRUCT_FIELD_NAME_BYTES,
-            TIMESTAMP,
-            ByteString.empty());
+        .setCell(DEFAULT_COLUMN_FAMILY, NESTED_NULL_STRUCT_FIELD_NAME_BYTES, ByteString.empty());
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
-    assertTrue(mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY).isPresent());
+    Optional maybeMutationData =
+        mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
+    assertTrue(maybeMutationData.isPresent());
+    assertEquals(TIMESTAMP.longValue(), maybeMutationData.get().getTimestampMicros());
   }
 
   @Test
@@ -740,12 +774,12 @@ public void testNullModeWriteNestedTwice() {
         getRecordMutationDataBuilder(mapper, getStructWithNullOnNthNestingLevel(2));
     verify(mutationDataBuilder, times(1))
         .setCell(
-            NESTED_NULL_STRUCT_FIELD_NAME,
-            NESTED_NULL_STRUCT_FIELD_NAME_BYTES,
-            TIMESTAMP,
-            ByteString.empty());
+            NESTED_NULL_STRUCT_FIELD_NAME, NESTED_NULL_STRUCT_FIELD_NAME_BYTES, ByteString.empty());
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
-    assertTrue(mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY).isPresent());
+    Optional maybeMutationData =
+        mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
+    assertTrue(maybeMutationData.isPresent());
+    assertEquals(TIMESTAMP.longValue(), maybeMutationData.get().getTimestampMicros());
   }
 
   @Test
@@ -755,7 +789,10 @@ public void testNullModeDeleteRoot() {
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, null);
     verify(mutationDataBuilder, times(1)).deleteRow();
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
-    assertTrue(mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY).isPresent());
+    Optional maybeMutationData =
+        mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
+    assertTrue(maybeMutationData.isPresent());
+    assertEquals(TIMESTAMP.longValue(), maybeMutationData.get().getTimestampMicros());
   }
 
   @Test
@@ -766,7 +803,10 @@ public void testNullModeDeleteNestedOnce() {
         getRecordMutationDataBuilder(mapper, getStructWithNullOnNthNestingLevel(1));
     verify(mutationDataBuilder, times(1)).deleteFamily(NESTED_NULL_STRUCT_FIELD_NAME);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
-    assertTrue(mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY).isPresent());
+    Optional maybeMutationData =
+        mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
+    assertTrue(maybeMutationData.isPresent());
+    assertEquals(TIMESTAMP.longValue(), maybeMutationData.get().getTimestampMicros());
   }
 
   @Test
@@ -779,7 +819,10 @@ public void testNullModeDeleteNestedTwice() {
         .deleteCells(
             NESTED_NULL_STRUCT_FIELD_NAME, NESTED_NULL_STRUCT_FIELD_NAME_BYTES, TIMESTAMP_RANGE);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
-    assertTrue(mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY).isPresent());
+    Optional maybeMutationData =
+        mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
+    assertTrue(maybeMutationData.isPresent());
+    assertEquals(TIMESTAMP.longValue(), maybeMutationData.get().getTimestampMicros());
   }
 
   @Test
@@ -795,10 +838,12 @@ public void testNullModeNestedThrice() {
         .setCell(
             NESTED_NULL_STRUCT_FIELD_NAME,
             NESTED_NULL_STRUCT_FIELD_NAME_BYTES,
-            TIMESTAMP,
             expectedJsonificationBytes);
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
-    assertTrue(mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY).isPresent());
+    Optional maybeMutationData =
+        mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
+    assertTrue(maybeMutationData.isPresent());
+    assertEquals(TIMESTAMP.longValue(), maybeMutationData.get().getTimestampMicros());
   }
 
   @Test
@@ -808,74 +853,78 @@ public void testDefaultColumnFamilySubstitution() {
             ConfigInterpolation.TOPIC_PLACEHOLDER, DEFAULT_COLUMN, NullValueMode.WRITE, false);
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, null);
     verify(mutationDataBuilder, times(1))
-        .setCell(DEFAULT_TOPIC, DEFAULT_COLUMN_BYTES, TIMESTAMP, ByteString.empty());
+        .setCell(DEFAULT_TOPIC, DEFAULT_COLUMN_BYTES, ByteString.empty());
     assertTotalNumberOfInvocations(mutationDataBuilder, 1);
-    assertTrue(mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY).isPresent());
+    Optional maybeMutationData =
+        mutationDataBuilder.maybeBuild(TARGET_TABLE_NAME, ROW_KEY);
+    assertTrue(maybeMutationData.isPresent());
+    assertEquals(TIMESTAMP.longValue(), maybeMutationData.get().getTimestampMicros());
   }
 
   @Test
   public void testExpandRootLevelArrays() throws JsonProcessingException {
-    ValueMapper mapper =
-        new TestValueMapper(
-            "cf", "", NullValueMode.WRITE, true);
-
-    Schema productSchema = SchemaBuilder.struct()
-        .field("name", Schema.STRING_SCHEMA)
-        .field("id", Schema.STRING_SCHEMA)
-        .field("quantity", Schema.INT32_SCHEMA)
-        .build();
-
-    Schema schema = SchemaBuilder.struct().optional()
-        .field("orderId", Schema.STRING_SCHEMA)
-        .field("userId", Schema.STRING_SCHEMA)
-        .field("products", SchemaBuilder.array(productSchema).build())
-        .build();
-    Struct productElement1 = new Struct(productSchema)
-        .put("name", "Ball")
-        .put("id", "PROD-123")
-        .put("quantity", 5);
-    Struct productElement2 = new Struct(productSchema)
-        .put("name", "Car")
-        .put("id", "PROD-456")
-        .put("quantity", 1);
-    Struct productElement3 = new Struct(productSchema)
-        .put("name", "Tambourine")
-        .put("id", "PROD-789")
-        .put("quantity", 2);
+    ValueMapper mapper = new TestValueMapper("cf", "", NullValueMode.WRITE, true);
 
-    // use more than 9 elements to we can see what happens when the column qualifier is > 1 digits
-    List productList = Arrays.stream(new Struct[]{
-        // 1
-        productElement1,
-        // 2
-        productElement2,
-        // 3
-        productElement3,
-        // 4
-        productElement3,
-        // 5
-        productElement3,
-        // 6
-        productElement3,
-        // 7
-        productElement3,
-        // 8
-        productElement3,
-        // 9
-        productElement3,
-        // 10
-        productElement3,
-        // 11
-        productElement3,
-        // 12
-        productElement2
-    }).toList();
-
-    Struct value = new Struct(schema)
-        .put("orderId", "ORD-999")
-        .put("userId", "USER-42")
-        .put("products", productList);
+    Schema productSchema =
+        SchemaBuilder.struct()
+            .field("name", Schema.STRING_SCHEMA)
+            .field("id", Schema.STRING_SCHEMA)
+            .field("quantity", Schema.INT32_SCHEMA)
+            .build();
 
+    Schema schema =
+        SchemaBuilder.struct()
+            .optional()
+            .field("orderId", Schema.STRING_SCHEMA)
+            .field("userId", Schema.STRING_SCHEMA)
+            .field("products", SchemaBuilder.array(productSchema).build())
+            .build();
+    Struct productElement1 =
+        new Struct(productSchema).put("name", "Ball").put("id", "PROD-123").put("quantity", 5);
+    Struct productElement2 =
+        new Struct(productSchema).put("name", "Car").put("id", "PROD-456").put("quantity", 1);
+    Struct productElement3 =
+        new Struct(productSchema)
+            .put("name", "Tambourine")
+            .put("id", "PROD-789")
+            .put("quantity", 2);
+
+    // use more than 9 elements to we can see what happens when the column qualifier is > 1 digits
+    List productList =
+        Arrays.stream(
+                new Struct[] {
+                  // 1
+                  productElement1,
+                  // 2
+                  productElement2,
+                  // 3
+                  productElement3,
+                  // 4
+                  productElement3,
+                  // 5
+                  productElement3,
+                  // 6
+                  productElement3,
+                  // 7
+                  productElement3,
+                  // 8
+                  productElement3,
+                  // 9
+                  productElement3,
+                  // 10
+                  productElement3,
+                  // 11
+                  productElement3,
+                  // 12
+                  productElement2
+                })
+            .toList();
+
+    Struct value =
+        new Struct(schema)
+            .put("orderId", "ORD-999")
+            .put("userId", "USER-42")
+            .put("products", productList);
 
     MutationDataBuilder mutationDataBuilder = getRecordMutationDataBuilder(mapper, value);
 
@@ -884,71 +933,100 @@ public void testExpandRootLevelArrays() throws JsonProcessingException {
     String proto = ProtoUtil.toProto(mutationData.get()).replace("\n", "");
 
     JsonNode actual = new ObjectMapper().readTree(proto);
-    assertEquals("projects/project/instances/instance/tables/my_table", actual.get("tableName").asText());
-    assertEquals(ROW_KEY.toString(StandardCharsets.UTF_8), ProtoUtil.fromBase64(actual.get("rowKey").asText()));
+    assertEquals(
+        "projects/project/instances/instance/tables/my_table", actual.get("tableName").asText());
+    assertEquals(
+        ROW_KEY.toString(StandardCharsets.UTF_8),
+        ProtoUtil.fromBase64(actual.get("rowKey").asText()));
     ArrayNode mutations = (ArrayNode) actual.get("mutations");
     assertEquals(15, mutations.size());
     assertEquals("cf", mutations.get(0).get("setCell").get("familyName").textValue());
-    assertEquals("orderId", ProtoUtil.fromBase64(mutations.get(0).get("setCell").get("columnQualifier").textValue()));
-    assertEquals(ProtoUtil.toBase64("ORD-999"), mutations.get(0).get("setCell").get("value").textValue());
+    assertEquals(
+        "orderId",
+        ProtoUtil.fromBase64(mutations.get(0).get("setCell").get("columnQualifier").textValue()));
+    assertEquals(
+        ProtoUtil.toBase64("ORD-999"), mutations.get(0).get("setCell").get("value").textValue());
 
     assertEquals("cf", mutations.get(1).get("setCell").get("familyName").textValue());
-    assertEquals("userId", ProtoUtil.fromBase64(mutations.get(1).get("setCell").get("columnQualifier").textValue()));
-    assertEquals(ProtoUtil.toBase64("USER-42"), mutations.get(1).get("setCell").get("value").textValue());
+    assertEquals(
+        "userId",
+        ProtoUtil.fromBase64(mutations.get(1).get("setCell").get("columnQualifier").textValue()));
+    assertEquals(
+        ProtoUtil.toBase64("USER-42"), mutations.get(1).get("setCell").get("value").textValue());
 
     // products
-    assertEquals("products", mutations.get(2).get("deleteFromFamily").get("familyName").textValue());
+    assertEquals(
+        "products", mutations.get(2).get("deleteFromFamily").get("familyName").textValue());
 
     assertEquals("products", mutations.get(3).get("setCell").get("familyName").textValue());
-    assertEquals("000000", ProtoUtil.fromBase64(mutations.get(3).get("setCell").get("columnQualifier").textValue()));
+    assertEquals(
+        "000000",
+        ProtoUtil.fromBase64(mutations.get(3).get("setCell").get("columnQualifier").textValue()));
     JsonMapper jsonMapper = new JsonMapper();
 
-    JsonNode product1Json = jsonMapper.readTree(ProtoUtil.fromBase64(mutations.get(3).get("setCell").get("value").textValue()));
+    JsonNode product1Json =
+        jsonMapper.readTree(
+            ProtoUtil.fromBase64(mutations.get(3).get("setCell").get("value").textValue()));
     assertEquals("Ball", product1Json.get("name").asText());
     assertEquals("PROD-123", product1Json.get("id").asText());
     assertEquals(5, product1Json.get("quantity").asInt());
 
-    assertEquals("000001", ProtoUtil.fromBase64(mutations.get(4).get("setCell").get("columnQualifier").textValue()));
-    JsonNode product2Json = jsonMapper.readTree(ProtoUtil.fromBase64(mutations.get(4).get("setCell").get("value").textValue()));
+    assertEquals(
+        "000001",
+        ProtoUtil.fromBase64(mutations.get(4).get("setCell").get("columnQualifier").textValue()));
+    JsonNode product2Json =
+        jsonMapper.readTree(
+            ProtoUtil.fromBase64(mutations.get(4).get("setCell").get("value").textValue()));
     assertEquals("Car", product2Json.get("name").asText());
     assertEquals("PROD-456", product2Json.get("id").asText());
     assertEquals(1, product2Json.get("quantity").asInt());
 
-    assertEquals("000002", ProtoUtil.fromBase64(mutations.get(5).get("setCell").get("columnQualifier").textValue()));
-    JsonNode product3Json = jsonMapper.readTree(ProtoUtil.fromBase64(mutations.get(5).get("setCell").get("value").textValue()));
+    assertEquals(
+        "000002",
+        ProtoUtil.fromBase64(mutations.get(5).get("setCell").get("columnQualifier").textValue()));
+    JsonNode product3Json =
+        jsonMapper.readTree(
+            ProtoUtil.fromBase64(mutations.get(5).get("setCell").get("value").textValue()));
     assertEquals("Tambourine", product3Json.get("name").asText());
     assertEquals("PROD-789", product3Json.get("id").asText());
     assertEquals(2, product3Json.get("quantity").asInt());
 
-    assertEquals("000011", ProtoUtil.fromBase64(mutations.get(14).get("setCell").get("columnQualifier").textValue()));
-    JsonNode product12Json = jsonMapper.readTree(ProtoUtil.fromBase64(mutations.get(5).get("setCell").get("value").textValue()));
+    assertEquals(
+        "000011",
+        ProtoUtil.fromBase64(mutations.get(14).get("setCell").get("columnQualifier").textValue()));
+    JsonNode product12Json =
+        jsonMapper.readTree(
+            ProtoUtil.fromBase64(mutations.get(5).get("setCell").get("value").textValue()));
     assertEquals("Tambourine", product12Json.get("name").asText());
     assertEquals("PROD-789", product12Json.get("id").asText());
     assertEquals(2, product12Json.get("quantity").asInt());
   }
 
   private MutationDataBuilder getRecordMutationDataBuilder(ValueMapper mapper, Object kafkaValue) {
-    return getRecordMutationDataBuilder(mapper, kafkaValue, DEFAULT_TOPIC);
+    return getRecordMutationDataBuilder(mapper, kafkaValue, DEFAULT_TOPIC, InsertMode.UPSERT);
   }
 
   private MutationDataBuilder getRecordMutationDataBuilder(
-      ValueMapper mapper, Object kafkaValue, String topic) {
+      ValueMapper mapper, Object kafkaValue, String topic, InsertMode insertMode) {
     // We use `null` in this test since our code for now uses  Schema only to warn the user when an
     // unsupported logical type is encountered.
     SchemaAndValue schemaAndValue = new SchemaAndValue(null, kafkaValue);
-    return mapper.getRecordMutationDataBuilder(schemaAndValue, topic, TIMESTAMP);
+    return mapper.getRecordMutationDataBuilder(schemaAndValue, topic, insertMode, TIMESTAMP);
   }
 
   private static class TestValueMapper extends ValueMapper {
-
     public TestValueMapper(
-        String defaultColumnFamily, String defaultColumnQualifier, NullValueMode nullMode, boolean expandRootLevelArrays) {
+        String defaultColumnFamily,
+        String defaultColumnQualifier,
+        NullValueMode nullMode,
+        boolean expandRootLevelArrays) {
       super(defaultColumnFamily, defaultColumnQualifier, nullMode, expandRootLevelArrays);
     }
 
     @Override
-    protected MutationDataBuilder createMutationDataBuilder() {
-      return spy(super.createMutationDataBuilder());
+    protected MutationDataBuilder createMutationDataBuilder(
+        InsertMode insertMode, long timestampMicros) {
+      return spy(super.createMutationDataBuilder(insertMode, timestampMicros));
     }
   }
 }
diff --git a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/transformations/ApplyJsonSchemaTest.java b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/transformations/ApplyJsonSchemaTest.java
index fca8d859..434e784d 100644
--- a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/transformations/ApplyJsonSchemaTest.java
+++ b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/transformations/ApplyJsonSchemaTest.java
@@ -1,5 +1,25 @@
+/*
+ * Copyright 2026 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.cloud.kafka.connect.bigtable.transformations;
 
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
 import org.apache.kafka.connect.data.Schema;
 import org.apache.kafka.connect.data.Struct;
 import org.apache.kafka.connect.errors.DataException;
@@ -8,14 +28,6 @@
 import org.junit.Before;
 import org.junit.Test;
 
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.util.*;
-
-import static org.junit.Assert.*;
-
 public class ApplyJsonSchemaTest {
 
   private ApplyJsonSchema.Value smt;
@@ -59,10 +71,7 @@ public void testApplyJsonSchemalessToStruct() {
     rootMap.put("tags", Arrays.asList("production", "urgent"));
 
     // 2. Create the SourceRecord with NO schema
-    SourceRecord record = new SourceRecord(
-        null, null, "test-topic", 0,
-        null, rootMap
-    );
+    SourceRecord record = new SourceRecord(null, null, "test-topic", 0, null, rootMap);
 
     // 3. Apply the SMT
     SourceRecord transformed = smt.apply(record);
@@ -183,10 +192,7 @@ public void testMissingRequiredFieldThrowsException() {
   @Test
   public void testTombstoneRecord() {
     // A tombstone record has a null value
-    SourceRecord record = new SourceRecord(
-        null, null, "test-topic", 0,
-        null, null
-    );
+    SourceRecord record = new SourceRecord(null, null, "test-topic", 0, null, null);
 
     SourceRecord transformed = smt.apply(record);
 
@@ -196,19 +202,20 @@ public void testTombstoneRecord() {
 
   @Test
   public void testBytesField() {
-    String schemaJson = "{" +
-        "  \"type\": \"struct\"," +
-        "  \"fields\": [" +
-        "    { \"field\": \"raw_bytes\", \"type\": \"bytes\" }," +
-        "    { \"field\": \"base64_bytes\", \"type\": \"bytes\" }" +
-        "  ]" +
-        "}";
+    String schemaJson =
+        "{"
+            + "  \"type\": \"struct\","
+            + "  \"fields\": ["
+            + "    { \"field\": \"raw_bytes\", \"type\": \"bytes\" },"
+            + "    { \"field\": \"base64_bytes\", \"type\": \"bytes\" }"
+            + "  ]"
+            + "}";
 
     ApplyJsonSchema.Value bytesSmt = new ApplyJsonSchema.Value<>();
     bytesSmt.configure(Collections.singletonMap(ApplyJsonSchema.SCHEMA_CONFIG, schemaJson));
 
-    byte[] rawData = new byte[]{1, 2, 3, 4};
-    String base64Data = Base64.getEncoder().encodeToString(new byte[]{5, 6, 7, 8});
+    byte[] rawData = new byte[] {1, 2, 3, 4};
+    String base64Data = Base64.getEncoder().encodeToString(new byte[] {5, 6, 7, 8});
 
     Map valueMap = new HashMap<>();
     valueMap.put("raw_bytes", rawData);
@@ -219,12 +226,13 @@ public void testBytesField() {
 
     Struct struct = (Struct) transformed.value();
     assertArrayEquals(rawData, (byte[]) struct.get("raw_bytes"));
-    assertArrayEquals(new byte[]{5, 6, 7, 8}, (byte[]) struct.get("base64_bytes"));
+    assertArrayEquals(new byte[] {5, 6, 7, 8}, (byte[]) struct.get("base64_bytes"));
   }
 
   @Test
   public void testNumericToStringConversion() {
-    String schemaJson = "{\"type\": \"struct\", \"fields\": [{\"field\": \"string_field\", \"type\": \"string\"}]}";
+    String schemaJson =
+        "{\"type\": \"struct\", \"fields\": [{\"field\": \"string_field\", \"type\": \"string\"}]}";
 
     ApplyJsonSchema.Value stringSmt = new ApplyJsonSchema.Value<>();
     stringSmt.configure(Collections.singletonMap(ApplyJsonSchema.SCHEMA_CONFIG, schemaJson));
@@ -243,7 +251,9 @@ public void testNumericToStringConversion() {
   @Test
   public void testDefaultValues() throws IOException {
     ApplyJsonSchema.Value defaultSmt = new ApplyJsonSchema.Value<>();
-    defaultSmt.configure(Collections.singletonMap(ApplyJsonSchema.SCHEMA_CONFIG, readResource(DEFAULT_VALUES_SCHEMA_FILE)));
+    defaultSmt.configure(
+        Collections.singletonMap(
+            ApplyJsonSchema.SCHEMA_CONFIG, readResource(DEFAULT_VALUES_SCHEMA_FILE)));
 
     // Input map is empty, so all fields should take their default values
     Map valueMap = new HashMap<>();
diff --git a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/transformations/FlattenArrayElementTest.java b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/transformations/FlattenArrayElementTest.java
index 0091c687..1e31a3a8 100644
--- a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/transformations/FlattenArrayElementTest.java
+++ b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/transformations/FlattenArrayElementTest.java
@@ -1,7 +1,23 @@
+/*
+ * Copyright 2026 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.cloud.kafka.connect.bigtable.transformations;
 
-import com.google.cloud.kafka.connect.bigtable.config.BigtableSinkConfig;
-import org.apache.kafka.common.config.ConfigException;
+import static org.junit.Assert.*;
+
+import java.util.*;
 import org.apache.kafka.connect.data.Schema;
 import org.apache.kafka.connect.data.SchemaBuilder;
 import org.apache.kafka.connect.data.Struct;
@@ -11,11 +27,6 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.util.*;
-
-import static org.junit.Assert.*;
-
-
 @RunWith(JUnit4.class)
 public class FlattenArrayElementTest {
 
@@ -33,49 +44,62 @@ private FlattenArrayElement getTransformer() {
   public void testApply_Success() {
     FlattenArrayElement smt = getTransformer();
 
-    Schema productSchema = SchemaBuilder.struct()
-        .field("name", Schema.STRING_SCHEMA)
-        .field("id", Schema.STRING_SCHEMA)
-        .field("quantity", Schema.INT32_SCHEMA)
-        .build();
+    Schema productSchema =
+        SchemaBuilder.struct()
+            .field("name", Schema.STRING_SCHEMA)
+            .field("id", Schema.STRING_SCHEMA)
+            .field("quantity", Schema.INT32_SCHEMA)
+            .build();
 
     Schema elementSchema = SchemaBuilder.struct().field("element", productSchema).build();
 
-    Schema schema = SchemaBuilder.struct().optional()
-        .field("orderId", Schema.STRING_SCHEMA)
-        .field("userId", Schema.STRING_SCHEMA)
-        .field("products",
-            SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema)).build()
-        )
-        .build();
-    Struct productElement1 = new Struct(elementSchema).put("element", new Struct(productSchema)
-        .put("name", "Ball")
-        .put("id", "PROD-123")
-        .put("quantity", 5)
-    );
-    Struct productElement2 = new Struct(elementSchema).put("element", new Struct(productSchema)
-        .put("name", "Car")
-        .put("id", "PROD-456")
-        .put("quantity", 1)
-    );
-    Struct productElement3 = new Struct(elementSchema).put("element", new Struct(productSchema)
-        .put("name", "Tambourine")
-        .put("id", "PROD-789")
-        .put("quantity", 2)
-    );
-
-    List productList = Arrays.stream(new Struct[]{productElement1, productElement2, productElement3}).toList();
-
-    Struct productsWrapper = new Struct(schema.field("products").schema())
-        .put("list", productList);
-
-    Struct value = new Struct(schema)
-        .put("orderId", "ORD-999")
-        .put("userId", "USER-42")
-        .put("products", productsWrapper);
-
-    SourceRecord record = new SourceRecord(null, null, "test-topic", 0,
-        null, null, value.schema(), value);
+    Schema schema =
+        SchemaBuilder.struct()
+            .optional()
+            .field("orderId", Schema.STRING_SCHEMA)
+            .field("userId", Schema.STRING_SCHEMA)
+            .field(
+                "products",
+                SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema)).build())
+            .build();
+    Struct productElement1 =
+        new Struct(elementSchema)
+            .put(
+                "element",
+                new Struct(productSchema)
+                    .put("name", "Ball")
+                    .put("id", "PROD-123")
+                    .put("quantity", 5));
+    Struct productElement2 =
+        new Struct(elementSchema)
+            .put(
+                "element",
+                new Struct(productSchema)
+                    .put("name", "Car")
+                    .put("id", "PROD-456")
+                    .put("quantity", 1));
+    Struct productElement3 =
+        new Struct(elementSchema)
+            .put(
+                "element",
+                new Struct(productSchema)
+                    .put("name", "Tambourine")
+                    .put("id", "PROD-789")
+                    .put("quantity", 2));
+
+    List productList =
+        Arrays.stream(new Struct[] {productElement1, productElement2, productElement3}).toList();
+
+    Struct productsWrapper = new Struct(schema.field("products").schema()).put("list", productList);
+
+    Struct value =
+        new Struct(schema)
+            .put("orderId", "ORD-999")
+            .put("userId", "USER-42")
+            .put("products", productsWrapper);
+
+    SourceRecord record =
+        new SourceRecord(null, null, "test-topic", 0, null, null, value.schema(), value);
 
     SourceRecord transformedRecord = smt.apply(record);
 
@@ -110,21 +134,23 @@ public void testApply_Success() {
 
   @Test
   public void testConvertSchema() {
-    Schema productSchema = SchemaBuilder.struct()
-        .field("name", Schema.STRING_SCHEMA)
-        .field("id", Schema.STRING_SCHEMA)
-        .field("quantity", Schema.INT32_SCHEMA)
-        .build();
+    Schema productSchema =
+        SchemaBuilder.struct()
+            .field("name", Schema.STRING_SCHEMA)
+            .field("id", Schema.STRING_SCHEMA)
+            .field("quantity", Schema.INT32_SCHEMA)
+            .build();
 
     Schema elementSchema = SchemaBuilder.struct().field("element", productSchema).build();
 
-    Schema schema = SchemaBuilder.struct()
-        .field("orderId", Schema.STRING_SCHEMA)
-        .field("userId", Schema.INT32_SCHEMA)
-        .field("products",
-            SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema)).build()
-        )
-        .build();
+    Schema schema =
+        SchemaBuilder.struct()
+            .field("orderId", Schema.STRING_SCHEMA)
+            .field("userId", Schema.INT32_SCHEMA)
+            .field(
+                "products",
+                SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema)).build())
+            .build();
     Schema result = getTransformer().convertSchema(schema);
     assertEquals(Schema.Type.STRING, result.schema().field("orderId").schema().type());
     assertEquals(Schema.Type.INT32, result.schema().field("userId").schema().type());
@@ -138,24 +164,24 @@ public void testConvertSchema() {
 
   @Test
   public void testConvertSchemaWrongTypeRootLevelField() {
-    Schema schema = SchemaBuilder.struct()
-        .field("orderId", Schema.STRING_SCHEMA)
-        .field("userId", Schema.INT32_SCHEMA)
-        .field("products", Schema.STRING_SCHEMA)
-        .build();
+    Schema schema =
+        SchemaBuilder.struct()
+            .field("orderId", Schema.STRING_SCHEMA)
+            .field("userId", Schema.INT32_SCHEMA)
+            .field("products", Schema.STRING_SCHEMA)
+            .build();
     Exception e = assertThrows(DataException.class, () -> getTransformer().convertSchema(schema));
     assertEquals("Root level field 'products' is not a struct", e.getMessage());
   }
 
   @Test
   public void testConvertSchemaWrongTypeArrayWrapperField() {
-    Schema schema = SchemaBuilder.struct()
-        .field("orderId", Schema.STRING_SCHEMA)
-        .field("userId", Schema.INT32_SCHEMA)
-        .field("products",
-            SchemaBuilder.struct().field("list", Schema.STRING_SCHEMA).build()
-        )
-        .build();
+    Schema schema =
+        SchemaBuilder.struct()
+            .field("orderId", Schema.STRING_SCHEMA)
+            .field("userId", Schema.INT32_SCHEMA)
+            .field("products", SchemaBuilder.struct().field("list", Schema.STRING_SCHEMA).build())
+            .build();
     Exception e = assertThrows(DataException.class, () -> getTransformer().convertSchema(schema));
     assertEquals("Array field: 'list' is not an array", e.getMessage());
   }
@@ -164,36 +190,38 @@ public void testConvertSchemaWrongTypeArrayWrapperField() {
   public void testConvertSchemaWrongTypeArrayElementField() {
     Schema elementSchema = SchemaBuilder.struct().field("element", Schema.STRING_SCHEMA).build();
 
-    Schema schema = SchemaBuilder.struct()
-        .field("orderId", Schema.STRING_SCHEMA)
-        .field("userId", Schema.INT32_SCHEMA)
-        .field("products",
-            SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema)).build()
-        )
-        .build();
+    Schema schema =
+        SchemaBuilder.struct()
+            .field("orderId", Schema.STRING_SCHEMA)
+            .field("userId", Schema.INT32_SCHEMA)
+            .field(
+                "products",
+                SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema)).build())
+            .build();
     Exception e = assertThrows(DataException.class, () -> getTransformer().convertSchema(schema));
     assertEquals("Array element wrapper: 'element' is not a struct", e.getMessage());
   }
 
   @Test
   public void testConvertSchemaMissingRootLevelField() {
-    Schema schema = SchemaBuilder.struct()
-        .field("orderId", Schema.STRING_SCHEMA)
-        .field("userId", Schema.STRING_SCHEMA)
-        .build();
+    Schema schema =
+        SchemaBuilder.struct()
+            .field("orderId", Schema.STRING_SCHEMA)
+            .field("userId", Schema.STRING_SCHEMA)
+            .build();
     Exception e = assertThrows(DataException.class, () -> getTransformer().convertSchema(schema));
     assertEquals("Missing root level field: 'products'", e.getMessage());
   }
 
   @Test
   public void testConvertSchemaMissingArrayWrapper() {
-    Schema schema = SchemaBuilder.struct().optional()
-        .field("orderId", Schema.STRING_SCHEMA)
-        .field("userId", Schema.STRING_SCHEMA)
-        .field("products",
-            SchemaBuilder.struct().field("foo", Schema.STRING_SCHEMA).build()
-        )
-        .build();
+    Schema schema =
+        SchemaBuilder.struct()
+            .optional()
+            .field("orderId", Schema.STRING_SCHEMA)
+            .field("userId", Schema.STRING_SCHEMA)
+            .field("products", SchemaBuilder.struct().field("foo", Schema.STRING_SCHEMA).build())
+            .build();
 
     Exception e = assertThrows(DataException.class, () -> getTransformer().convertSchema(schema));
     assertEquals("Missing inner field: 'list'", e.getMessage());
@@ -201,18 +229,21 @@ public void testConvertSchemaMissingArrayWrapper() {
 
   @Test
   public void testConvertSchemaMissingElementWrapper() {
-    Schema productSchema = SchemaBuilder.struct()
-        .field("name", Schema.STRING_SCHEMA)
-        .field("id", Schema.STRING_SCHEMA)
-        .field("quantity", Schema.INT32_SCHEMA)
-        .build();
-    Schema schema = SchemaBuilder.struct().optional()
-        .field("orderId", Schema.STRING_SCHEMA)
-        .field("userId", Schema.STRING_SCHEMA)
-        .field("products",
-            SchemaBuilder.struct().field("list", SchemaBuilder.array(productSchema)).build()
-        )
-        .build();
+    Schema productSchema =
+        SchemaBuilder.struct()
+            .field("name", Schema.STRING_SCHEMA)
+            .field("id", Schema.STRING_SCHEMA)
+            .field("quantity", Schema.INT32_SCHEMA)
+            .build();
+    Schema schema =
+        SchemaBuilder.struct()
+            .optional()
+            .field("orderId", Schema.STRING_SCHEMA)
+            .field("userId", Schema.STRING_SCHEMA)
+            .field(
+                "products",
+                SchemaBuilder.struct().field("list", SchemaBuilder.array(productSchema)).build())
+            .build();
     Exception e = assertThrows(DataException.class, () -> getTransformer().convertSchema(schema));
     assertEquals("Missing array element field: 'element'", e.getMessage());
   }
@@ -221,29 +252,33 @@ public void testConvertSchemaMissingElementWrapper() {
   public void testApplyNullRootArray() {
     FlattenArrayElement smt = getTransformer();
 
-    Schema productSchema = SchemaBuilder.struct()
-        .field("name", Schema.STRING_SCHEMA)
-        .field("id", Schema.STRING_SCHEMA)
-        .field("quantity", Schema.INT32_SCHEMA)
-        .build();
+    Schema productSchema =
+        SchemaBuilder.struct()
+            .field("name", Schema.STRING_SCHEMA)
+            .field("id", Schema.STRING_SCHEMA)
+            .field("quantity", Schema.INT32_SCHEMA)
+            .build();
 
     Schema elementSchema = SchemaBuilder.struct().field("element", productSchema).build();
 
-    Schema schema = SchemaBuilder.struct().optional()
-        .field("orderId", Schema.STRING_SCHEMA)
-        .field("userId", Schema.STRING_SCHEMA)
-        .field("products",
-            SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema)).optional().build()
-        )
-        .build();
-
-    Struct value = new Struct(schema)
-        .put("orderId", "ORD-999")
-        .put("userId", "USER-42")
-        .put("products", null);
-
-    SourceRecord record = new SourceRecord(null, null, "test-topic", 0,
-        null, null, value.schema(), value);
+    Schema schema =
+        SchemaBuilder.struct()
+            .optional()
+            .field("orderId", Schema.STRING_SCHEMA)
+            .field("userId", Schema.STRING_SCHEMA)
+            .field(
+                "products",
+                SchemaBuilder.struct()
+                    .field("list", SchemaBuilder.array(elementSchema))
+                    .optional()
+                    .build())
+            .build();
+
+    Struct value =
+        new Struct(schema).put("orderId", "ORD-999").put("userId", "USER-42").put("products", null);
+
+    SourceRecord record =
+        new SourceRecord(null, null, "test-topic", 0, null, null, value.schema(), value);
 
     SourceRecord transformedRecord = smt.apply(record);
 
@@ -260,32 +295,37 @@ public void testApplyNullRootArray() {
   public void testApplyNullNestedArray() {
     FlattenArrayElement smt = getTransformer();
 
-    Schema productSchema = SchemaBuilder.struct()
-        .field("name", Schema.STRING_SCHEMA)
-        .field("id", Schema.STRING_SCHEMA)
-        .field("quantity", Schema.INT32_SCHEMA)
-        .build();
+    Schema productSchema =
+        SchemaBuilder.struct()
+            .field("name", Schema.STRING_SCHEMA)
+            .field("id", Schema.STRING_SCHEMA)
+            .field("quantity", Schema.INT32_SCHEMA)
+            .build();
 
     Schema elementSchema = SchemaBuilder.struct().field("element", productSchema).build();
 
-    Schema schema = SchemaBuilder.struct().optional()
-        .field("orderId", Schema.STRING_SCHEMA)
-        .field("userId", Schema.STRING_SCHEMA)
-        .field("products",
-            SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema).optional()).build()
-        )
-        .build();
-
-    Struct productsWrapper = new Struct(schema.field("products").schema())
-        .put("list", null);
-
-    Struct value = new Struct(schema)
-        .put("orderId", "ORD-999")
-        .put("userId", "USER-42")
-        .put("products", productsWrapper);
-
-    SourceRecord record = new SourceRecord(null, null, "test-topic", 0,
-        null, null, value.schema(), value);
+    Schema schema =
+        SchemaBuilder.struct()
+            .optional()
+            .field("orderId", Schema.STRING_SCHEMA)
+            .field("userId", Schema.STRING_SCHEMA)
+            .field(
+                "products",
+                SchemaBuilder.struct()
+                    .field("list", SchemaBuilder.array(elementSchema).optional())
+                    .build())
+            .build();
+
+    Struct productsWrapper = new Struct(schema.field("products").schema()).put("list", null);
+
+    Struct value =
+        new Struct(schema)
+            .put("orderId", "ORD-999")
+            .put("userId", "USER-42")
+            .put("products", productsWrapper);
+
+    SourceRecord record =
+        new SourceRecord(null, null, "test-topic", 0, null, null, value.schema(), value);
 
     SourceRecord transformedRecord = smt.apply(record);
 
@@ -302,44 +342,54 @@ public void testApplyNullNestedArray() {
   public void testApplyNullArrayElement() {
     FlattenArrayElement smt = getTransformer();
 
-    Schema productSchema = SchemaBuilder.struct()
-        .field("name", Schema.STRING_SCHEMA)
-        .field("id", Schema.STRING_SCHEMA)
-        .field("quantity", Schema.INT32_SCHEMA)
-        .build();
-
-    Schema elementSchema = SchemaBuilder.struct().field("element", productSchema).optional().build();
-
-    Schema schema = SchemaBuilder.struct()
-        .field("orderId", Schema.STRING_SCHEMA)
-        .field("userId", Schema.STRING_SCHEMA)
-        .field("products",
-            SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema)).build()
-        )
-        .build();
-    Struct productElement2 = new Struct(elementSchema).put("element", new Struct(productSchema)
-        .put("name", "Car")
-        .put("id", "PROD-456")
-        .put("quantity", 1)
-    );
-    Struct productElement3 = new Struct(elementSchema).put("element", new Struct(productSchema)
-        .put("name", "Tambourine")
-        .put("id", "PROD-789")
-        .put("quantity", 2)
-    );
-
-    List productList = Arrays.stream(new Struct[]{null, productElement2, productElement3}).toList();
-
-    Struct productsWrapper = new Struct(schema.field("products").schema())
-        .put("list", productList);
-
-    Struct value = new Struct(schema)
-        .put("orderId", "ORD-999")
-        .put("userId", "USER-42")
-        .put("products", productsWrapper);
-
-    SourceRecord record = new SourceRecord(null, null, "test-topic", 0,
-        null, null, value.schema(), value);
+    Schema productSchema =
+        SchemaBuilder.struct()
+            .field("name", Schema.STRING_SCHEMA)
+            .field("id", Schema.STRING_SCHEMA)
+            .field("quantity", Schema.INT32_SCHEMA)
+            .build();
+
+    Schema elementSchema =
+        SchemaBuilder.struct().field("element", productSchema).optional().build();
+
+    Schema schema =
+        SchemaBuilder.struct()
+            .field("orderId", Schema.STRING_SCHEMA)
+            .field("userId", Schema.STRING_SCHEMA)
+            .field(
+                "products",
+                SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema)).build())
+            .build();
+    Struct productElement2 =
+        new Struct(elementSchema)
+            .put(
+                "element",
+                new Struct(productSchema)
+                    .put("name", "Car")
+                    .put("id", "PROD-456")
+                    .put("quantity", 1));
+    Struct productElement3 =
+        new Struct(elementSchema)
+            .put(
+                "element",
+                new Struct(productSchema)
+                    .put("name", "Tambourine")
+                    .put("id", "PROD-789")
+                    .put("quantity", 2));
+
+    List productList =
+        Arrays.stream(new Struct[] {null, productElement2, productElement3}).toList();
+
+    Struct productsWrapper = new Struct(schema.field("products").schema()).put("list", productList);
+
+    Struct value =
+        new Struct(schema)
+            .put("orderId", "ORD-999")
+            .put("userId", "USER-42")
+            .put("products", productsWrapper);
+
+    SourceRecord record =
+        new SourceRecord(null, null, "test-topic", 0, null, null, value.schema(), value);
 
     SourceRecord transformedRecord = smt.apply(record);
 
@@ -371,45 +421,55 @@ public void testApplyNullArrayElement() {
   public void testApplyNullArrayElementValue() {
     FlattenArrayElement smt = getTransformer();
 
-    Schema productSchema = SchemaBuilder.struct().optional()
-        .field("name", Schema.STRING_SCHEMA)
-        .field("id", Schema.STRING_SCHEMA)
-        .field("quantity", Schema.INT32_SCHEMA)
-        .build();
+    Schema productSchema =
+        SchemaBuilder.struct()
+            .optional()
+            .field("name", Schema.STRING_SCHEMA)
+            .field("id", Schema.STRING_SCHEMA)
+            .field("quantity", Schema.INT32_SCHEMA)
+            .build();
 
     Schema elementSchema = SchemaBuilder.struct().field("element", productSchema).build();
 
-    Schema schema = SchemaBuilder.struct()
-        .field("orderId", Schema.STRING_SCHEMA)
-        .field("userId", Schema.STRING_SCHEMA)
-        .field("products",
-            SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema)).build()
-        )
-        .build();
+    Schema schema =
+        SchemaBuilder.struct()
+            .field("orderId", Schema.STRING_SCHEMA)
+            .field("userId", Schema.STRING_SCHEMA)
+            .field(
+                "products",
+                SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema)).build())
+            .build();
     Struct productElement1 = new Struct(elementSchema).put("element", null);
-    Struct productElement2 = new Struct(elementSchema).put("element", new Struct(productSchema)
-        .put("name", "Car")
-        .put("id", "PROD-456")
-        .put("quantity", 1)
-    );
-    Struct productElement3 = new Struct(elementSchema).put("element", new Struct(productSchema)
-        .put("name", "Tambourine")
-        .put("id", "PROD-789")
-        .put("quantity", 2)
-    );
-
-    List productList = Arrays.stream(new Struct[]{productElement1, productElement2, productElement3}).toList();
-
-    Struct productsWrapper = new Struct(schema.field("products").schema())
-        .put("list", productList);
-
-    Struct value = new Struct(schema)
-        .put("orderId", "ORD-999")
-        .put("userId", "USER-42")
-        .put("products", productsWrapper);
-
-    SourceRecord record = new SourceRecord(null, null, "test-topic", 0,
-        null, null, value.schema(), value);
+    Struct productElement2 =
+        new Struct(elementSchema)
+            .put(
+                "element",
+                new Struct(productSchema)
+                    .put("name", "Car")
+                    .put("id", "PROD-456")
+                    .put("quantity", 1));
+    Struct productElement3 =
+        new Struct(elementSchema)
+            .put(
+                "element",
+                new Struct(productSchema)
+                    .put("name", "Tambourine")
+                    .put("id", "PROD-789")
+                    .put("quantity", 2));
+
+    List productList =
+        Arrays.stream(new Struct[] {productElement1, productElement2, productElement3}).toList();
+
+    Struct productsWrapper = new Struct(schema.field("products").schema()).put("list", productList);
+
+    Struct value =
+        new Struct(schema)
+            .put("orderId", "ORD-999")
+            .put("userId", "USER-42")
+            .put("products", productsWrapper);
+
+    SourceRecord record =
+        new SourceRecord(null, null, "test-topic", 0, null, null, value.schema(), value);
 
     SourceRecord transformedRecord = smt.apply(record);
 
@@ -434,33 +494,34 @@ public void testApplyNullArrayElementValue() {
   public void testApplyMixedNulls() {
     FlattenArrayElement smt = getTransformer();
 
-    Schema productSchema = SchemaBuilder.struct().optional()
-        .field("name", Schema.STRING_SCHEMA)
-        .build();
+    Schema productSchema =
+        SchemaBuilder.struct().optional().field("name", Schema.STRING_SCHEMA).build();
 
-    Schema elementSchema = SchemaBuilder.struct().field("element", productSchema).optional().build();
+    Schema elementSchema =
+        SchemaBuilder.struct().field("element", productSchema).optional().build();
 
-    Schema schema = SchemaBuilder.struct()
-        .field("products",
-            SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema)).build()
-        )
-        .build();
+    Schema schema =
+        SchemaBuilder.struct()
+            .field(
+                "products",
+                SchemaBuilder.struct().field("list", SchemaBuilder.array(elementSchema)).build())
+            .build();
 
     // 1. null element wrapper
     // 2. element wrapper with null value
     // 3. valid element
     Struct productElement2 = new Struct(elementSchema).put("element", null);
-    Struct productElement3 = new Struct(elementSchema).put("element", new Struct(productSchema).put("name", "Ball"));
+    Struct productElement3 =
+        new Struct(elementSchema).put("element", new Struct(productSchema).put("name", "Ball"));
 
     List productList = Arrays.asList(null, productElement2, productElement3);
 
-    Struct productsWrapper = new Struct(schema.field("products").schema())
-        .put("list", productList);
+    Struct productsWrapper = new Struct(schema.field("products").schema()).put("list", productList);
 
     Struct value = new Struct(schema).put("products", productsWrapper);
 
-    SourceRecord record = new SourceRecord(null, null, "test-topic", 0,
-        null, null, value.schema(), value);
+    SourceRecord record =
+        new SourceRecord(null, null, "test-topic", 0, null, null, value.schema(), value);
 
     SourceRecord transformedRecord = smt.apply(record);
 
diff --git a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/util/ByteUtilsTest.java b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/util/ByteUtilsTest.java
index ae9dcf60..0790243f 100644
--- a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/util/ByteUtilsTest.java
+++ b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/util/ByteUtilsTest.java
@@ -1,17 +1,30 @@
+/*
+ * Copyright 2026 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.cloud.kafka.connect.bigtable.util;
 
 import static org.junit.Assert.assertArrayEquals;
 
-import com.google.cloud.kafka.connect.bigtable.mapping.ByteUtils;
+import com.google.cloud.kafka.connect.bigtable.utils.ByteUtils;
 import java.math.BigDecimal;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-/**
- * Ensures compatability with hbase-common Bytes
- */
+/** Ensures compatability with hbase-common Bytes */
 @RunWith(JUnit4.class)
 public class ByteUtilsTest {
 
@@ -71,10 +84,10 @@ public void testLong() {
   @Test
   public void testString() {
     assertArrayEquals(Bytes.toBytes(""), ByteUtils.toBytes(""));
-    assertArrayEquals(Bytes.toBytes("https://www.Google.com"),
-        ByteUtils.toBytes("https://www.Google.com"));
-    assertArrayEquals(Bytes.toBytes("https://www.google.com"),
-        ByteUtils.toBytes("https://www.google.com"));
+    assertArrayEquals(
+        Bytes.toBytes("https://www.Google.com"), ByteUtils.toBytes("https://www.Google.com"));
+    assertArrayEquals(
+        Bytes.toBytes("https://www.google.com"), ByteUtils.toBytes("https://www.google.com"));
     assertArrayEquals(Bytes.toBytes("this is a string"), ByteUtils.toBytes("this is a string"));
   }
 
@@ -93,20 +106,18 @@ public void testShort() {
   public void testBigDecimal() {
     assertArrayEquals(Bytes.toBytes(BigDecimal.ZERO), ByteUtils.toBytes(BigDecimal.ZERO));
     assertArrayEquals(Bytes.toBytes(BigDecimal.ONE), ByteUtils.toBytes(BigDecimal.ONE));
-    assertArrayEquals(Bytes.toBytes(BigDecimal.valueOf(-1)),
-        ByteUtils.toBytes(BigDecimal.valueOf(-1)));
-    assertArrayEquals(Bytes.toBytes(BigDecimal.valueOf(1)),
-        ByteUtils.toBytes(BigDecimal.valueOf(1)));
-    assertArrayEquals(Bytes.toBytes(BigDecimal.valueOf(-100)),
-        ByteUtils.toBytes(BigDecimal.valueOf(-100)));
-    assertArrayEquals(Bytes.toBytes(BigDecimal.valueOf(100)),
-        ByteUtils.toBytes(BigDecimal.valueOf(100)));
-    assertArrayEquals(Bytes.toBytes(BigDecimal.valueOf(100)),
-        ByteUtils.toBytes(BigDecimal.valueOf(100)));
+    assertArrayEquals(
+        Bytes.toBytes(BigDecimal.valueOf(-1)), ByteUtils.toBytes(BigDecimal.valueOf(-1)));
+    assertArrayEquals(
+        Bytes.toBytes(BigDecimal.valueOf(1)), ByteUtils.toBytes(BigDecimal.valueOf(1)));
+    assertArrayEquals(
+        Bytes.toBytes(BigDecimal.valueOf(-100)), ByteUtils.toBytes(BigDecimal.valueOf(-100)));
+    assertArrayEquals(
+        Bytes.toBytes(BigDecimal.valueOf(100)), ByteUtils.toBytes(BigDecimal.valueOf(100)));
+    assertArrayEquals(
+        Bytes.toBytes(BigDecimal.valueOf(100)), ByteUtils.toBytes(BigDecimal.valueOf(100)));
     assertArrayEquals(
         Bytes.toBytes(new BigDecimal("0.300000000000000000000000000000001")),
-        ByteUtils.toBytes(new BigDecimal("0.300000000000000000000000000000001"))
-    );
+        ByteUtils.toBytes(new BigDecimal("0.300000000000000000000000000000001")));
   }
-
 }
diff --git a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/util/ProtoUtil.java b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/util/ProtoUtil.java
index cb9dd49a..91eb9ff4 100644
--- a/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/util/ProtoUtil.java
+++ b/kafka-connect-bigtable-sink/sink/src/test/java/com/google/cloud/kafka/connect/bigtable/util/ProtoUtil.java
@@ -1,13 +1,27 @@
+/*
+ * Copyright 2026 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.cloud.kafka.connect.bigtable.util;
 
 import com.google.bigtable.v2.MutateRowRequest;
 import com.google.cloud.bigtable.data.v2.internal.RequestContext;
 import com.google.cloud.bigtable.data.v2.models.RowMutation;
 import com.google.cloud.bigtable.data.v2.models.TableId;
-import com.google.cloud.kafka.connect.bigtable.mapping.ByteUtils;
 import com.google.cloud.kafka.connect.bigtable.mapping.MutationData;
+import com.google.cloud.kafka.connect.bigtable.utils.ByteUtils;
 import com.google.protobuf.util.JsonFormat;
-
 import java.nio.charset.StandardCharsets;
 import java.util.Base64;
 
@@ -16,7 +30,9 @@ public class ProtoUtil {
   public static String toProto(MutationData mutation) {
     try {
       RequestContext context = RequestContext.create("project", "instance", "profile");
-      RowMutation rowMutation = RowMutation.create(TableId.of(mutation.getTargetTable()), mutation.getRowKey(), mutation.getInsertMutation());
+      RowMutation rowMutation =
+          RowMutation.create(
+              TableId.of(mutation.getTargetTable()), mutation.getRowKey(), mutation.getMutation());
       MutateRowRequest request = rowMutation.toProto(context);
       return JsonFormat.printer().print(request);
     } catch (Exception e) {

From b5439c53a8c52a7269def1c2f0df9883847f98da Mon Sep 17 00:00:00 2001
From: Brandt Newton 
Date: Wed, 18 Mar 2026 16:07:30 -0400
Subject: [PATCH 2/3] fix

---
 .../bigtable/bigtable_test.go                  | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/bigtable/bigtable_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/bigtable/bigtable_test.go
index 12b9e812..ccd4cf1f 100644
--- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/bigtable/bigtable_test.go
+++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/bigtable/bigtable_test.go
@@ -143,7 +143,7 @@ func TestInsertRow(t *testing.T) {
 			client, err := btc.clients.GetClient(tt.keyspace)
 			require.NoError(t, err)
 			table := client.Open(string(tt.table))
-			row, err := table.ReadRow(t.Context(), string(tt.rowKey))
+			row, err := table.ReadRow(t.Context(), string(tt.rowKey), bigtable.RowFilter(bigtable.LatestNFilter(1)))
 			require.NoError(t, err)
 			require.NotEmpty(t, row)
 			require.Contains(t, row, "cf1")
@@ -198,7 +198,7 @@ func TestApplyBulkMutation(t *testing.T) {
 	require.NoError(t, err)
 
 	// Verify mutations
-	row1, err := tbl.ReadRow(t.Context(), "bulk1")
+	row1, err := tbl.ReadRow(t.Context(), "bulk1", bigtable.RowFilter(bigtable.LatestNFilter(1)))
 	assert.NoError(t, err)
 	assert.NotEmpty(t, row1)
 	assert.Equal(t, []byte(nil), row1["cf1"][0].Value) // empty row cell
@@ -208,7 +208,7 @@ func TestApplyBulkMutation(t *testing.T) {
 	assert.NoError(t, err)
 	assert.Empty(t, row2)
 
-	row3, err := tbl.ReadRow(t.Context(), "bulk3")
+	row3, err := tbl.ReadRow(t.Context(), "bulk3", bigtable.RowFilter(bigtable.LatestNFilter(1)))
 	assert.NoError(t, err)
 	assert.NotEmpty(t, row3)
 	assert.Equal(t, []byte(nil), row3["cf1"][0].Value) // empty row cell
@@ -229,7 +229,7 @@ func TestMutateRowDeleteColumnFamily(t *testing.T) {
 	// Verify both column families are populated
 	tbl, err := btc.clients.GetTableClient(keyspace, tableName)
 	require.NoError(t, err)
-	row, err := tbl.ReadRow(t.Context(), key)
+	row, err := tbl.ReadRow(t.Context(), key, bigtable.RowFilter(bigtable.LatestNFilter(1)))
 	require.NoError(t, err)
 	assert.ElementsMatch(t, maps.Keys(row), []string{"cf1", "tags"})
 
@@ -240,7 +240,7 @@ func TestMutateRowDeleteColumnFamily(t *testing.T) {
 	require.NoError(t, err)
 
 	// Verify deletion by reading the row
-	row, err = tbl.ReadRow(t.Context(), key)
+	row, err = tbl.ReadRow(t.Context(), key, bigtable.RowFilter(bigtable.LatestNFilter(1)))
 	require.NoError(t, err)
 	assert.ElementsMatch(t, maps.Keys(row), []string{"cf1"}, "cf1 should still exist and tags should be deleted")
 }
@@ -265,7 +265,7 @@ func TestMutateRowDeleteQualifiers(t *testing.T) {
 	// Verify deletion by reading the row
 	tbl, err := btc.clients.GetTableClient(keyspace, tableName)
 	require.NoError(t, err)
-	row, err := tbl.ReadRow(t.Context(), key, bigtable.RowFilter(bigtable.FamilyFilter("cf1")))
+	row, err := tbl.ReadRow(t.Context(), key, bigtable.RowFilter(bigtable.ChainFilters(bigtable.FamilyFilter("cf1"), bigtable.LatestNFilter(1))))
 	require.NoError(t, err)
 	var columns []string
 	for _, item := range row["cf1"] {
@@ -297,7 +297,7 @@ func TestMutateRowIfExists(t *testing.T) {
 	tbl, err := btc.clients.GetTableClient(keyspace, tableName)
 	require.NoError(t, err)
 
-	row, err := tbl.ReadRow(t.Context(), key1, bigtable.RowFilter(bigtable.FamilyFilter("cf1")))
+	row, err := tbl.ReadRow(t.Context(), key1, bigtable.RowFilter(bigtable.ChainFilters(bigtable.FamilyFilter("cf1"), bigtable.LatestNFilter(1))))
 	require.NoError(t, err)
 	assert.Equal(t, []byte(nil), row["cf1"][0].Value) // empty row cell
 	assert.Equal(t, "v2", string(row["cf1"][1].Value), "value should be updated to v2")
@@ -327,7 +327,7 @@ func TestMutateRowIfNotExists(t *testing.T) {
 	// Verify the row is created
 	tbl, err := btc.clients.GetTableClient(keyspace, tableName)
 	require.NoError(t, err)
-	row, err := tbl.ReadRow(t.Context(), key, bigtable.RowFilter(bigtable.FamilyFilter("cf1")))
+	row, err := tbl.ReadRow(t.Context(), key, bigtable.RowFilter(bigtable.ChainFilters(bigtable.FamilyFilter("cf1"), bigtable.LatestNFilter(1))))
 	require.NoError(t, err)
 	assert.Equal(t, []byte(nil), row["cf1"][0].Value) // empty row cell
 	assert.Equal(t, "v1", string(row["cf1"][1].Value), "row1 should be created with value v1")
@@ -338,7 +338,7 @@ func TestMutateRowIfNotExists(t *testing.T) {
 	assert.False(t, wasApplied(res))
 
 	// Verify the row is not updated
-	row, err = tbl.ReadRow(t.Context(), key, bigtable.RowFilter(bigtable.FamilyFilter("cf1")))
+	row, err = tbl.ReadRow(t.Context(), key, bigtable.RowFilter(bigtable.ChainFilters(bigtable.FamilyFilter("cf1"), bigtable.LatestNFilter(1))))
 	require.NoError(t, err)
 	assert.Equal(t, []byte(nil), row["cf1"][0].Value) // empty row cell
 	assert.Equal(t, "v1", string(row["cf1"][1].Value), "row1 should not be updated")

From b985255133b5b5ddc45a115e7e1d659f9ed480a2 Mon Sep 17 00:00:00 2001
From: Brandt Newton 
Date: Wed, 1 Apr 2026 11:50:15 -0400
Subject: [PATCH 3/3] fixes

---
 .../global/types/cql_func_max_timeuuid.go      | 18 +++++++++---------
 .../global/types/cql_func_min_timeuuid.go      | 14 +++++++-------
 .../global/types/cql_func_to_timestamp.go      |  2 +-
 .../testing/compliance/compliance_uuid_test.go |  4 ++--
 4 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_max_timeuuid.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_max_timeuuid.go
index aa0275f6..b3b95556 100644
--- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_max_timeuuid.go
+++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_max_timeuuid.go
@@ -13,7 +13,7 @@ func (f *FuncMaxTimeuuid) GetValidClauses() []QueryClause {
 }
 
 func (f *FuncMaxTimeuuid) GetName() string {
-	return "minTimeuuid"
+	return "maxTimeuuid"
 }
 
 func (f *FuncMaxTimeuuid) GetCode() CqlFuncCode {
@@ -56,18 +56,18 @@ func maxUUIDv1ForTime(t time.Time) (uuid.UUID, error) {
 	// clock_seq_hi_and_variant (byte 8, 8 bits)
 	// The variant bits must be 10 (0x80 to 0xBF). We set the clock sequence to max.
 	// 0xBF is 0b10111111 (variant 10 and max 6 bits for the clock sequence high part)
-	u[8] = 0x7f
+	u[8] = 0xBF
 
 	// clock_seq_low (byte 9, 8 bits)
-	u[9] = 0x7f
+	u[9] = 0xFF
 
 	// Node ID (bytes 10-15, 48 bits) - set to all F's (max)
-	u[10] = 0x7f
-	u[11] = 0x7f
-	u[12] = 0x7f
-	u[13] = 0x7f
-	u[14] = 0x7f
-	u[15] = 0x7f
+	u[10] = 0xFF
+	u[11] = 0xFF
+	u[12] = 0xFF
+	u[13] = 0xFF
+	u[14] = 0xFF
+	u[15] = 0xFF
 
 	// Create the UUID from the byte array
 	return u, nil
diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_min_timeuuid.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_min_timeuuid.go
index 67f913a4..1d99f03e 100644
--- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_min_timeuuid.go
+++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_min_timeuuid.go
@@ -54,15 +54,15 @@ func minUUIDv1ForTime(t time.Time) (uuid.UUID, error) {
 	u[8] = 0x80
 
 	// clock_seq_low (byte 9, 8 bits)
-	u[9] = 0x80 // Min 8 bits
+	u[9] = 0x00 // Min 8 bits
 
 	// Node ID (bytes 10-15, 48 bits) - set to all 0's (min)
-	u[10] = 0x80
-	u[11] = 0x80
-	u[12] = 0x80
-	u[13] = 0x80
-	u[14] = 0x80
-	u[15] = 0x80
+	u[10] = 0x00
+	u[11] = 0x00
+	u[12] = 0x00
+	u[13] = 0x00
+	u[14] = 0x00
+	u[15] = 0x00
 
 	// Create the UUID from the byte array
 	return u, nil
diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_to_timestamp.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_to_timestamp.go
index 821820bb..3ee7f280 100644
--- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_to_timestamp.go
+++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/global/types/cql_func_to_timestamp.go
@@ -41,7 +41,7 @@ func (f *FuncToTimestamp) Apply(args []DynamicValue, values *QueryParameterValue
 }
 
 func (f *FuncToTimestamp) GetReturnType(_ []DynamicValue) CqlDataType {
-	return TypeTimeuuid
+	return TypeTimestamp
 }
 
 func getTimeFromUUID(id uuid.UUID) (time.Time, error) {
diff --git a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_uuid_test.go b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_uuid_test.go
index f16516fc..ad67748b 100644
--- a/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_uuid_test.go
+++ b/cassandra-bigtable-migration-tools/cassandra-bigtable-proxy/testing/compliance/compliance_uuid_test.go
@@ -147,9 +147,9 @@ func TestInsertTimeUuidNull(t *testing.T) {
 func TestValidateMaxAndMin(t *testing.T) {
 	inputTime := time.Date(2025, 12, 12, 13, 20, 42, 456000000, time.UTC)
 
-	minUuid, err := gocql.ParseUUID("5c09c580-d75d-11f0-8080-808080808080")
+	minUuid, err := gocql.ParseUUID("5c09c580-d75d-11f0-0000-000000000000")
 	require.NoError(t, err)
-	maxUuid, err := gocql.ParseUUID("5c09ec8f-d75d-11f0-7f7f-7f7f7f7f7f7f")
+	maxUuid, err := gocql.ParseUUID("5c09ec8f-d75d-11f0-ffff-ffffffffffff")
 	require.NoError(t, err)
 
 	require.NoError(t, session.Query(`INSERT INTO timeuuid_key (pk, id, val, parentEvent) VALUES ('timeuuid-validate', ?, '3', now())`, minUuid).Exec())