package parquet

import (
	
	
	
	
	
	
	

	
	
	
	
)

// Schema represents a parquet schema created from a Go value.
//
// Schema implements the Node interface to represent the root node of a parquet
// schema.
type Schema struct {
	name        string
	root        Node
	deconstruct deconstructFunc
	reconstruct reconstructFunc
	mapping     columnMapping
	columns     [][]string
}

// SchemaOf constructs a parquet schema from a Go value.
//
// The function can construct parquet schemas from struct or pointer-to-struct
// values only. A panic is raised if a Go value of a different type is passed
// to this function.
//
// When creating a parquet Schema from a Go value, the struct fields may contain
// a "parquet" tag to describe properties of the parquet node. The "parquet" tag
// follows the conventional format of Go struct tags: a comma-separated list of
// values describe the options, with the first one defining the name of the
// parquet column.
//
// The following options are also supported in the "parquet" struct tag:
//
//	optional  | make the parquet column optional
//	snappy    | sets the parquet column compression codec to snappy
//	gzip      | sets the parquet column compression codec to gzip
//	brotli    | sets the parquet column compression codec to brotli
//	lz4       | sets the parquet column compression codec to lz4
//	zstd      | sets the parquet column compression codec to zstd
//	plain     | enables the plain encoding (no-op default)
//	dict      | enables dictionary encoding on the parquet column
//	delta     | enables delta encoding on the parquet column
//	list      | for slice types, use the parquet LIST logical type
//	enum      | for string types, use the parquet ENUM logical type
//	uuid      | for string and [16]byte types, use the parquet UUID logical type
//	decimal   | for int32, int64 and [n]byte types, use the parquet DECIMAL logical type
//	date      | for int32 types use the DATE logical type
//	timestamp | for int64 types use the TIMESTAMP logical type with, by default, millisecond precision
//	split     | for float32/float64, use the BYTE_STREAM_SPLIT encoding
//	id(n)     | where n is int denoting a column field id. Example id(2) for a column with field id of 2
//
// # The date logical type is an int32 value of the number of days since the unix epoch
//
// The timestamp precision can be changed by defining which precision to use as an argument.
// Supported precisions are: nanosecond, millisecond and microsecond. Example:
//
//	type Message struct {
//	  TimestrampMicros int64 `parquet:"timestamp_micros,timestamp(microsecond)"
//	}
//
// The decimal tag must be followed by two integer parameters, the first integer
// representing the scale and the second the precision; for example:
//
//	type Item struct {
//		Cost int64 `parquet:"cost,decimal(0:3)"`
//	}
//
// Invalid combination of struct tags and Go types, or repeating options will
// cause the function to panic.
//
// As a special case, if the field tag is "-", the field is omitted from the schema
// and the data will not be written into the parquet file(s).
// Note that a field with name "-" can still be generated using the tag "-,".
//
// The configuration of Parquet maps are done via two tags:
//   - The `parquet-key` tag allows to configure the key of a map.
//   - The parquet-value tag allows users to configure a map's values, for example to declare their native Parquet types.
//
// When configuring a Parquet map, the `parquet` tag will configure the map itself.
//
// For example, the following will set the int64 key of the map to be a timestamp:
//
//	type Actions struct {
//	  Action map[int64]string `parquet:"," parquet-key:",timestamp"`
//	}
//
// The schema name is the Go type name of the value.
func ( interface{}) *Schema {
	return schemaOf(dereference(reflect.TypeOf()))
}

var cachedSchemas sync.Map // map[reflect.Type]*Schema

func schemaOf( reflect.Type) *Schema {
	,  := cachedSchemas.Load()
	,  := .(*Schema)
	if  != nil {
		return 
	}
	if .Kind() != reflect.Struct {
		panic("cannot construct parquet schema from value of type " + .String())
	}
	 = NewSchema(.Name(), nodeOf(, nil))
	if ,  := cachedSchemas.LoadOrStore(, );  {
		 = .(*Schema)
	}
	return 
}

// NewSchema constructs a new Schema object with the given name and root node.
//
// The function panics if Node contains more leaf columns than supported by the
// package (see parquet.MaxColumnIndex).
func ( string,  Node) *Schema {
	,  := columnMappingOf()
	return &Schema{
		name:        ,
		root:        ,
		deconstruct: makeDeconstructFunc(),
		reconstruct: makeReconstructFunc(),
		mapping:     ,
		columns:     ,
	}
}

func dereference( reflect.Type) reflect.Type {
	for .Kind() == reflect.Ptr {
		 = .Elem()
	}
	return 
}

func makeDeconstructFunc( Node) ( deconstructFunc) {
	if ,  := .(*Schema);  != nil {
		return .deconstruct
	}
	if !.Leaf() {
		_,  = deconstructFuncOf(0, )
	}
	return 
}

func makeReconstructFunc( Node) ( reconstructFunc) {
	if ,  := .(*Schema);  != nil {
		return .reconstruct
	}
	if !.Leaf() {
		_,  = reconstructFuncOf(0, )
	}
	return 
}

// ConfigureRowGroup satisfies the RowGroupOption interface, allowing Schema
// instances to be passed to row group constructors to pre-declare the schema of
// the output parquet file.
func ( *Schema) ( *RowGroupConfig) { .Schema =  }

// ConfigureReader satisfies the ReaderOption interface, allowing Schema
// instances to be passed to NewReader to pre-declare the schema of rows
// read from the reader.
func ( *Schema) ( *ReaderConfig) { .Schema =  }

// ConfigureWriter satisfies the WriterOption interface, allowing Schema
// instances to be passed to NewWriter to pre-declare the schema of the
// output parquet file.
func ( *Schema) ( *WriterConfig) { .Schema =  }

// ID returns field id of the root node.
func ( *Schema) () int { return .root.ID() }

// String returns a parquet schema representation of s.
func ( *Schema) () string { return sprint(.name, .root) }

// Name returns the name of s.
func ( *Schema) () string { return .name }

// Type returns the parquet type of s.
func ( *Schema) () Type { return .root.Type() }

// Optional returns false since the root node of a parquet schema is always required.
func ( *Schema) () bool { return .root.Optional() }

// Repeated returns false since the root node of a parquet schema is always required.
func ( *Schema) () bool { return .root.Repeated() }

// Required returns true since the root node of a parquet schema is always required.
func ( *Schema) () bool { return .root.Required() }

// Leaf returns true if the root node of the parquet schema is a leaf column.
func ( *Schema) () bool { return .root.Leaf() }

// Fields returns the list of fields on the root node of the parquet schema.
func ( *Schema) () []Field { return .root.Fields() }

// Encoding returns the encoding set on the root node of the parquet schema.
func ( *Schema) () encoding.Encoding { return .root.Encoding() }

// Compression returns the compression codec set on the root node of the parquet
// schema.
func ( *Schema) () compress.Codec { return .root.Compression() }

// GoType returns the Go type that best represents the schema.
func ( *Schema) () reflect.Type { return .root.GoType() }

// Deconstruct deconstructs a Go value and appends it to a row.
//
// The method panics is the structure of the go value does not match the
// parquet schema.
func ( *Schema) ( Row,  interface{}) Row {
	 := make([][]Value, len(.columns))
	 := make([]Value, len(.columns))

	for  := range  {
		[] = [ :  : +1]
	}

	.deconstructValueToColumns(, reflect.ValueOf())
	return appendRow(, )
}

func ( *Schema) ( [][]Value,  reflect.Value) {
	for .Kind() == reflect.Ptr || .Kind() == reflect.Interface {
		if .IsNil() {
			 = reflect.Value{}
			break
		}
		 = .Elem()
	}
	.deconstruct(, levels{}, )
}

// Reconstruct reconstructs a Go value from a row.
//
// The go value passed as first argument must be a non-nil pointer for the
// row to be decoded into.
//
// The method panics if the structure of the go value and parquet row do not
// match.
func ( *Schema) ( interface{},  Row) error {
	 := reflect.ValueOf()
	if !.IsValid() {
		panic("cannot reconstruct row into go value of type <nil>")
	}
	if .Kind() != reflect.Ptr {
		panic("cannot reconstruct row into go value of non-pointer type " + .Type().String())
	}
	if .IsNil() {
		panic("cannot reconstruct row into nil pointer of type " + .Type().String())
	}
	for .Kind() == reflect.Ptr {
		if .IsNil() {
			.Set(reflect.New(.Type().Elem()))
		}
		 = .Elem()
	}

	 := valuesSliceBufferPool.Get().(*valuesSliceBuffer)

	 := .reserve(len(.columns))
	.Range(func( int,  []Value) bool {
		if  < len() {
			[] = 
		}
		return true
	})
	// we avoid the defer penalty by releasing b manually
	 := .reconstruct(, levels{}, )
	.release()
	return 
}

type valuesSliceBuffer struct {
	values [][]Value
}

func ( *valuesSliceBuffer) ( int) [][]Value {
	if  <= cap(.values) {
		return .values[:]
	}
	// we can try to keep growing by the power of two, but we care more about the
	// memory footprint so  this should suffice.
	//
	// The nature of reads tends to be from similar number of columns.The less work
	// we do here the better performance we can get.
	.values = make([][]Value, )
	return .values
}

func ( *valuesSliceBuffer) () {
	.values = .values[:0]
	valuesSliceBufferPool.Put()
}

var valuesSliceBufferPool = &sync.Pool{
	New: func() interface{} {
		return &valuesSliceBuffer{
			// use 64 as a cache friendly base estimate of max column numbers we will be
			// reading.
			values: make([][]Value, 0, 64),
		}
	},
}

// Lookup returns the leaf column at the given path.
//
// The path is the sequence of column names identifying a leaf column (not
// including the root).
//
// If the path was not found in the mapping, or if it did not represent a
// leaf column of the parquet schema, the boolean will be false.
func ( *Schema) ( ...string) (LeafColumn, bool) {
	 := .mapping.lookup()
	return LeafColumn{
		Node:               .node,
		Path:               .path,
		ColumnIndex:        int(.columnIndex),
		MaxRepetitionLevel: int(.maxRepetitionLevel),
		MaxDefinitionLevel: int(.maxDefinitionLevel),
	}, .node != nil
}

// Columns returns the list of column paths available in the schema.
//
// The method always returns the same slice value across calls to ColumnPaths,
// applications should treat it as immutable.
func ( *Schema) () [][]string {
	return .columns
}

// Comparator constructs a comparator function which orders rows according to
// the list of sorting columns passed as arguments.
func ( *Schema) ( ...SortingColumn) func(Row, Row) int {
	return compareRowsFuncOf(, )
}

func ( *Schema) ( func( string,  Node)) {
	forEachNodeOf(.Name(), , )
}

type structNode struct {
	gotype reflect.Type
	fields []structField
}

func structNodeOf( reflect.Type) *structNode {
	// Collect struct fields first so we can order them before generating the
	// column indexes.
	 := structFieldsOf()

	 := &structNode{
		gotype: ,
		fields: make([]structField, len()),
	}

	for  := range  {
		 := structField{name: [].Name, index: [].Index}
		.Node = makeNodeOf([].Type, [].Name, []string{
			[].Tag.Get("parquet"),
			[].Tag.Get("parquet-key"),
			[].Tag.Get("parquet-value"),
		})
		.fields[] = 
	}

	return 
}

func structFieldsOf( reflect.Type) []reflect.StructField {
	 := appendStructFields(, nil, nil, 0)

	for  := range  {
		 := &[]

		if  := .Tag.Get("parquet");  != "" {
			,  := split()
			if  != "" {
				.Name = 
			}
		}
	}

	return 
}

func appendStructFields( reflect.Type,  []reflect.StructField,  []int,  uintptr) []reflect.StructField {
	for ,  := 0, .NumField();  < ; ++ {
		 := .Field()
		if  := .Tag.Get("parquet");  != "" {
			,  := split()
			if  != "-," &&  == "-" {
				continue
			}
		}

		 := [:len():len()]
		 = append(, )

		.Offset += 

		if .Anonymous {
			 = (.Type, , , .Offset)
		} else if .IsExported() {
			.Index = 
			 = append(, )
		}
	}
	return 
}

func ( *structNode) () bool { return false }

func ( *structNode) () bool { return false }

func ( *structNode) () bool { return true }

func ( *structNode) () bool { return false }

func ( *structNode) () encoding.Encoding { return nil }

func ( *structNode) () compress.Codec { return nil }

func ( *structNode) () reflect.Type { return .gotype }

func ( *structNode) () int { return 0 }

func ( *structNode) () string { return sprint("", ) }

func ( *structNode) () Type { return groupType{} }

func ( *structNode) () []Field {
	 := make([]Field, len(.fields))
	for  := range .fields {
		[] = &.fields[]
	}
	return 
}

// fieldByIndex is like reflect.Value.FieldByIndex but returns the zero-value of
// reflect.Value if one of the fields was a nil pointer instead of panicking.
func fieldByIndex( reflect.Value,  []int) reflect.Value {
	for ,  := range  {
		if  = .Field(); .Kind() == reflect.Ptr || .Kind() == reflect.Interface {
			if .IsNil() {
				.Set(reflect.New(.Type().Elem()))
				 = .Elem()
				break
			} else {
				 = .Elem()
			}
		}
	}
	return 
}

type structField struct {
	Node
	name  string
	index []int
}

func ( *structField) () string { return .name }

func ( *structField) ( reflect.Value) reflect.Value {
	switch .Kind() {
	case reflect.Map:
		return .MapIndex(reflect.ValueOf(&.name).Elem())
	case reflect.Ptr:
		if .IsNil() {
			.Set(reflect.New(.Type().Elem()))
		}
		return fieldByIndex(.Elem(), .index)
	default:
		if len(.index) == 1 {
			return .Field(.index[0])
		} else {
			return fieldByIndex(, .index)
		}
	}
}

func nodeString( reflect.Type,  string,  ...string) string {
	return fmt.Sprintf("%s %s %v", , .String(), )
}

func throwInvalidTag( reflect.Type,  string,  string) {
	panic( + " is an invalid parquet tag: " + nodeString(, , ))
}

func throwUnknownTag( reflect.Type,  string,  string) {
	panic( + " is an unrecognized parquet tag: " + nodeString(, , ))
}

func throwInvalidNode( reflect.Type, ,  string,  ...string) {
	panic( + ": " + nodeString(, , ...))
}

// FixedLenByteArray decimals are sized based on precision
// this function calculates the necessary byte array size.
func decimalFixedLenByteArraySize( int) int {
	return int(math.Ceil((math.Log10(2) + float64()) / math.Log10(256)))
}

func forEachStructTagOption( reflect.StructField,  func( reflect.Type, ,  string)) {
	if  := .Tag.Get("parquet");  != "" {
		_,  = split() // skip the field name
		for  != "" {
			 := ""
			 := ""
			,  = split()
			,  = splitOptionArgs()
			 := .Type
			if .Kind() == reflect.Ptr {
				 = .Elem()
			}
			(, , )
		}
	}
}

func nodeOf( reflect.Type,  []string) Node {
	switch  {
	case reflect.TypeOf(deprecated.Int96{}):
		return Leaf(Int96Type)
	case reflect.TypeOf(uuid.UUID{}):
		return UUID()
	case reflect.TypeOf(time.Time{}):
		return Timestamp(Nanosecond)
	}

	var  Node
	switch .Kind() {
	case reflect.Bool:
		 = Leaf(BooleanType)

	case reflect.Int, reflect.Int64:
		 = Int(64)

	case reflect.Int8, reflect.Int16, reflect.Int32:
		 = Int(.Bits())

	case reflect.Uint, reflect.Uintptr, reflect.Uint64:
		 = Uint(64)

	case reflect.Uint8, reflect.Uint16, reflect.Uint32:
		 = Uint(.Bits())

	case reflect.Float32:
		 = Leaf(FloatType)

	case reflect.Float64:
		 = Leaf(DoubleType)

	case reflect.String:
		 = String()

	case reflect.Ptr:
		 = Optional((.Elem(), nil))

	case reflect.Slice:
		if  := .Elem(); .Kind() == reflect.Uint8 { // []byte?
			 = Leaf(ByteArrayType)
		} else {
			 = Repeated((, nil))
		}

	case reflect.Array:
		if .Elem().Kind() == reflect.Uint8 {
			 = Leaf(FixedLenByteArrayType(.Len()))
		}

	case reflect.Map:
		var , ,  string
		if len() > 0 {
			 = [0]
			if len() > 1 {
				 = [1]
			}
			if len() >= 2 {
				 = [2]
			}
		}

		if strings.Contains(, "json") {
			 = JSON()
		} else {
			 = Map(
				makeNodeOf(.Key(), .Name(), []string{}),
				makeNodeOf(.Elem(), .Name(), []string{}),
			)
		}

		forEachTagOption([]string{}, func(,  string) {
			switch  {
			case "", "json":
				return
			case "optional":
				 = Optional()
			case "id":
				,  := parseIDArgs()
				if  != nil {
					throwInvalidTag(, "map", )
				}
				 = FieldID(, )
			default:
				throwUnknownTag(, "map", )
			}
		})

	case reflect.Struct:
		return structNodeOf()
	}

	if  == nil {
		panic("cannot create parquet node from go value of type " + .String())
	}

	return &goNode{Node: , gotype: }
}

func split( string) (,  string) {
	if  := strings.IndexByte(, ',');  < 0 {
		 = 
	} else {
		,  = [:], [+1:]
	}
	return
}

func splitOptionArgs( string) (,  string) {
	if  := strings.IndexByte(, '(');  >= 0 {
		 = [:]
		 = [:]
	} else {
		 = 
		 = "()"
	}
	return
}

func parseDecimalArgs( string) (,  int,  error) {
	if !strings.HasPrefix(, "(") || !strings.HasSuffix(, ")") {
		return 0, 0, fmt.Errorf("malformed decimal args: %s", )
	}
	 = strings.TrimPrefix(, "(")
	 = strings.TrimSuffix(, ")")
	 := strings.Split(, ":")
	if len() != 2 {
		return 0, 0, fmt.Errorf("malformed decimal args: (%s)", )
	}
	,  := strconv.ParseInt([0], 10, 32)
	if  != nil {
		return 0, 0, 
	}
	,  := strconv.ParseInt([1], 10, 32)
	if  != nil {
		return 0, 0, 
	}
	return int(), int(), nil
}

func parseIDArgs( string) (int, error) {
	if !strings.HasPrefix(, "(") || !strings.HasSuffix(, ")") {
		return 0, fmt.Errorf("malformed id args: %s", )
	}
	 = strings.TrimPrefix(, "(")
	 = strings.TrimSuffix(, ")")
	return strconv.Atoi()
}

func parseTimestampArgs( string) (TimeUnit, error) {
	if !strings.HasPrefix(, "(") || !strings.HasSuffix(, ")") {
		return nil, fmt.Errorf("malformed timestamp args: %s", )
	}

	 = strings.TrimPrefix(, "(")
	 = strings.TrimSuffix(, ")")

	if len() == 0 {
		return Millisecond, nil
	}

	switch  {
	case "millisecond":
		return Millisecond, nil
	case "microsecond":
		return Microsecond, nil
	case "nanosecond":
		return Nanosecond, nil
	default:
	}

	return nil, fmt.Errorf("unknown time unit: %s", )
}

type goNode struct {
	Node
	gotype reflect.Type
}

func ( *goNode) () reflect.Type { return .gotype }

var (
	_ RowGroupOption = (*Schema)(nil)
	_ ReaderOption   = (*Schema)(nil)
	_ WriterOption   = (*Schema)(nil)
)

func makeNodeOf( reflect.Type,  string,  []string) Node {
	var (
		       Node
		   bool
		       bool
		    encoding.Encoding
		 compress.Codec
		    int
	)

	 := func( Node) {
		if  != nil {
			throwInvalidNode(, "struct field has multiple logical parquet types declared", , ...)
		}
		 = 
	}

	 := func() {
		if  {
			throwInvalidNode(, "struct field has multiple declaration of the optional tag", , ...)
		}
		 = true
	}

	 := func() {
		if  {
			throwInvalidNode(, "struct field has multiple declaration of the list tag", , ...)
		}
		 = true
	}

	 := func( encoding.Encoding) {
		if  != nil {
			throwInvalidNode(, "struct field has encoding declared multiple time", , ...)
		}
		 = 
	}

	 := func( compress.Codec) {
		if  != nil {
			throwInvalidNode(, "struct field has compression codecs declared multiple times", , ...)
		}
		 = 
	}

	forEachTagOption(, func(,  string) {
		if .Kind() == reflect.Map {
			 = nodeOf(, )
			return
		}
		switch  {
		case "":
			return
		case "optional":
			()

		case "snappy":
			(&Snappy)

		case "gzip":
			(&Gzip)

		case "brotli":
			(&Brotli)

		case "lz4":
			(&Lz4Raw)

		case "zstd":
			(&Zstd)

		case "uncompressed":
			(&Uncompressed)

		case "plain":
			(&Plain)

		case "dict":
			(&RLEDictionary)

		case "json":
			(JSON())

		case "delta":
			switch .Kind() {
			case reflect.Int, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint32, reflect.Uint64:
				(&DeltaBinaryPacked)
			case reflect.String:
				(&DeltaByteArray)
			case reflect.Slice:
				if .Elem().Kind() == reflect.Uint8 { // []byte?
					(&DeltaByteArray)
				} else {
					throwInvalidTag(, , )
				}
			case reflect.Array:
				if .Elem().Kind() == reflect.Uint8 { // [N]byte?
					(&DeltaByteArray)
				} else {
					throwInvalidTag(, , )
				}
			default:
				switch  {
				case reflect.TypeOf(time.Time{}):
					(&DeltaBinaryPacked)
				default:
					throwInvalidTag(, , )
				}
			}

		case "split":
			switch .Kind() {
			case reflect.Float32, reflect.Float64:
				(&ByteStreamSplit)
			default:
				throwInvalidTag(, , )
			}

		case "list":
			switch .Kind() {
			case reflect.Slice:
				 := nodeOf(.Elem(), nil)
				()
				()
			default:
				throwInvalidTag(, , )
			}

		case "enum":
			switch .Kind() {
			case reflect.String:
				(Enum())
			default:
				throwInvalidTag(, , )
			}

		case "uuid":
			switch .Kind() {
			case reflect.Array:
				if .Elem().Kind() != reflect.Uint8 || .Len() != 16 {
					throwInvalidTag(, , )
				}
			default:
				throwInvalidTag(, , )
			}

		case "decimal":
			, ,  := parseDecimalArgs()
			if  != nil {
				throwInvalidTag(, , +)
			}
			var  Type
			switch .Kind() {
			case reflect.Int32:
				 = Int32Type
			case reflect.Int64:
				 = Int64Type
			case reflect.Array, reflect.Slice:
				 = FixedLenByteArrayType(decimalFixedLenByteArraySize())
			default:
				throwInvalidTag(, , )
			}

			(Decimal(, , ))
		case "date":
			switch .Kind() {
			case reflect.Int32:
				(Date())
			default:
				throwInvalidTag(, , )
			}
		case "timestamp":
			switch .Kind() {
			case reflect.Int64:
				,  := parseTimestampArgs()
				if  != nil {
					throwInvalidTag(, , )
				}
				(Timestamp())
			default:
				switch  {
				case reflect.TypeOf(time.Time{}):
					,  := parseTimestampArgs()
					if  != nil {
						throwInvalidTag(, , )
					}
					(Timestamp())
				default:
					throwInvalidTag(, , )
				}
			}
		case "id":
			,  := parseIDArgs()
			if  != nil {
				throwInvalidNode(, "struct field has field id that is not a valid int", , ...)
			}
			 = 
		}
	})

	// Special case: an "optional" struct tag on a slice applies to the
	// individual items, not the overall list. The least messy way to
	// deal with this is at this level, instead of passing down optional
	// information into the nodeOf function, and then passing back whether an
	// optional tag was applied.
	if  == nil && .Kind() == reflect.Slice {
		 := .Elem().Kind() == reflect.Uint8
		// Note for strings "optional" applies only to the entire BYTE_ARRAY and
		// not each individual byte.
		if  && ! {
			 = Repeated(Optional(nodeOf(.Elem(), )))
			// Don't also apply "optional" to the whole list.
			 = false
		}
	}

	if  == nil {
		 = nodeOf(, )
	}

	if  != nil {
		 = Compressed(, )
	}

	if  != nil {
		 = Encoded(, )
	}

	if  {
		 = List()
	}

	if .Repeated() && ! {
		 := .GoType().Elem()
		if .Kind() == reflect.Slice {
			// Special case: allow [][]uint as seen in a logical map of strings
			if .Elem().Kind() != reflect.Uint8 {
				panic("unhandled nested slice on parquet schema without list tag")
			}
		}
	}

	if  {
		 = Optional()
	}
	if  != 0 {
		 = FieldID(, )
	}
	return 
}

func forEachTagOption( []string,  func(,  string)) {
	for ,  := range  {
		_,  = split() // skip the field name
		for  != "" {
			 := ""
			,  = split()
			var  string
			,  = splitOptionArgs()
			(, )
		}
	}
}