package cview

import (
	
	

	
)

// DefaultFormFieldWidth is the default field screen width of form elements
// whose field width is flexible (0). This is used in the Form class for
// horizontal layouts.
var DefaultFormFieldWidth = 10

// FormItemAttributes is a set of attributes to be applied.
type FormItemAttributes struct {
	// The screen width of the label. A value of 0 will cause the primitive to
	// use the width of the label string.
	LabelWidth int

	BackgroundColor             tcell.Color
	LabelColor                  tcell.Color
	LabelColorFocused           tcell.Color
	FieldBackgroundColor        tcell.Color
	FieldBackgroundColorFocused tcell.Color
	FieldTextColor              tcell.Color
	FieldTextColorFocused       tcell.Color

	FinishedFunc func(key tcell.Key)
}

// FormItem is the interface all form items must implement to be able to be
// included in a form.
type FormItem interface {
	Primitive

	// GetLabel returns the item's label text.
	GetLabel() string

	// SetLabelWidth sets the screen width of the label. A value of 0 will cause the
	// primitive to use the width of the label string.
	SetLabelWidth(int)

	// SetLabelColor sets the color of the label.
	SetLabelColor(tcell.Color)

	// SetLabelColor sets the color of the label when focused.
	SetLabelColorFocused(tcell.Color)

	// GetFieldWidth returns the width of the form item's field (the area which
	// is manipulated by the user) in number of screen cells. A value of 0
	// indicates the the field width is flexible and may use as much space as
	// required.
	GetFieldWidth() int

	// GetFieldHeight returns the height of the form item.
	GetFieldHeight() int

	// SetFieldTextColor sets the text color of the input area.
	SetFieldTextColor(tcell.Color)

	// SetFieldTextColorFocused sets the text color of the input area when focused.
	SetFieldTextColorFocused(tcell.Color)

	// SetFieldBackgroundColor sets the background color of the input area.
	SetFieldBackgroundColor(tcell.Color)

	// SetFieldBackgroundColor sets the background color of the input area when focused.
	SetFieldBackgroundColorFocused(tcell.Color)

	// SetBackgroundColor sets the background color of the form item.
	SetBackgroundColor(tcell.Color)

	// SetFinishedFunc sets a callback invoked when the user leaves the form item.
	SetFinishedFunc(func(key tcell.Key))
}

// Form allows you to combine multiple one-line form elements into a vertical
// or horizontal layout. Form elements include types such as InputField or
// CheckBox. These elements can be optionally followed by one or more buttons
// for which you can define form-wide actions (e.g. Save, Clear, Cancel).
type Form struct {
	*Box

	// The items of the form (one row per item).
	items []FormItem

	// The buttons of the form.
	buttons []*Button

	// If set to true, instead of position items and buttons from top to bottom,
	// they are positioned from left to right.
	horizontal bool

	// The alignment of the buttons.
	buttonsAlign int

	// The number of empty rows between items.
	itemPadding int

	// The index of the item or button which has focus. (Items are counted first,
	// buttons are counted last.) This is only used when the form itself receives
	// focus so that the last element that had focus keeps it.
	focusedElement int

	// Whether or not navigating the form will wrap around.
	wrapAround bool

	// The label color.
	labelColor tcell.Color

	// The label color when focused.
	labelColorFocused tcell.Color

	// The background color of the input area.
	fieldBackgroundColor tcell.Color

	// The background color of the input area when focused.
	fieldBackgroundColorFocused tcell.Color

	// The text color of the input area.
	fieldTextColor tcell.Color

	// The text color of the input area when focused.
	fieldTextColorFocused tcell.Color

	// The background color of the buttons.
	buttonBackgroundColor tcell.Color

	// The background color of the buttons when focused.
	buttonBackgroundColorFocused tcell.Color

	// The color of the button text.
	buttonTextColor tcell.Color

	// The color of the button text when focused.
	buttonTextColorFocused tcell.Color

	// An optional function which is called when the user hits Escape.
	cancel func()

	sync.RWMutex
}

// NewForm returns a new form.
func () *Form {
	 := NewBox()
	.SetPadding(1, 1, 1, 1)

	 := &Form{
		Box:                          ,
		itemPadding:                  1,
		labelColor:                   Styles.SecondaryTextColor,
		fieldBackgroundColor:         Styles.MoreContrastBackgroundColor,
		fieldBackgroundColorFocused:  Styles.ContrastBackgroundColor,
		fieldTextColor:               Styles.PrimaryTextColor,
		fieldTextColorFocused:        Styles.PrimaryTextColor,
		buttonBackgroundColor:        Styles.MoreContrastBackgroundColor,
		buttonBackgroundColorFocused: Styles.ContrastBackgroundColor,
		buttonTextColor:              Styles.PrimaryTextColor,
		buttonTextColorFocused:       Styles.PrimaryTextColor,
		labelColorFocused:            ColorUnset,
	}

	.focus = 
	return 
}

// SetItemPadding sets the number of empty rows between form items for vertical
// layouts and the number of empty cells between form items for horizontal
// layouts.
func ( *Form) ( int) {
	.Lock()
	defer .Unlock()

	.itemPadding = 
}

// SetHorizontal sets the direction the form elements are laid out. If set to
// true, instead of positioning them from top to bottom (the default), they are
// positioned from left to right, moving into the next row if there is not
// enough space.
func ( *Form) ( bool) {
	.Lock()
	defer .Unlock()

	.horizontal = 
}

// SetLabelColor sets the color of the labels.
func ( *Form) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.labelColor = 
}

// SetLabelColorFocused sets the color of the labels when focused.
func ( *Form) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.labelColorFocused = 
}

// SetFieldBackgroundColor sets the background color of the input areas.
func ( *Form) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.fieldBackgroundColor = 
}

// SetFieldBackgroundColorFocused sets the background color of the input areas when focused.
func ( *Form) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.fieldBackgroundColorFocused = 
}

// SetFieldTextColor sets the text color of the input areas.
func ( *Form) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.fieldTextColor = 
}

// SetFieldTextColorFocused sets the text color of the input areas when focused.
func ( *Form) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.fieldTextColorFocused = 
}

// SetButtonsAlign sets how the buttons align horizontally, one of AlignLeft
// (the default), AlignCenter, and AlignRight. This is only
func ( *Form) ( int) {
	.Lock()
	defer .Unlock()

	.buttonsAlign = 
}

// SetButtonBackgroundColor sets the background color of the buttons.
func ( *Form) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.buttonBackgroundColor = 
}

// SetButtonBackgroundColorFocused sets the background color of the buttons when focused.
func ( *Form) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.buttonBackgroundColorFocused = 
}

// SetButtonTextColor sets the color of the button texts.
func ( *Form) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.buttonTextColor = 
}

// SetButtonTextColorFocused sets the color of the button texts when focused.
func ( *Form) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.buttonTextColorFocused = 
}

// SetFocus shifts the focus to the form element with the given index, counting
// non-button items first and buttons last. Note that this index is only used
// when the form itself receives focus.
func ( *Form) ( int) {
	.Lock()
	defer .Unlock()

	if  < 0 {
		.focusedElement = 0
	} else if  >= len(.items)+len(.buttons) {
		.focusedElement = len(.items) + len(.buttons)
	} else {
		.focusedElement = 
	}
}

// AddInputField adds an input field to the form. It has a label, an optional
// initial value, a field width (a value of 0 extends it as far as possible),
// an optional accept function to validate the item's value (set to nil to
// accept any text), and an (optional) callback function which is invoked when
// the input field's text has changed.
func ( *Form) (,  string,  int,  func( string,  rune) bool,  func( string)) {
	.Lock()
	defer .Unlock()

	 := NewInputField()
	.SetLabel()
	.SetText()
	.SetFieldWidth()
	.SetAcceptanceFunc()
	.SetChangedFunc()

	.items = append(.items, )
}

// AddPasswordField adds a password field to the form. This is similar to an
// input field except that the user's input not shown. Instead, a "mask"
// character is displayed. The password field has a label, an optional initial
// value, a field width (a value of 0 extends it as far as possible), and an
// (optional) callback function which is invoked when the input field's text has
// changed.
func ( *Form) (,  string,  int,  rune,  func( string)) {
	.Lock()
	defer .Unlock()

	if  == 0 {
		 = '*'
	}

	 := NewInputField()
	.SetLabel()
	.SetText()
	.SetFieldWidth()
	.SetMaskCharacter()
	.SetChangedFunc()

	.items = append(.items, )
}

// AddDropDownSimple adds a drop-down element to the form. It has a label, options,
// and an (optional) callback function which is invoked when an option was
// selected. The initial option may be a negative value to indicate that no
// option is currently selected.
func ( *Form) ( string,  int,  func( int,  *DropDownOption),  ...string) {
	.Lock()
	defer .Unlock()

	 := NewDropDown()
	.SetLabel()
	.SetOptionsSimple(, ...)
	.SetCurrentOption()

	.items = append(.items, )
}

// AddDropDown adds a drop-down element to the form. It has a label, options,
// and an (optional) callback function which is invoked when an option was
// selected. The initial option may be a negative value to indicate that no
// option is currently selected.
func ( *Form) ( string,  int,  func( int,  *DropDownOption),  []*DropDownOption) {
	.Lock()
	defer .Unlock()

	 := NewDropDown()
	.SetLabel()
	.SetOptions(, ...)
	.SetCurrentOption()

	.items = append(.items, )
}

// AddCheckBox adds a checkbox to the form. It has a label, a message, an
// initial state, and an (optional) callback function which is invoked when the
// state of the checkbox was changed by the user.
func ( *Form) ( string,  string,  bool,  func( bool)) {
	.Lock()
	defer .Unlock()

	 := NewCheckBox()
	.SetLabel()
	.SetMessage()
	.SetChecked()
	.SetChangedFunc()

	.items = append(.items, )
}

// AddSlider adds a slider to the form. It has a label, an initial value, a
// maximum value, an amount to increment by when modified via keyboard, and an
// (optional) callback function which is invoked when the state of the slider
// was changed by the user.
func ( *Form) ( string, , ,  int,  func( int)) {
	.Lock()
	defer .Unlock()

	 := NewSlider()
	.SetLabel()
	.SetMax()
	.SetProgress()
	.SetIncrement()
	.SetChangedFunc()

	.items = append(.items, )
}

// AddButton adds a new button to the form. The "selected" function is called
// when the user selects this button. It may be nil.
func ( *Form) ( string,  func()) {
	.Lock()
	defer .Unlock()

	 := NewButton()
	.SetSelectedFunc()
	.buttons = append(.buttons, )
}

// GetButton returns the button at the specified 0-based index. Note that
// buttons have been specially prepared for this form and modifying some of
// their attributes may have unintended side effects.
func ( *Form) ( int) *Button {
	.RLock()
	defer .RUnlock()

	return .buttons[]
}

// RemoveButton removes the button at the specified position, starting with 0
// for the button that was added first.
func ( *Form) ( int) {
	.Lock()
	defer .Unlock()

	.buttons = append(.buttons[:], .buttons[+1:]...)
}

// GetButtonCount returns the number of buttons in this form.
func ( *Form) () int {
	.RLock()
	defer .RUnlock()

	return len(.buttons)
}

// GetButtonIndex returns the index of the button with the given label, starting
// with 0 for the button that was added first. If no such label was found, -1
// is returned.
func ( *Form) ( string) int {
	.RLock()
	defer .RUnlock()

	for ,  := range .buttons {
		if .GetLabel() ==  {
			return 
		}
	}
	return -1
}

// Clear removes all input elements from the form, including the buttons if
// specified.
func ( *Form) ( bool) {
	.Lock()
	defer .Unlock()

	.items = nil
	if  {
		.buttons = nil
	}
	.focusedElement = 0
}

// ClearButtons removes all buttons from the form.
func ( *Form) () {
	.Lock()
	defer .Unlock()

	.buttons = nil
}

// AddFormItem adds a new item to the form. This can be used to add your own
// objects to the form. Note, however, that the Form class will override some
// of its attributes to make it work in the form context. Specifically, these
// are:
//
//   - The label width
//   - The label color
//   - The background color
//   - The field text color
//   - The field background color
func ( *Form) ( FormItem) {
	.Lock()
	defer .Unlock()

	if reflect.ValueOf().IsNil() {
		panic("Invalid FormItem")
	}

	.items = append(.items, )
}

// GetFormItemCount returns the number of items in the form (not including the
// buttons).
func ( *Form) () int {
	.RLock()
	defer .RUnlock()

	return len(.items)
}

// IndexOfFormItem returns the index of the given FormItem.
func ( *Form) ( FormItem) int {
	.l.RLock()
	defer .l.RUnlock()
	for ,  := range .items {
		if  ==  {
			return 
		}
	}
	return -1
}

// GetFormItem returns the form item at the given position, starting with index
// 0. Elements are referenced in the order they were added. Buttons are not included.
// If index is out of bounds it returns nil.
func ( *Form) ( int) FormItem {
	.RLock()
	defer .RUnlock()
	if  > len(.items)-1 ||  < 0 {
		return nil
	}
	return .items[]
}

// RemoveFormItem removes the form element at the given position, starting with
// index 0. Elements are referenced in the order they were added. Buttons are
// not included.
func ( *Form) ( int) {
	.Lock()
	defer .Unlock()

	.items = append(.items[:], .items[+1:]...)
}

// GetFormItemByLabel returns the first form element with the given label. If
// no such element is found, nil is returned. Buttons are not searched and will
// therefore not be returned.
func ( *Form) ( string) FormItem {
	.RLock()
	defer .RUnlock()

	for ,  := range .items {
		if .GetLabel() ==  {
			return 
		}
	}
	return nil
}

// GetFormItemIndex returns the index of the first form element with the given
// label. If no such element is found, -1 is returned. Buttons are not searched
// and will therefore not be returned.
func ( *Form) ( string) int {
	.RLock()
	defer .RUnlock()

	for ,  := range .items {
		if .GetLabel() ==  {
			return 
		}
	}
	return -1
}

// GetFocusedItemIndex returns the indices of the form element or button which
// currently has focus. If they don't, -1 is returned resepectively.
func ( *Form) () (,  int) {
	.RLock()
	defer .RUnlock()

	 := .focusIndex()
	if  < 0 {
		return -1, -1
	}
	if  < len(.items) {
		return , -1
	}
	return -1,  - len(.items)
}

// SetWrapAround sets the flag that determines whether navigating the form will
// wrap around. That is, navigating downwards on the last item will move the
// selection to the first item (similarly in the other direction). If set to
// false, the selection won't change when navigating downwards on the last item
// or navigating upwards on the first item.
func ( *Form) ( bool) {
	.Lock()
	defer .Unlock()

	.wrapAround = 
}

// SetCancelFunc sets a handler which is called when the user hits the Escape
// key.
func ( *Form) ( func()) {
	.Lock()
	defer .Unlock()

	.cancel = 
}

// GetAttributes returns the current attribute settings of a form.
func ( *Form) () *FormItemAttributes {
	.Lock()
	defer .Unlock()

	return .getAttributes()
}

func ( *Form) () *FormItemAttributes {
	 := &FormItemAttributes{
		BackgroundColor:      .backgroundColor,
		LabelColor:           .labelColor,
		FieldBackgroundColor: .fieldBackgroundColor,
		FieldTextColor:       .fieldTextColor,
	}
	if .labelColorFocused == ColorUnset {
		.LabelColorFocused = .labelColor
	} else {
		.LabelColorFocused = .labelColorFocused
	}
	if .fieldBackgroundColorFocused == ColorUnset {
		.FieldBackgroundColorFocused = .fieldTextColor
	} else {
		.FieldBackgroundColorFocused = .fieldBackgroundColorFocused
	}
	if .fieldTextColorFocused == ColorUnset {
		.FieldTextColorFocused = .fieldBackgroundColor
	} else {
		.FieldTextColorFocused = .fieldTextColorFocused
	}
	return 
}

// Draw draws this primitive onto the screen.
func ( *Form) ( tcell.Screen) {
	if !.GetVisible() {
		return
	}

	.Box.Draw()

	.Lock()
	defer .Unlock()

	// Determine the actual item that has focus.
	if  := .focusIndex();  >= 0 {
		.focusedElement = 
	}

	// Determine the dimensions.
	, , ,  := .GetInnerRect()
	 := 
	 :=  + 
	 :=  + 
	 := 

	// Find the longest label.
	var  int
	for ,  := range .items {
		 := TaggedStringWidth(.GetLabel())
		if  >  {
			 = 
		}
	}
	++ // Add one space.

	// Calculate positions of form items.
	 := make([]struct{ , , ,  int }, len(.items)+len(.buttons))
	var  struct{ , , ,  int }
	for ,  := range .items {
		if !.GetVisible() {
			continue
		}

		// Calculate the space needed.
		 := TaggedStringWidth(.GetLabel())
		var  int
		if .horizontal {
			 := .GetFieldWidth()
			if  == 0 {
				 = DefaultFormFieldWidth
			}
			++
			 =  + 
		} else {
			// We want all fields to align vertically.
			 = 
			 = 
		}

		// Advance to next line if there is no space.
		if .horizontal && ++1 >=  {
			 = 
			 += 2
		}

		// Adjust the item's attributes.
		if + >=  {
			 =  - 
		}

		 := .getAttributes()
		.LabelWidth = 
		setFormItemAttributes(, )

		// Save position.
		[]. = 
		[]. = 
		[]. = 
		[]. = 1
		if .GetFocusable().HasFocus() {
			 = []
		}

		// Advance to next item.
		if .horizontal {
			 +=  + .itemPadding
		} else {
			 += .GetFieldHeight() + .itemPadding
		}
	}

	// How wide are the buttons?
	 := make([]int, len(.buttons))
	 := 0
	for ,  := range .buttons {
		 := TaggedStringWidth(.GetLabel()) + 4
		[] = 
		 +=  + 1
	}
	--

	// Where do we place them?
	if !.horizontal && + <  {
		if .buttonsAlign == AlignRight {
			 =  - 
		} else if .buttonsAlign == AlignCenter {
			 = ( +  - ) / 2
		}

		// In vertical layouts, buttons always appear after an empty line.
		if .itemPadding == 0 {
			++
		}
	}

	// Calculate positions of buttons.
	for ,  := range .buttons {
		if !.GetVisible() {
			continue
		}

		 :=  - 
		 := []
		if .horizontal {
			if  < -4 {
				 = 
				 += 2
				 = 
			}
		} else {
			if  < 1 {
				break // No space for this button anymore.
			}
		}
		if  >  {
			 = 
		}
		.SetLabelColor(.buttonTextColor)
		.SetLabelColorFocused(.buttonTextColorFocused)
		.SetBackgroundColorFocused(.buttonBackgroundColorFocused)
		.SetBackgroundColor(.buttonBackgroundColor)

		 :=  + len(.items)
		[]. = 
		[]. = 
		[]. = 
		[]. = 1

		if .HasFocus() {
			 = []
		}

		 +=  + 1
	}

	// Determine vertical offset based on the position of the focused item.
	var  int
	if .+. >  {
		 = . + . - 
		if .- <  {
			 = . - 
		}
	}

	// Draw items.
	for ,  := range .items {
		if !.GetVisible() {
			continue
		}

		// Set position.
		 := []. - 
		 := [].
		.SetRect([]., , []., )

		// Is this item visible?
		if + <=  ||  >=  {
			continue
		}

		// Draw items with focus last (in case of overlaps).
		if .GetFocusable().HasFocus() {
			defer .Draw()
		} else {
			.Draw()
		}
	}

	// Draw buttons.
	for ,  := range .buttons {
		if !.GetVisible() {
			continue
		}

		// Set position.
		 :=  + len(.items)
		 := []. - 
		 := [].
		.SetRect([]., , []., )

		// Is this button visible?
		if + <=  ||  >=  {
			continue
		}

		// Draw button.
		.Draw()
	}
}

func ( *Form) ( bool) {
	 := len(.items)
	 := len(.items) + len(.buttons)
	for  := 0;  < ; ++ {
		if .focusedElement < 0 {
			if .wrapAround {
				.focusedElement =  - 1
			} else {
				.focusedElement = 0
			}
		} else if .focusedElement >=  {
			if .wrapAround {
				.focusedElement = 0
			} else {
				.focusedElement =  - 1
			}
		}

		if .focusedElement <  {
			 := .items[.focusedElement]
			if .GetVisible() {
				break
			}
		} else {
			 := .buttons[.focusedElement-]
			if .GetVisible() {
				break
			}
		}

		if  {
			.focusedElement--
		} else {
			.focusedElement++
		}
	}

}

func ( *Form) ( func( Primitive)) func( tcell.Key) {
	return func( tcell.Key) {
		.Lock()

		switch  {
		case tcell.KeyTab, tcell.KeyEnter:
			.focusedElement++
			.updateFocusedElement(false)
			.Unlock()
			.Focus()
			.Lock()
		case tcell.KeyBacktab:
			.focusedElement--
			.updateFocusedElement(true)
			.Unlock()
			.Focus()
			.Lock()
		case tcell.KeyEscape:
			if .cancel != nil {
				.Unlock()
				.cancel()
				.Lock()
			} else {
				.focusedElement = 0
				.updateFocusedElement(true)
				.Unlock()
				.Focus()
				.Lock()
			}
		}

		.Unlock()
	}
}

// Focus is called by the application when the primitive receives focus.
func ( *Form) ( func( Primitive)) {
	.Lock()
	if len(.items)+len(.buttons) == 0 {
		.hasFocus = true
		.Unlock()
		return
	}
	.hasFocus = false

	// Hand on the focus to one of our child elements.
	if .focusedElement < 0 || .focusedElement >= len(.items)+len(.buttons) {
		.focusedElement = 0
	}

	if .focusedElement < len(.items) {
		// We're selecting an item.
		 := .items[.focusedElement]

		 := .getAttributes()
		.FinishedFunc = .formItemInputHandler()

		.Unlock()

		setFormItemAttributes(, )
		()
	} else {
		// We're selecting a button.
		 := .buttons[.focusedElement-len(.items)]
		.SetBlurFunc(.formItemInputHandler())

		.Unlock()

		()
	}
}

// HasFocus returns whether or not this primitive has focus.
func ( *Form) () bool {
	.Lock()
	defer .Unlock()

	if .hasFocus {
		return true
	}
	return .focusIndex() >= 0
}

// focusIndex returns the index of the currently focused item, counting form
// items first, then buttons. A negative value indicates that no containeed item
// has focus.
func ( *Form) () int {
	for ,  := range .items {
		if .GetVisible() && .GetFocusable().HasFocus() {
			return 
		}
	}
	for ,  := range .buttons {
		if .GetVisible() && .focus.HasFocus() {
			return len(.items) + 
		}
	}
	return -1
}

// MouseHandler returns the mouse handler for this primitive.
func ( *Form) () func( MouseAction,  *tcell.EventMouse,  func( Primitive)) ( bool,  Primitive) {
	return .WrapMouseHandler(func( MouseAction,  *tcell.EventMouse,  func( Primitive)) ( bool,  Primitive) {
		if !.InRect(.Position()) {
			return false, nil
		}

		// Determine items to pass mouse events to.
		for ,  := range .items {
			,  = .MouseHandler()(, , )
			if  {
				return
			}
		}
		for ,  := range .buttons {
			,  = .MouseHandler()(, , )
			if  {
				return
			}
		}

		// A mouse click anywhere else will return the focus to the last selected
		// element.
		if  == MouseLeftClick {
			if .focusedElement < len(.items) {
				(.items[.focusedElement])
			} else if .focusedElement < len(.items)+len(.buttons) {
				(.buttons[.focusedElement-len(.items)])
			}
			 = true
		}

		return
	})
}

func setFormItemAttributes( FormItem,  *FormItemAttributes) {
	.SetLabelWidth(.LabelWidth)
	.SetBackgroundColor(.BackgroundColor)
	.SetLabelColor(.LabelColor)
	.SetLabelColorFocused(.LabelColorFocused)
	.SetFieldTextColor(.FieldTextColor)
	.SetFieldTextColorFocused(.FieldTextColorFocused)
	.SetFieldBackgroundColor(.FieldBackgroundColor)
	.SetFieldBackgroundColorFocused(.FieldBackgroundColorFocused)

	if .FinishedFunc != nil {
		.SetFinishedFunc(.FinishedFunc)
	}
}