func (c *RadioGroup) AddItem(r *Radio) {
	c.items = append(c.items, r)
	r.SetGroup(c)
}

func ( c * RadioGroup ) AddItem ( r * Radio ) { c . items = append ( c . items , r ) r . SetGroup ( c ) }

// AddItem add a new radio button to group


func NewColorParser(str string, defText, defBack term.Attribute) *ColorParser {
	p := new(ColorParser)
	p.text = []rune(str)
	p.defBack, p.defText = defBack, defText
	p.currBack, p.currText = defBack, defText
	return p
}

func NewColorParser ( str string , defText , defBack term . Attribute ) * ColorParser { p := new ( ColorParser ) p . text = [ ] rune ( str ) p . defBack , p . defText = defBack , defText p . currBack , p . currText = defBack , defText return p }

// NewColorParser creates a new string parser.
// str is a string to parse.
// defText is a default text color.
// defBack is a default background color.
// Default colors are applied in case of reset color tag

NewColorParser creates a new string parser . str is a string to parse . defText is a default text color . defBack is a default background color . Default colors are applied in case of reset color tag


func (p *ColorParser) NextElement() TextElement {
	if p.index >= len(p.text) {
		return TextElement{Type: ElemEndOfText}
	}

	if p.text[p.index] == '\n' {
		p.index++
		return TextElement{Type: ElemLineBreak}
	}

	if p.text[p.index] != '<' {
		p.index++
		return TextElement{Type: ElemPrintable, Ch: p.text[p.index-1], Fg: p.currText, Bg: p.currBack}
	}

	attr, atype, ok := p.parseColor()
	if !ok {
		p.index++
		return TextElement{Type: ElemPrintable, Ch: p.text[p.index-1], Fg: p.currText, Bg: p.currBack}
	}

	if atype == ElemBackColor {
		if attr == ColorDefault {
			p.currBack = p.defBack
		} else {
			p.currBack = attr
		}
	} else if atype == ElemTextColor {
		if attr == ColorDefault {
			p.currText = p.defText
		} else {
			p.currText = attr
		}
	}
	return TextElement{Type: atype, Fg: p.currText, Bg: p.currBack}
}

func ( p * ColorParser ) NextElement ( ) TextElement { if p . index >= len ( p . text ) { return TextElement { Type : ElemEndOfText } } if p . text [ p . index ] == '\n' { p . index ++ return TextElement { Type : ElemLineBreak } } if p . text [ p . index ] != '<' { p . index ++ return TextElement { Type : ElemPrintable , Ch : p . text [ p . index - 1 ] , Fg : p . currText , Bg : p . currBack } } attr , atype , ok := p . parseColor ( ) if ! ok { p . index ++ return TextElement { Type : ElemPrintable , Ch : p . text [ p . index - 1 ] , Fg : p . currText , Bg : p . currBack } } if atype == ElemBackColor { if attr == ColorDefault { p . currBack = p . defBack } else { p . currBack = attr } } else if atype == ElemTextColor { if attr == ColorDefault { p . currText = p . defText } else { p . currText = attr } } return TextElement { Type : atype , Fg : p . currText , Bg : p . currBack } }

// NextElement parses and returns the next string element


func (e *EditField) SetTitle(title string) {
	e.setTitleInternal(title)
	e.offset = 0
	e.end()
}

func ( e * EditField ) SetTitle ( title string ) { e . setTitleInternal ( title ) e . offset = 0 e . end ( ) }

// SetTitle changes the EditField content and emits OnChage eventif the new value does not equal to old one


func (e *EditField) SetMaxWidth(w int) {
	e.maxWidth = w
	if w > 0 && xs.Len(e.title) > w {
		e.title = xs.Slice(e.title, 0, w)
		e.end()
	}
}

func ( e * EditField ) SetMaxWidth ( w int ) { e . maxWidth = w if w > 0 && xs . Len ( e . title ) > w { e . title = xs . Slice ( e . title , 0 , w ) e . end ( ) } }

// SetMaxWidth sets the maximum lenght of the EditField text. If the current text is longer it is truncated

SetMaxWidth sets the maximum lenght of the EditField text . If the current text is longer it is truncated


func (e *EditField) SetSize(width, height int) {
	if width != KeepValue && (width > 1000 || width < e.minW) {
		return
	}
	if height != KeepValue && (height > 200 || height < e.minH) {
		return
	}

	if width != KeepValue {
		e.width = width
	}

	e.height = 1
}

func ( e * EditField ) SetSize ( width , height int ) { if width != KeepValue && ( width > 1000 || width < e . minW ) { return } if height != KeepValue && ( height > 200 || height < e . minH ) { return } if width != KeepValue { e . width = width } e . height = 1 }

// SetSize changes control size. Constant DoNotChange can be
// used as placeholder to indicate that the control attrubute
// should be unchanged.
// Method does nothing if new size is less than minimal size
// EditField height cannot be changed - it equals 1 always

SetSize changes control size . Constant DoNotChange can be used as placeholder to indicate that the control attrubute should be unchanged . Method does nothing if new size is less than minimal size EditField height cannot be changed - it equals 1 always


func PopAttributes() {
	if len(canvas.attrStack) == 0 {
		return
	}
	a := canvas.attrStack[len(canvas.attrStack)-1]
	canvas.attrStack = canvas.attrStack[:len(canvas.attrStack)-1]
	SetTextColor(a.text)
	SetBackColor(a.back)
}

func PopAttributes ( ) { if len ( canvas . attrStack ) == 0 { return } a := canvas . attrStack [ len ( canvas . attrStack ) - 1 ] canvas . attrStack = canvas . attrStack [ : len ( canvas . attrStack ) - 1 ] SetTextColor ( a . text ) SetBackColor ( a . back ) }

// PopAttributes restores saved with PushAttributes colors. Function does
// nothing if there is no saved colors

PopAttributes restores saved with PushAttributes colors . Function does nothing if there is no saved colors


func PushClip() {
	c := rect{x: canvas.clipX, y: canvas.clipY, w: canvas.clipW, h: canvas.clipH}
	canvas.clipStack = append(canvas.clipStack, c)
}

func PushClip ( ) { c := rect { x : canvas . clipX , y : canvas . clipY , w : canvas . clipW , h : canvas . clipH } canvas . clipStack = append ( canvas . clipStack , c ) }

// PushClip saves the current clipping window


func PopClip() {
	if len(canvas.clipStack) == 0 {
		return
	}
	c := canvas.clipStack[len(canvas.clipStack)-1]
	canvas.clipStack = canvas.clipStack[:len(canvas.clipStack)-1]
	SetClipRect(c.x, c.y, c.w, c.h)
}

func PopClip ( ) { if len ( canvas . clipStack ) == 0 { return } c := canvas . clipStack [ len ( canvas . clipStack ) - 1 ] canvas . clipStack = canvas . clipStack [ : len ( canvas . clipStack ) - 1 ] SetClipRect ( c . x , c . y , c . w , c . h ) }

// PopClip restores saved with PushClip clipping window


func InClipRect(x, y int) bool {
	return x >= canvas.clipX && y >= canvas.clipY &&
		x < canvas.clipX+canvas.clipW &&
		y < canvas.clipY+canvas.clipH
}

func InClipRect ( x , y int ) bool { return x >= canvas . clipX && y >= canvas . clipY && x < canvas . clipX + canvas . clipW && y < canvas . clipY + canvas . clipH }

// InClipRect returns true if x and y position is inside current clipping
// rectangle

InClipRect returns true if x and y position is inside current clipping rectangle


func SetScreenSize(width int, height int) {
	if canvas.width == width && canvas.height == height {
		return
	}

	canvas.width = width
	canvas.height = height

	canvas.clipStack = make([]rect, 0)
	SetClipRect(0, 0, width, height)
}

func SetScreenSize ( width int , height int ) { if canvas . width == width && canvas . height == height { return } canvas . width = width canvas . height = height canvas . clipStack = make ( [ ] rect , 0 ) SetClipRect ( 0 , 0 , width , height ) }

// SetSize sets the new Canvas size. If new size does not
// equal old size then Canvas is recreated and cleared
// with default colors. Both Canvas width and height must
// be greater than 2

SetSize sets the new Canvas size . If new size does not equal old size then Canvas is recreated and cleared with default colors . Both Canvas width and height must be greater than 2


func Symbol(x, y int) (term.Cell, bool) {
	if x >= 0 && x < canvas.width && y >= 0 && y < canvas.height {
		cells := term.CellBuffer()
		return cells[y*canvas.width+x], true
	}
	return term.Cell{Ch: ' '}, false
}

func
Symbol
(
x
,
y
int
)
(
term
.
Cell
,
bool
)
{
if
x
>=
0
&&
x
<
canvas
.
width
&&
y
>=
0
&&
y
<
canvas
.
height
{
cells
:=
term
.
CellBuffer
(
)
return
cells
[
y
*
canvas
.
width
+
x
]
,
true
}
return
term
.
Cell
{
Ch
:
' '
}
,
false
}

// Symbol returns the character and its attributes by its coordinates


func SetClipRect(x, y, w, h int) {
	if x < 0 {
		x = 0
	}
	if y < 0 {
		y = 0
	}
	if x+w > canvas.width {
		w = canvas.width - x
	}
	if y+h > canvas.height {
		h = canvas.height - h
	}

	canvas.clipX = x
	canvas.clipY = y
	canvas.clipW = w
	canvas.clipH = h
}

func SetClipRect ( x , y , w , h int ) { if x < 0 { x = 0 } if y < 0 { y = 0 } if x + w > canvas . width { w = canvas . width - x } if y + h > canvas . height { h = canvas . height - h } canvas . clipX = x canvas . clipY = y canvas . clipW = w canvas . clipH = h }

// SetClipRect defines a new clipping rect. Maybe useful with PopClip and
// PushClip functions

SetClipRect defines a new clipping rect . Maybe useful with PopClip and PushClip functions


func ClipRect() (x int, y int, w int, h int) {
	return canvas.clipX, canvas.clipY, canvas.clipW, canvas.clipH
}

func ClipRect ( ) ( x int , y int , w int , h int ) { return canvas . clipX , canvas . clipY , canvas . clipW , canvas . clipH }

// ClipRect returns the current clipping rectangle


func DrawHorizontalLine(x, y, w int, r rune) {
	x, y, w, _ = clip(x, y, w, 1)
	if w == 0 {
		return
	}

	for i := x; i < x+w; i++ {
		putCharUnsafe(i, y, r)
	}
}

func DrawHorizontalLine ( x , y , w int , r rune ) { x , y , w , _ = clip ( x , y , w , 1 ) if w == 0 { return } for i := x ; i < x + w ; i ++ { putCharUnsafe ( i , y , r ) } }

// DrawHorizontalLine draws the part of the horizontal line that is inside
// current clipping rectangle

DrawHorizontalLine draws the part of the horizontal line that is inside current clipping rectangle


func DrawVerticalLine(x, y, h int, r rune) {
	x, y, _, h = clip(x, y, 1, h)
	if h == 0 {
		return
	}

	for i := y; i < y+h; i++ {
		putCharUnsafe(x, i, r)
	}
}

func DrawVerticalLine ( x , y , h int , r rune ) { x , y , _ , h = clip ( x , y , 1 , h ) if h == 0 { return } for i := y ; i < y + h ; i ++ { putCharUnsafe ( x , i , r ) } }

// DrawVerticalLine draws the part of the vertical line that is inside current
// clipping rectangle

DrawVerticalLine draws the part of the vertical line that is inside current clipping rectangle


func DrawRawText(x, y int, text string) {
	cx, cy, cw, ch := ClipRect()
	if x >= cx+cw || y < cy || y >= cy+ch {
		return
	}

	length := xs.Len(text)
	if x+length < cx {
		return
	}

	if x < cx {
		text = xs.Slice(text, cx-x, -1)
		length = length - (cx - x)
		x = cx
	}
	text = CutText(text, cw)

	dx := 0
	for _, ch := range text {
		putCharUnsafe(x+dx, y, ch)
		dx++
	}
}

func DrawRawText ( x , y int , text string ) { cx , cy , cw , ch := ClipRect ( ) if x >= cx + cw || y < cy || y >= cy + ch { return } length := xs . Len ( text ) if x + length < cx { return } if x < cx { text = xs . Slice ( text , cx - x , - 1 ) length = length - ( cx - x ) x = cx } text = CutText ( text , cw ) dx := 0 for _ , ch := range text { putCharUnsafe ( x + dx , y , ch ) dx ++ } }

// DrawRawText draws the part of text that is inside the current clipping
// rectangle. DrawRawText always paints string as is - no color changes.
// If you want to draw string with color changing commands included then
// use DrawText function

DrawRawText draws the part of text that is inside the current clipping rectangle . DrawRawText always paints string as is - no color changes . If you want to draw string with color changing commands included then use DrawText function


func DrawTextVertical(x, y int, text string) {
	PushAttributes()
	defer PopAttributes()

	defText, defBack := TextColor(), BackColor()
	firstdrawn := InClipRect(x, y)

	parser := NewColorParser(text, defText, defBack)
	elem := parser.NextElement()
	for elem.Type != ElemEndOfText {
		if elem.Type == ElemPrintable {
			SetTextColor(elem.Fg)
			SetBackColor(elem.Bg)
			drawn := PutChar(x, y, elem.Ch)
			y += 1
			if firstdrawn && !drawn {
				break
			}
		}

		elem = parser.NextElement()
	}
}

func DrawTextVertical ( x , y int , text string ) { PushAttributes ( ) defer PopAttributes ( ) defText , defBack := TextColor ( ) , BackColor ( ) firstdrawn := InClipRect ( x , y ) parser := NewColorParser ( text , defText , defBack ) elem := parser . NextElement ( ) for elem . Type != ElemEndOfText { if elem . Type == ElemPrintable { SetTextColor ( elem . Fg ) SetBackColor ( elem . Bg ) drawn := PutChar ( x , y , elem . Ch ) y += 1 if firstdrawn && ! drawn { break } } elem = parser . NextElement ( ) } }

// DrawTextVertical draws the part of text that is inside the current clipping
// rectangle. DrawTextVertical always paints colorized string. If you want to draw
// raw string then use DrawRawTextVertical function

DrawTextVertical draws the part of text that is inside the current clipping rectangle . DrawTextVertical always paints colorized string . If you want to draw raw string then use DrawRawTextVertical function


func DrawRawTextVertical(x, y int, text string) {
	cx, cy, cw, ch := ClipRect()
	if y >= cy+ch || x < cx || x >= cx+cw {
		return
	}

	length := xs.Len(text)
	if y+length < cy {
		return
	}

	if y < cy {
		text = xs.Slice(text, cy-y, -1)
		length = length - (cy - y)
		y = cy
	}
	text = CutText(text, ch)

	dy := 0
	for _, ch := range text {
		putCharUnsafe(x, y+dy, ch)
		dy++
	}
}

func DrawRawTextVertical ( x , y int , text string ) { cx , cy , cw , ch := ClipRect ( ) if y >= cy + ch || x < cx || x >= cx + cw { return } length := xs . Len ( text ) if y + length < cy { return } if y < cy { text = xs . Slice ( text , cy - y , - 1 ) length = length - ( cy - y ) y = cy } text = CutText ( text , ch ) dy := 0 for _ , ch := range text { putCharUnsafe ( x , y + dy , ch ) dy ++ } }

// DrawRawTextVertical draws the part of text that is inside the current clipping
// rectangle. DrawRawTextVertical always paints string as is - no color changes.
// If you want to draw string with color changing commands included then
// use DrawTextVertical function

DrawRawTextVertical draws the part of text that is inside the current clipping rectangle . DrawRawTextVertical always paints string as is - no color changes . If you want to draw string with color changing commands included then use DrawTextVertical function


func DrawFrame(x, y, w, h int, border BorderStyle) {
	var chars string
	if border == BorderThick {
		chars = SysObject(ObjDoubleBorder)
	} else if border == BorderThin {
		chars = SysObject(ObjSingleBorder)
	} else if border == BorderNone {
		chars = "      "
	} else {
		chars = "      "
	}

	parts := []rune(chars)
	H, V, UL, UR, DL, DR := parts[0], parts[1], parts[2], parts[3], parts[4], parts[5]

	if InClipRect(x, y) {
		putCharUnsafe(x, y, UL)
	}
	if InClipRect(x+w-1, y+h-1) {
		putCharUnsafe(x+w-1, y+h-1, DR)
	}
	if InClipRect(x, y+h-1) {
		putCharUnsafe(x, y+h-1, DL)
	}
	if InClipRect(x+w-1, y) {
		putCharUnsafe(x+w-1, y, UR)
	}

	var xx, yy, ww, hh int
	xx, yy, ww, _ = clip(x+1, y, w-2, 1)
	if ww > 0 {
		DrawHorizontalLine(xx, yy, ww, H)
	}
	xx, yy, ww, _ = clip(x+1, y+h-1, w-2, 1)
	if ww > 0 {
		DrawHorizontalLine(xx, yy, ww, H)
	}
	xx, yy, _, hh = clip(x, y+1, 1, h-2)
	if hh > 0 {
		DrawVerticalLine(xx, yy, hh, V)
	}
	xx, yy, _, hh = clip(x+w-1, y+1, 1, h-2)
	if hh > 0 {
		DrawVerticalLine(xx, yy, hh, V)
	}
}

func DrawFrame ( x , y , w , h int , border BorderStyle ) { var chars string if border == BorderThick { chars = SysObject ( ObjDoubleBorder ) } else if border == BorderThin { chars = SysObject ( ObjSingleBorder ) } else if border == BorderNone { chars = " " } else { chars = " " } parts := [ ] rune ( chars ) H , V , UL , UR , DL , DR := parts [ 0 ] , parts [ 1 ] , parts [ 2 ] , parts [ 3 ] , parts [ 4 ] , parts [ 5 ] if InClipRect ( x , y ) { putCharUnsafe ( x , y , UL ) } if InClipRect ( x + w - 1 , y + h - 1 ) { putCharUnsafe ( x + w - 1 , y + h - 1 , DR ) } if InClipRect ( x , y + h - 1 ) { putCharUnsafe ( x , y + h - 1 , DL ) } if InClipRect ( x + w - 1 , y ) { putCharUnsafe ( x + w - 1 , y , UR ) } var xx , yy , ww , hh int xx , yy , ww , _ = clip ( x + 1 , y , w - 2 , 1 ) if ww > 0 { DrawHorizontalLine ( xx , yy , ww , H ) } xx , yy , ww , _ = clip ( x + 1 , y + h - 1 , w - 2 , 1 ) if ww > 0 { DrawHorizontalLine ( xx , yy , ww , H ) } xx , yy , _ , hh = clip ( x , y + 1 , 1 , h - 2 ) if hh > 0 { DrawVerticalLine ( xx , yy , hh , V ) } xx , yy , _ , hh = clip ( x + w - 1 , y + 1 , 1 , h - 2 ) if hh > 0 { DrawVerticalLine ( xx , yy , hh , V ) } }

// DrawFrame paints the frame without changing area inside it


func FillRect(x, y, w, h int, r rune) {
	x, y, w, h = clip(x, y, w, h)
	if w < 1 || y < -1 {
		return
	}

	for yy := y; yy < y+h; yy++ {
		for xx := x; xx < x+w; xx++ {
			putCharUnsafe(xx, yy, r)
		}
	}
}

func FillRect ( x , y , w , h int , r rune ) { x , y , w , h = clip ( x , y , w , h ) if w < 1 || y < - 1 { return } for yy := y ; yy < y + h ; yy ++ { for xx := x ; xx < x + w ; xx ++ { putCharUnsafe ( xx , yy , r ) } } }

// FillRect paints the area with r character using the current colors


func TextExtent(text string) (int, int) {
	if text == "" {
		return 0, 0
	}
	parts := strings.Split(text, "\n")
	h := len(parts)
	w := 0
	for _, p := range parts {
		s := UnColorizeText(p)
		l := len(s)
		if l > w {
			w = l
		}
	}

	return h, w
}

func TextExtent ( text string ) ( int , int ) { if text == " " { return 0 , 0 } parts := strings . Split ( text , " \n " ) h := len ( parts ) w := 0 for _ , p := range parts { s := UnColorizeText ( p ) l := len ( s ) if l > w { w = l } } return h , w }

// TextExtent calculates the width and the height of the text


func (l *ListBox) EnsureVisible() {
	length := len(l.items)

	if length <= l.height || l.currSelection == -1 {
		return
	}

	diff := l.currSelection - l.topLine
	if diff >= 0 && diff < l.height {
		return
	}

	if diff < 0 {
		l.topLine = l.currSelection
	} else {
		top := l.currSelection - l.height + 1
		if length-top > l.height {
			l.topLine = top
		} else {
			l.topLine = length - l.height
		}
	}
}

func ( l * ListBox ) EnsureVisible ( ) { length := len ( l . items ) if length <= l . height || l . currSelection == - 1 { return } diff := l . currSelection - l . topLine if diff >= 0 && diff < l . height { return } if diff < 0 { l . topLine = l . currSelection } else { top := l . currSelection - l . height + 1 if length - top > l . height { l . topLine = top } else { l . topLine = length - l . height } } }

// EnsureVisible makes the currently selected item visible and scrolls the item list if it is required


func (l *ListBox) Clear() {
	l.items = make([]string, 0)
	l.currSelection = -1
	l.topLine = 0
}

func ( l * ListBox ) Clear ( ) { l . items = make ( [ ] string , 0 ) l . currSelection = - 1 l . topLine = 0 }


func (l *ListBox) AddItem(item string) bool {
	l.items = append(l.items, item)
	return true
}

func ( l * ListBox ) AddItem ( item string ) bool { l . items = append ( l . items , item ) return true }

// own methods
// AddItem adds a new item to item list.
// Returns true if the operation is successful

own methods AddItem adds a new item to item list . Returns true if the operation is successful


func (l *ListBox) SelectItem(id int) bool {
	if len(l.items) <= id || id < 0 {
		return false
	}

	l.currSelection = id
	l.EnsureVisible()
	return true
}

func ( l * ListBox ) SelectItem ( id int ) bool { if len ( l . items ) <= id || id < 0 { return false } l . currSelection = id l . EnsureVisible ( ) return true }

// SelectItem selects item which number in the list equals
// id. If the item exists the ListBox scrolls the list to
// make the item visible.
// Returns true if the item is selected successfully

SelectItem selects item which number in the list equals id . If the item exists the ListBox scrolls the list to make the item visible . Returns true if the item is selected successfully


func (l *ListBox) Item(id int) (string, bool) {
	if len(l.items) <= id || id < 0 {
		return "", false
	}

	return l.items[id], true
}

func ( l * ListBox ) Item ( id int ) ( string , bool ) { if len ( l . items ) <= id || id < 0 { return " " , false } return l . items [ id ] , true }

// Item returns item text by its index.
// If index is out of range an empty string and false are returned

Item returns item text by its index . If index is out of range an empty string and false are returned


func (l *ListBox) FindItem(text string, caseSensitive bool) int {
	for idx, itm := range l.items {
		if itm == text || (caseSensitive && strings.EqualFold(itm, text)) {
			return idx
		}
	}

	return -1
}

func ( l * ListBox ) FindItem ( text string , caseSensitive bool ) int { for idx , itm := range l . items { if itm == text || ( caseSensitive && strings . EqualFold ( itm , text ) ) { return idx } } return - 1 }

// FindItem looks for an item in list which text equals
// to text, by default the search is casesensitive.
// Returns item number in item list or -1 if nothing is found.

FindItem looks for an item in list which text equals to text by default the search is casesensitive . Returns item number in item list or - 1 if nothing is found .


func (l *ListBox) PartialFindItem(text string, caseSensitive bool) int {
	if !caseSensitive {
		text = strings.ToLower(text)
	}

	for idx, itm := range l.items {
		if caseSensitive {
			if strings.HasPrefix(itm, text) {
				return idx
			}
		} else {
			low := strings.ToLower(itm)
			if strings.HasPrefix(low, text) {
				return idx
			}
		}
	}

	return -1
}

func ( l * ListBox ) PartialFindItem ( text string , caseSensitive bool ) int { if ! caseSensitive { text = strings . ToLower ( text ) } for idx , itm := range l . items { if caseSensitive { if strings . HasPrefix ( itm , text ) { return idx } } else { low := strings . ToLower ( itm ) if strings . HasPrefix ( low , text ) { return idx } } } return - 1 }

// PartialFindItem looks for an item in list which text starts from
// the given substring, by default the search is casesensitive.
// Returns item number in item list or -1 if nothing is found.

PartialFindItem looks for an item in list which text starts from the given substring by default the search is casesensitive . Returns item number in item list or - 1 if nothing is found .


func (l *ListBox) SelectedItemText() string {
	if l.currSelection == -1 {
		return ""
	}

	return l.items[l.currSelection]
}

func ( l * ListBox ) SelectedItemText ( ) string { if l . currSelection == - 1 { return " " } return l . items [ l . currSelection ] }

// SelectedItemText returns text of currently selected item or empty sting if nothing is
// selected or ListBox is empty.

SelectedItemText returns text of currently selected item or empty sting if nothing is selected or ListBox is empty .


func (l *ListBox) RemoveItem(id int) bool {
	if id < 0 || id >= len(l.items) {
		return false
	}

	l.items = append(l.items[:id], l.items[id+1:]...)
	return true
}

func ( l * ListBox ) RemoveItem ( id int ) bool { if id < 0 || id >= len ( l . items ) { return false } l . items = append ( l . items [ : id ] , l . items [ id + 1 : ] ... ) return true }

// RemoveItem deletes an item which number is id in item list
// Returns true if item is deleted

RemoveItem deletes an item which number is id in item list Returns true if item is deleted


func SysColor(color string) term.Attribute {
	thememtx.RLock()
	sch, ok := themeManager.themes[themeManager.current]
	if !ok {
		sch = themeManager.themes[defaultTheme]
	}
	thememtx.RUnlock()

	clr, okclr := sch.colors[color]
	if !okclr {
		visited := make(map[string]int, 0)
		visited[themeManager.current] = 1
		if !ok {
			visited[defaultTheme] = 1
		}

		for {
			if sch.parent == "" {
				break
			}
			themeManager.loadTheme(sch.parent)
			thememtx.RLock()
			sch = themeManager.themes[sch.parent]
			clr, okclr = sch.colors[color]
			thememtx.RUnlock()

			if ok {
				break
			} else {
				if _, okSch := visited[sch.parent]; okSch {
					panic("Color + " + color + ". Theme loop detected: " + sch.title + " --> " + sch.parent)
				} else {
					visited[sch.parent] = 1
				}
			}
		}
	}

	return clr
}

func SysColor ( color string ) term . Attribute { thememtx . RLock ( ) sch , ok := themeManager . themes [ themeManager . current ] if ! ok { sch = themeManager . themes [ defaultTheme ] } thememtx . RUnlock ( ) clr , okclr := sch . colors [ color ] if ! okclr { visited := make ( map [ string ] int , 0 ) visited [ themeManager . current ] = 1 if ! ok { visited [ defaultTheme ] = 1 } for { if sch . parent == " " { break } themeManager . loadTheme ( sch . parent ) thememtx . RLock ( ) sch = themeManager . themes [ sch . parent ] clr , okclr = sch . colors [ color ] thememtx . RUnlock ( ) if ok { break } else { if _ , okSch := visited [ sch . parent ] ; okSch { panic ( " " + color + " " + sch . title + " " + sch . parent ) } else { visited [ sch . parent ] = 1 } } } } return clr }

// SysColor returns attribute by its id for the current theme.
// The method panics if theme loop is detected - check if
// parent attribute is correct

SysColor returns attribute by its id for the current theme . The method panics if theme loop is detected - check if parent attribute is correct


func SysObject(object string) string {
	thememtx.RLock()
	sch, ok := themeManager.themes[themeManager.current]
	if !ok {
		sch = themeManager.themes[defaultTheme]
	}
	thememtx.RUnlock()

	obj, okobj := sch.objects[object]
	if !okobj {
		visited := make(map[string]int, 0)
		visited[themeManager.current] = 1
		if !ok {
			visited[defaultTheme] = 1
		}

		for {
			if sch.parent == "" {
				break
			}

			themeManager.loadTheme(sch.parent)
			thememtx.RLock()
			sch = themeManager.themes[sch.parent]
			obj, okobj = sch.objects[object]
			thememtx.RUnlock()

			if ok {
				break
			} else {
				if _, okSch := visited[sch.parent]; okSch {
					panic("Object: " + object + ". Theme loop detected: " + sch.title + " --> " + sch.parent)
				} else {
					visited[sch.parent] = 1
				}
			}
		}
	}

	return obj
}

func SysObject ( object string ) string { thememtx . RLock ( ) sch , ok := themeManager . themes [ themeManager . current ] if ! ok { sch = themeManager . themes [ defaultTheme ] } thememtx . RUnlock ( ) obj , okobj := sch . objects [ object ] if ! okobj { visited := make ( map [ string ] int , 0 ) visited [ themeManager . current ] = 1 if ! ok { visited [ defaultTheme ] = 1 } for { if sch . parent == " " { break } themeManager . loadTheme ( sch . parent ) thememtx . RLock ( ) sch = themeManager . themes [ sch . parent ] obj , okobj = sch . objects [ object ] thememtx . RUnlock ( ) if ok { break } else { if _ , okSch := visited [ sch . parent ] ; okSch { panic ( " " + object + " " + sch . title + " " + sch . parent ) } else { visited [ sch . parent ] = 1 } } } } return obj }

// SysObject returns object look by its id for the current
// theme. E.g, border lines for frame or arrows for scrollbar.
// The method panics if theme loop is detected - check if
// parent attribute is correct

SysObject returns object look by its id for the current theme . E . g border lines for frame or arrows for scrollbar . The method panics if theme loop is detected - check if parent attribute is correct


func SetThemePath(path string) {
	if path == themeManager.themePath {
		return
	}

	themeManager.themePath = path
	ThemeReset()
}

func SetThemePath ( path string ) { if path == themeManager . themePath { return } themeManager . themePath = path ThemeReset ( ) }

// SetThemePath changes the directory that contains themes.
// If new path does not equal old one, theme list reloads

SetThemePath changes the directory that contains themes . If new path does not equal old one theme list reloads


func (s *ThemeManager) loadTheme(name string) {
	thememtx.Lock()
	defer thememtx.Unlock()

	if _, ok := s.themes[name]; ok {
		return
	}

	theme := theme{parent: defaultTheme, title: "", author: ""}
	theme.colors = make(map[string]term.Attribute, 0)
	theme.objects = make(map[string]string, 0)

	file, err := os.Open(s.themePath + string(os.PathSeparator) + name + themeSuffix)
	if err != nil {
		panic("Failed to open theme " + name + " : " + err.Error())
	}
	defer file.Close()
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		line = strings.TrimSpace(line)

		// skip comments
		if strings.HasPrefix(line, "#") || strings.HasPrefix(line, "/") {
			continue
		}

		// skip invalid lines
		if !strings.Contains(line, "=") {
			continue
		}

		parts := strings.SplitN(line, "=", 2)
		key := strings.TrimSpace(parts[0])
		value := strings.TrimSpace(parts[1])

		if (strings.HasPrefix(value, "'") && strings.HasSuffix(value, "'")) ||
			(strings.HasPrefix(value, "\"") && strings.HasSuffix(value, "\"")) {
			toTrim, _ := utf8.DecodeRuneInString(value)
			value = strings.Trim(value, string(toTrim))
		}

		low := strings.ToLower(key)
		if low == "parent" {
			theme.parent = value
		} else if low == "author" {
			theme.author = value
		} else if low == "name" || low == "title" {
			theme.title = value
		} else if low == "version" {
			theme.version = value
		} else if strings.HasSuffix(key, "Back") || strings.HasSuffix(key, "Text") {
			// the first case is a reference to existing color (of this or parent theme)
			// the second is the real color
			if strings.HasSuffix(value, "Back") || strings.HasSuffix(value, "Text") {
				clr, ok := theme.colors[value]
				if !ok {
					v := value
					// if color starts with 'parent.' it means the parent color
					// must be used always. It may be useful to load inversed
					// text and background colors of parent theme
					if strings.HasPrefix(v, "parent.") {
						v = strings.TrimPrefix(v, "parent.")
					}
					sch, schOk := s.themes[theme.parent]
					if schOk {
						clr, ok = sch.colors[v]
					} else {
						panic(fmt.Sprintf("%v: Parent theme '%v' not found", name, theme.parent))
					}
				}
				if ok {
					theme.colors[key] = clr
				} else {
					panic(fmt.Sprintf("%v: Failed to find color '%v' by reference", name, value))
				}
			} else {
				c := StringToColor(value)
				if c%32 == 0 {
					panic("Failed to read color: " + value)
				}
				theme.colors[key] = c
			}
		} else {
			theme.objects[key] = value
		}
	}

	s.themes[name] = theme
}

// loadTheme loads the theme if it is not in the cache already.
// If theme is in the cache loadTheme does nothing

loadTheme loads the theme if it is not in the cache already . If theme is in the cache loadTheme does nothing


func ReloadTheme(name string) {
	if name == defaultTheme {
		// default theme cannot be reloaded
		return
	}

	thememtx.Lock()
	if _, ok := themeManager.themes[name]; ok {
		delete(themeManager.themes, name)
	}
	thememtx.Unlock()

	themeManager.loadTheme(name)
}

func
ReloadTheme
(
name
string
)
{
if
name
==
defaultTheme
{
// default theme cannot be reloaded
return
}
thememtx
.
Lock
(
)
if
_
,
ok
:=
themeManager
.
themes
[
name
]
;
ok
{
delete
(
themeManager
.
themes
,
name
)
}
thememtx
.
Unlock
(
)
themeManager
.
loadTheme
(
name
)
}

// ReloadTheme refresh cache entry for the theme with new
// data loaded from file. Use it to apply theme changes on
// the fly without resetting manager or restarting application

ReloadTheme refresh cache entry for the theme with new data loaded from file . Use it to apply theme changes on the fly without resetting manager or restarting application


func ThemeInfo(name string) ThemeDesc {
	themeManager.loadTheme(name)

	thememtx.RLock()
	defer thememtx.RUnlock()

	var theme ThemeDesc
	if t, ok := themeManager.themes[name]; !ok {
		theme.parent = t.parent
		theme.title = t.title
		theme.version = t.version
	}
	return theme
}

func ThemeInfo ( name string ) ThemeDesc { themeManager . loadTheme ( name ) thememtx . RLock ( ) defer thememtx . RUnlock ( ) var theme ThemeDesc if t , ok := themeManager . themes [ name ] ; ! ok { theme . parent = t . parent theme . title = t . title theme . version = t . version } return theme }

// ThemeInfo returns detailed info about theme


func Ellipsize(str string, maxWidth int) string {
	ln := xs.Len(str)
	if ln <= maxWidth {
		return str
	}

	if maxWidth < 5 {
		return xs.Slice(str, 0, maxWidth)
	}

	left := int((maxWidth - 3) / 2)
	right := maxWidth - left - 3
	return xs.Slice(str, 0, left) + "..." + xs.Slice(str, ln-right, -1)
}

func Ellipsize ( str string , maxWidth int ) string { ln := xs . Len ( str ) if ln <= maxWidth { return str } if maxWidth < 5 { return xs . Slice ( str , 0 , maxWidth ) } left := int ( ( maxWidth - 3 ) / 2 ) right := maxWidth - left - 3 return xs . Slice ( str , 0 , left ) + " " + xs . Slice ( str , ln - right , - 1 ) }

// Ellipsize truncates text to maxWidth by replacing a
// substring in the middle with ellipsis and keeping
// the beginning and ending of the string untouched.
// If maxWidth is less than 5 then no ellipsis is
// added, the text is just truncated from the right.

Ellipsize truncates text to maxWidth by replacing a substring in the middle with ellipsis and keeping the beginning and ending of the string untouched . If maxWidth is less than 5 then no ellipsis is added the text is just truncated from the right .


func CutText(str string, maxWidth int) string {
	ln := xs.Len(str)
	if ln <= maxWidth {
		return str
	}

	return xs.Slice(str, 0, maxWidth)
}

func CutText ( str string , maxWidth int ) string { ln := xs . Len ( str ) if ln <= maxWidth { return str } return xs . Slice ( str , 0 , maxWidth ) }

// CutText makes a text no longer than maxWidth


func AlignText(str string, width int, align Align) (shift int, out string) {
	length := xs.Len(str)

	if length >= width {
		return 0, CutText(str, width)
	}

	if align == AlignRight {
		return width - length, str
	} else if align == AlignCenter {
		return (width - length) / 2, str
	}

	return 0, str
}

func AlignText ( str string , width int , align Align ) ( shift int , out string ) { length := xs . Len ( str ) if length >= width { return 0 , CutText ( str , width ) } if align == AlignRight { return width - length , str } else if align == AlignCenter { return ( width - length ) / 2 , str } return 0 , str }

// AlignText calculates the initial position of the text
// output depending on str length and available width.
// The str is truncated in case of its lenght greater than
// width. Function returns shift that should be added to
// original label position before output instead of padding
// the string with spaces. The reason is to make possible
// to draw a label aligned but with transparent beginning
// and ending. If you do not need transparency you can
// add spaces manually using the returned shift value

AlignText calculates the initial position of the text output depending on str length and available width . The str is truncated in case of its lenght greater than width . Function returns shift that should be added to original label position before output instead of padding the string with spaces . The reason is to make possible to draw a label aligned but with transparent beginning and ending . If you do not need transparency you can add spaces manually using the returned shift value


func SliceColorized(str string, start, end int) string {
	if str == "" {
		return str
	}
	if start < 0 {
		start = 0
	}

	fgChanged, bgChanged := false, false
	curr := 0
	parser := NewColorParser(str, term.ColorBlack, term.ColorBlack)
	var out string
	for {
		if end != -1 && curr >= end {
			break
		}
		elem := parser.NextElement()
		if elem.Type == ElemEndOfText {
			break
		}

		switch elem.Type {
		case ElemTextColor:
			fgChanged = true
			if out != "" {
				out += "<t:" + ColorToString(elem.Fg) + ">"
			}
		case ElemBackColor:
			bgChanged = true
			if out != "" {
				out += "<b:" + ColorToString(elem.Bg) + ">"
			}
		case ElemPrintable:
			if curr == start {
				if fgChanged {
					out += "<t:" + ColorToString(elem.Fg) + ">"
				}
				if bgChanged {
					out += "<b:" + ColorToString(elem.Bg) + ">"
				}
			}
			if curr >= start {
				out += string(elem.Ch)
			}
			curr++
		}
	}

	return out
}

func SliceColorized ( str string , start , end int ) string { if str == " " { return str } if start < 0 { start = 0 } fgChanged , bgChanged := false , false curr := 0 parser := NewColorParser ( str , term . ColorBlack , term . ColorBlack ) var out string for { if end != - 1 && curr >= end { break } elem := parser . NextElement ( ) if elem . Type == ElemEndOfText { break } switch elem . Type { case ElemTextColor : fgChanged = true if out != " " { out += " " + ColorToString ( elem . Fg ) + " " } case ElemBackColor : bgChanged = true if out != " " { out += " " + ColorToString ( elem . Bg ) + " " } case ElemPrintable : if curr == start { if fgChanged { out += " " + ColorToString ( elem . Fg ) + " " } if bgChanged { out += " " + ColorToString ( elem . Bg ) + " " } } if curr >= start { out += string ( elem . Ch ) } curr ++ } } return out }

// SliceColorized returns a slice of text with correct color
// tags. start and end are real printable rune indices

SliceColorized returns a slice of text with correct color tags . start and end are real printable rune indices


func ColorToString(attr term.Attribute) string {
	var out string

	rawClr := attr & 15
	if rawClr < 8 {
		for k, v := range colorMap {
			if v == rawClr {
				out += k + " "
				break
			}
		}
	}

	if attr&term.AttrBold != 0 {
		out += "bold "
	}
	if attr&term.AttrUnderline != 0 {
		out += "underline "
	}
	if attr&term.AttrReverse != 0 {
		out += "reverse "
	}

	return strings.TrimSpace(out)
}

func ColorToString ( attr term . Attribute ) string { var out string rawClr := attr & 15 if rawClr < 8 { for k , v := range colorMap { if v == rawClr { out += k + " " break } } } if attr & term . AttrBold != 0 { out += " " } if attr & term . AttrUnderline != 0 { out += " " } if attr & term . AttrReverse != 0 { out += " " } return strings . TrimSpace ( out ) }

// ColorToString returns string representation of the attribute


func MainLoop() {
	RefreshScreen()

	eventQueue := make(chan term.Event)
	go func() {
		for {
			eventQueue <- term.PollEvent()
		}
	}()

	for {
		RefreshScreen()

		select {
		case ev := <-eventQueue:
			switch ev.Type {
			case term.EventError:
				panic(ev.Err)
			default:
				ProcessEvent(termboxEventToLocal(ev))
			}
		case cmd := <-loop.channel:
			if cmd.Type == EventQuit {
				return
			}
			ProcessEvent(cmd)
		}
	}
}

func MainLoop ( ) { RefreshScreen ( ) eventQueue := make ( chan term . Event ) go func ( ) { for { eventQueue <- term . PollEvent ( ) } } ( ) for { RefreshScreen ( ) select { case ev := <- eventQueue : switch ev . Type { case term . EventError : panic ( ev . Err ) default : ProcessEvent ( termboxEventToLocal ( ev ) ) } case cmd := <- loop . channel : if cmd . Type == EventQuit { return } ProcessEvent ( cmd ) } } }

// MainLoop starts the main application event loop


func CreateEditField(parent Control, width int, text string, scale int) *EditField {
	e := new(EditField)
	e.BaseControl = NewBaseControl()
	e.onChange = nil
	e.SetTitle(text)
	e.SetEnabled(true)

	if width == AutoSize {
		width = xs.Len(text) + 1
	}

	e.SetSize(width, 1)
	e.cursorPos = xs.Len(text)
	e.offset = 0
	e.parent = parent
	e.readonly = false
	e.SetScale(scale)

	e.SetConstraints(width, 1)

	e.end()

	if parent != nil {
		parent.AddChild(e)
	}

	return e
}

func CreateEditField ( parent Control , width int , text string , scale int ) * EditField { e := new ( EditField ) e . BaseControl = NewBaseControl ( ) e . onChange = nil e . SetTitle ( text ) e . SetEnabled ( true ) if width == AutoSize { width = xs . Len ( text ) + 1 } e . SetSize ( width , 1 ) e . cursorPos = xs . Len ( text ) e . offset = 0 e . parent = parent e . readonly = false e . SetScale ( scale ) e . SetConstraints ( width , 1 ) e . end ( ) if parent != nil { parent . AddChild ( e ) } return e }

// NewEditField creates a new EditField control
// view - is a View that manages the control
// parent - is container that keeps the control. The same View can be a view and a parent at the same time.
// width - is minimal width of the control.
// text - text to edit.
// scale - the way of scaling the control when the parent is resized. Use DoNotScale constant if the
//  control should keep its original size.

NewEditField creates a new EditField control view - is a View that manages the control parent - is container that keeps the control . The same View can be a view and a parent at the same time . width - is minimal width of the control . text - text to edit . scale - the way of scaling the control when the parent is resized . Use DoNotScale constant if the control should keep its original size .


func ChildAt(parent Control, x, y int) Control {
	px, py := parent.Pos()
	pw, ph := parent.Size()
	if px > x || py > y || px+pw <= x || py+ph <= y {
		return nil
	}

	if len(parent.Children()) == 0 {
		return parent
	}

	var ctrl Control
	ctrl = parent
	for _, child := range parent.Children() {
		if !child.Visible() {
			continue
		}

		check := ChildAt(child, x, y)
		if check != nil {
			ctrl = check
			break
		}
	}

	return ctrl
}

func ChildAt ( parent Control , x , y int ) Control { px , py := parent . Pos ( ) pw , ph := parent . Size ( ) if px > x || py > y || px + pw <= x || py + ph <= y { return nil } if len ( parent . Children ( ) ) == 0 { return parent } var ctrl Control ctrl = parent for _ , child := range parent . Children ( ) { if ! child . Visible ( ) { continue } check := ChildAt ( child , x , y ) if check != nil { ctrl = check break } } return ctrl }

// ChildAt returns the children of parent control that is at absolute
// coordinates x, y. Returns nil if x, y are outside parent control and
// returns parent if no child is at x, y

ChildAt returns the children of parent control that is at absolute coordinates x y . Returns nil if x y are outside parent control and returns parent if no child is at x y


func DeactivateControls(parent Control) {
	for _, ctrl := range parent.Children() {
		if ctrl.Active() {
			ctrl.SetActive(false)
			ctrl.ProcessEvent(Event{Type: EventActivate, X: 0})
		}

		DeactivateControls(ctrl)
	}
}

func DeactivateControls ( parent Control ) { for _ , ctrl := range parent . Children ( ) { if ctrl . Active ( ) { ctrl . SetActive ( false ) ctrl . ProcessEvent ( Event { Type : EventActivate , X : 0 } ) } DeactivateControls ( ctrl ) } }

// DeactivateControls makes all children of parent inactive


func ActivateControl(parent, control Control) bool {
	DeactivateControls(parent)
	res := false
	ctrl := FindChild(parent, control)
	if ctrl != nil {
		res = true
		if !ctrl.Active() {
			ctrl.ProcessEvent(Event{Type: EventActivate, X: 1})
			ctrl.SetActive(true)
		}
	}

	return res
}

func ActivateControl ( parent , control Control ) bool { DeactivateControls ( parent ) res := false ctrl := FindChild ( parent , control ) if ctrl != nil { res = true if ! ctrl . Active ( ) { ctrl . ProcessEvent ( Event { Type : EventActivate , X : 1 } ) ctrl . SetActive ( true ) } } return res }

// ActivateControl makes control active and disables all other children of
// the parent. Returns true if control was found and activated

ActivateControl makes control active and disables all other children of the parent . Returns true if control was found and activated


func FindChild(parent, control Control) Control {
	var res Control

	if parent == control {
		return parent
	}

	for _, ctrl := range parent.Children() {
		if ctrl == control {
			res = ctrl
			break
		}

		res = FindChild(ctrl, control)
		if res != nil {
			break
		}
	}

	return res
}

func FindChild ( parent , control Control ) Control { var res Control if parent == control { return parent } for _ , ctrl := range parent . Children ( ) { if ctrl == control { res = ctrl break } res = FindChild ( ctrl , control ) if res != nil { break } } return res }

// FindChild returns control if it is a child of the parent and nil otherwise


func IsMouseClickEvent(ev Event) bool {
	if ev.Type == EventClick {
		return true
	}
	if ev.Type == EventMouse && ev.Key == term.MouseLeft {
		return true
	}

	return false
}

func IsMouseClickEvent ( ev Event ) bool { if ev . Type == EventClick { return true } if ev . Type == EventMouse && ev . Key == term . MouseLeft { return true } return false }

// IsMouseClickEvent returns if a user action can be treated as mouse click.

IsMouseClickEvent returns if a user action can be treated as mouse click .


func FindFirstControl(parent Control, fn func(Control) bool) Control {
	linear := getLinearControlList(parent, fn)
	if len(linear) == 0 {
		return nil
	}

	return linear[0]
}

func FindFirstControl ( parent Control , fn func ( Control ) bool ) Control { linear := getLinearControlList ( parent , fn ) if len ( linear ) == 0 { return nil } return linear [ 0 ] }

// FindFirstControl returns the first child for that fn returns true.
// The function is used to find active or tab-stop control

FindFirstControl returns the first child for that fn returns true . The function is used to find active or tab - stop control


func ActiveControl(parent Control) Control {
	fnActive := func(c Control) bool {
		return c.Active()
	}
	return FindFirstControl(parent, fnActive)
}

func ActiveControl ( parent Control ) Control { fnActive := func ( c Control ) bool { return c . Active ( ) } return FindFirstControl ( parent , fnActive ) }

// ActiveControl returns the active child of the parent or nil if no child is
// active

ActiveControl returns the active child of the parent or nil if no child is active


func FindFirstActiveControl(parent Control) Control {
	for _, curr := range getLinearControlList(parent, nil) {
		if curr.Active() {
			return curr
		}
	}
	return nil
}

func FindFirstActiveControl ( parent Control ) Control { for _ , curr := range getLinearControlList ( parent , nil ) { if curr . Active ( ) { return curr } } return nil }

// FindFirstActiveControl returns the first active control of a parent


func SendEventToChild(parent Control, ev Event) bool {
	var child Control
	if IsMouseClickEvent(ev) {
		child = ChildAt(parent, ev.X, ev.Y)
		if child != nil && !child.Active() {
			ActivateControl(parent, child)
		}
	} else {
		child = ActiveControl(parent)
	}

	if child != nil && child != parent {
		ev.Target = child
		res := child.ProcessEvent(ev)

		if cparent := ClippedParent(child); cparent != nil && cparent != child {
			cparent.ProcessEvent(ev)
		}

		return res
	}

	return false
}

func SendEventToChild ( parent Control , ev Event ) bool { var child Control if IsMouseClickEvent ( ev ) { child = ChildAt ( parent , ev . X , ev . Y ) if child != nil && ! child . Active ( ) { ActivateControl ( parent , child ) } } else { child = ActiveControl ( parent ) } if child != nil && child != parent { ev . Target = child res := child . ProcessEvent ( ev ) if cparent := ClippedParent ( child ) ; cparent != nil && cparent != child { cparent . ProcessEvent ( ev ) } return res } return false }

// SendEventToChild tries to find a child control that should recieve the evetn
// For mouse click events it looks for a control at coordinates of event,
// makes it active, and then sends the event to it.
// If it is not mouse click event then it looks for the first active child and
// sends the event to it if it is not nil

SendEventToChild tries to find a child control that should recieve the evetn For mouse click events it looks for a control at coordinates of event makes it active and then sends the event to it . If it is not mouse click event then it looks for the first active child and sends the event to it if it is not nil


func CalcClipper(c Control) (int, int, int, int) {
	w, h := c.Size()
	x, y := c.Pos()
	px, py := c.Paddings()

	x = x + px
	y = y + py
	w = w - 2*px
	h = h - 2*py

	return x, y, w, h
}

func CalcClipper ( c Control ) ( int , int , int , int ) { w , h := c . Size ( ) x , y := c . Pos ( ) px , py := c . Paddings ( ) x = x + px y = y + py w = w - 2 * px h = h - 2 * py return x , y , w , h }

// CalcClipper calculates the clipper size based on the control's size, position
// and paddings

CalcClipper calculates the clipper size based on the control s size position and paddings


func ClippedParent(c Control) Control {
	var clipped Control

	ctrl := c.Parent()
	clipped = c

	for ctrl != nil {
		if ctrl.Clipped() {
			clipped = ctrl
			break
		}

		ctrl = ctrl.Parent()
	}

	return clipped
}

func ClippedParent ( c Control ) Control { var clipped Control ctrl := c . Parent ( ) clipped = c for ctrl != nil { if ctrl . Clipped ( ) { clipped = ctrl break } ctrl = ctrl . Parent ( ) } return clipped }

// ClippedParent finds the first c parent with clipped flag


func ControlInRect(c Control, x int, y int, w int, h int) bool {
	xx, yy := c.Pos()
	ww, hh := c.Size()

	return xx >= x && ww <= x+w && yy <= y+h &&
		yy+hh <= y+h && yy >= y && yy+h >= y
}

func ControlInRect ( c Control , x int , y int , w int , h int ) bool { xx , yy := c . Pos ( ) ww , hh := c . Size ( ) return xx >= x && ww <= x + w && yy <= y + h && yy + hh <= y + h && yy >= y && yy + h >= y }

// ControlInRect returns true if c is within a given rect


func CreateAlertDialog(title, message string, button string) *ConfirmationDialog {
	return CreateConfirmationDialog(title, message, []string{button}, 0)
}

func CreateAlertDialog ( title , message string , button string ) * ConfirmationDialog { return CreateConfirmationDialog ( title , message , [ ] string { button } , 0 ) }

// CreateAlertDialog creates a new alert dialog.
// title is a dialog title
// message is a text inside dialog for user to be notified of a fact
// button is a title for button inside dialog.

CreateAlertDialog creates a new alert dialog . title is a dialog title message is a text inside dialog for user to be notified of a fact button is a title for button inside dialog .


func (c *CheckBox) ProcessEvent(event Event) bool {
	if (!c.Active() && event.Type == EventKey) || !c.Enabled() {
		return false
	}

	if (event.Type == EventKey && event.Key == term.KeySpace) || (event.Type == EventClick) {
		if c.state == 0 {
			c.SetState(1)
		} else if c.state == 2 {
			c.SetState(0)
		} else {
			if c.allow3state {
				c.SetState(2)
			} else {
				c.SetState(0)
			}
		}
		return true
	}

	return false
}

func ( c * CheckBox ) ProcessEvent ( event Event ) bool { if ( ! c . Active ( ) && event . Type == EventKey ) || ! c . Enabled ( ) { return false } if ( event . Type == EventKey && event . Key == term . KeySpace ) || ( event . Type == EventClick ) { if c . state == 0 { c . SetState ( 1 ) } else if c . state == 2 { c . SetState ( 0 ) } else { if c . allow3state { c . SetState ( 2 ) } else { c . SetState ( 0 ) } } return true } return false }

//ProcessEvent processes all events come from the control parent. If a control
//   processes an event it should return true. If the method returns false it means
//   that the control do not want or cannot process the event and the caller sends
//   the event to the control parent

ProcessEvent processes all events come from the control parent . If a control processes an event it should return true . If the method returns false it means that the control do not want or cannot process the event and the caller sends the event to the control parent


func (c *CheckBox) SetState(val int) {
	c.mtx.Lock()
	defer c.mtx.Unlock()

	if val == c.state {
		return
	}

	if val < 0 {
		val = 0
	}
	if val > 1 && !c.allow3state {
		val = 1
	}
	if val > 2 {
		val = 2
	}

	c.state = val

	if c.onChange != nil {
		go c.onChange(val)
	}
}

func ( c * CheckBox ) SetState ( val int ) { c . mtx . Lock ( ) defer c . mtx . Unlock ( ) if val == c . state { return } if val < 0 { val = 0 } if val > 1 && ! c . allow3state { val = 1 } if val > 2 { val = 2 } c . state = val if c . onChange != nil { go c . onChange ( val ) } }

// SetState changes the current state of CheckBox
// Value must be 0 or 1 if Allow3State is off,
// and 0, 1, or 2 if Allow3State is on

SetState changes the current state of CheckBox Value must be 0 or 1 if Allow3State is off and 0 1 or 2 if Allow3State is on


func (c *CheckBox) State() int {
	c.mtx.RLock()
	defer c.mtx.RUnlock()

	return c.state
}

func ( c * CheckBox ) State ( ) int { c . mtx . RLock ( ) defer c . mtx . RUnlock ( ) return c . state }

// State returns current state of CheckBox


func (c *CheckBox) SetAllow3State(enable bool) {
	if !enable && c.state == 2 {
		c.state = 0
	}
	c.allow3state = enable
}

func ( c * CheckBox ) SetAllow3State ( enable bool ) { if ! enable && c . state == 2 { c . state = 0 } c . allow3state = enable }

// SetAllow3State sets if ComboBox should use 3 states. If the current
// state is unknown and one disables Allow3State option then the current
// value resets to off

SetAllow3State sets if ComboBox should use 3 states . If the current state is unknown and one disables Allow3State option then the current value resets to off


func (c *CheckBox) SetSize(width, height int) {
	if width != KeepValue && (width > 1000 || width < c.minW) {
		return
	}
	if height != KeepValue && (height > 200 || height < c.minH) {
		return
	}

	if width != KeepValue {
		c.width = width
	}

	c.height = 1
}

func ( c * CheckBox ) SetSize ( width , height int ) { if width != KeepValue && ( width > 1000 || width < c . minW ) { return } if height != KeepValue && ( height > 200 || height < c . minH ) { return } if width != KeepValue { c . width = width } c . height = 1 }

// SetSize changes control size. Constant DoNotChange can be
// used as placeholder to indicate that the control attrubute
// should be unchanged.
// Method does nothing if new size is less than minimal size
// CheckBox height cannot be changed - it equals 1 always

SetSize changes control size . Constant DoNotChange can be used as placeholder to indicate that the control attrubute should be unchanged . Method does nothing if new size is less than minimal size CheckBox height cannot be changed - it equals 1 always


func (f *Frame) ScrollTo(x int, y int) {
	if !f.scrollable {
		return
	}

	f.x = x
	f.y = y

	f.ResizeChildren()
	f.PlaceChildren()
}

func ( f * Frame ) ScrollTo ( x int , y int ) { if ! f . scrollable { return } f . x = x f . y = y f . ResizeChildren ( ) f . PlaceChildren ( ) }

// ScrollTo in case of a scrollable frame this api will scroll the content
// without adjusting the clipper

ScrollTo in case of a scrollable frame this api will scroll the content without adjusting the clipper


func (l *TableView) EnsureColVisible() {
	if l.isColVisible(l.selectedCol) {
		return
	}

	if l.selectedCol < l.topCol {
		l.topCol = l.selectedCol
		return
	}

	width := l.width - 1 - l.counterWidth()
	if l.showRowNo && l.showVLines {
		width--
	}

	toShow := l.selectedCol
	for width > 0 {
		if l.columns[toShow].Width > width {
			if toShow == l.selectedCol {
				break
			} else {
				toShow++
				break
			}
		} else if l.columns[toShow].Width == width {
			break
		} else {
			width -= l.columns[toShow].Width
			if width < 0 {
				break
			}
			toShow--
			if toShow == 0 {
				break
			}
		}
	}

	l.topCol = toShow
}

func ( l * TableView ) EnsureColVisible ( ) { if l . isColVisible ( l . selectedCol ) { return } if l . selectedCol < l . topCol { l . topCol = l . selectedCol return } width := l . width - 1 - l . counterWidth ( ) if l . showRowNo && l . showVLines { width -- } toShow := l . selectedCol for width > 0 { if l . columns [ toShow ] . Width > width { if toShow == l . selectedCol { break } else { toShow ++ break } } else if l . columns [ toShow ] . Width == width { break } else { width -= l . columns [ toShow ] . Width if width < 0 { break } toShow -- if toShow == 0 { break } } } l . topCol = toShow }

// EnsureColVisible scrolls the table horizontally
// to make the currently selected column fully visible

EnsureColVisible scrolls the table horizontally to make the currently selected column fully visible


func (l *TableView) EnsureRowVisible() {
	length := l.rowCount

	hgt := l.height - 3

	if length <= hgt || l.selectedRow == -1 {
		return
	}

	diff := l.selectedRow - l.topRow
	if diff >= 0 && diff < hgt {
		return
	}

	if diff < 0 {
		l.topRow = l.selectedRow
	} else {
		top := l.selectedRow - hgt + 1
		if length-top > hgt {
			l.topRow = top
		} else {
			l.topRow = length - hgt
		}
	}
}

func ( l * TableView ) EnsureRowVisible ( ) { length := l . rowCount hgt := l . height - 3 if length <= hgt || l . selectedRow == - 1 { return } diff := l . selectedRow - l . topRow if diff >= 0 && diff < hgt { return } if diff < 0 { l . topRow = l . selectedRow } else { top := l . selectedRow - hgt + 1 if length - top > hgt { l . topRow = top } else { l . topRow = length - hgt } } }

// EnsureRowVisible scrolls the table vertically
// to make the currently selected row visible

EnsureRowVisible scrolls the table vertically to make the currently selected row visible


func (l *TableView) Columns() []Column {
	c := make([]Column, len(l.columns))
	copy(c, l.columns)
	return c
}

func ( l * TableView ) Columns ( ) [ ] Column { c := make ( [ ] Column , len ( l . columns ) ) copy ( c , l . columns ) return c }

// Columns returns the current list of table columns


func (l *TableView) SetColumnInfo(id int, col Column) {
	if id < len(l.columns) {
		l.columns[id] = col
	}
}

func ( l * TableView ) SetColumnInfo ( id int , col Column ) { if id < len ( l . columns ) { l . columns [ id ] = col } }

// SetColumnInfo replaces the existing column info


func (l *TableView) OnKeyPress(fn func(term.Key) bool) {
	l.onKeyPress = fn
}

func ( l * TableView ) OnKeyPress ( fn func ( term . Key ) bool ) { l . onKeyPress = fn }

// OnKeyPress sets the callback that is called when a user presses a Key while
// the controls is active. If a handler processes the key it should return
// true. If handler returns false it means that the default handler has to
// process the key

OnKeyPress sets the callback that is called when a user presses a Key while the controls is active . If a handler processes the key it should return true . If handler returns false it means that the default handler has to process the key


func (l *TableView) OnDrawCell(fn func(*ColumnDrawInfo)) {
	l.mtx.Lock()
	l.onDrawCell = fn
	l.mtx.Unlock()
}

func ( l * TableView ) OnDrawCell ( fn func ( * ColumnDrawInfo ) ) { l . mtx . Lock ( ) l . onDrawCell = fn l . mtx . Unlock ( ) }

// OnDrawCell is called every time the table is going to display
// a cell

OnDrawCell is called every time the table is going to display a cell


func (l *TableView) SetSelectedRow(row int) {
	oldSelection := l.selectedRow
	if row >= l.rowCount {
		l.selectedRow = l.rowCount - 1
	} else if row < -1 {
		l.selectedRow = -1
	}

	if l.selectedRow != oldSelection {
		l.EnsureRowVisible()
		l.emitSelectionChange()
	}
}

func ( l * TableView ) SetSelectedRow ( row int ) { oldSelection := l . selectedRow if row >= l . rowCount { l . selectedRow = l . rowCount - 1 } else if row < - 1 { l . selectedRow = - 1 } if l . selectedRow != oldSelection { l . EnsureRowVisible ( ) l . emitSelectionChange ( ) } }

// SetSelectedRow changes the currently selected row.
// If row is greater than number of row the last row
// is selected. Set row to -1 to turn off selection.
// The table scrolls automatically to display the column

SetSelectedRow changes the currently selected row . If row is greater than number of row the last row is selected . Set row to - 1 to turn off selection . The table scrolls automatically to display the column


func (l *TableView) SetSelectedCol(col int) {
	oldSelection := l.selectedCol
	if col >= len(l.columns) {
		l.selectedCol = len(l.columns) - 1
	} else if col < -1 {
		l.selectedCol = -1
	}

	if l.selectedCol != oldSelection {
		l.EnsureColVisible()
		l.emitSelectionChange()
	}
}

func ( l * TableView ) SetSelectedCol ( col int ) { oldSelection := l . selectedCol if col >= len ( l . columns ) { l . selectedCol = len ( l . columns ) - 1 } else if col < - 1 { l . selectedCol = - 1 } if l . selectedCol != oldSelection { l . EnsureColVisible ( ) l . emitSelectionChange ( ) } }

// SetSelectedCol changes the currently selected column.
// If column is greater than number of columns the last
// column is selected. Set row to -1 to turn off selection.
// The table scrolls automatically to display the column

SetSelectedCol changes the currently selected column . If column is greater than number of columns the last column is selected . Set row to - 1 to turn off selection . The table scrolls automatically to display the column


func (c *Radio) SetSelected(val bool) {
	c.selected = val

	if c.onChange != nil {
		go c.onChange(val)
	}
}

func ( c * Radio ) SetSelected ( val bool ) { c . selected = val if c . onChange != nil { go c . onChange ( val ) } }

// SetSelected makes the button selected. One should not use
// the method directly, it is for RadioGroup control

SetSelected makes the button selected . One should not use the method directly it is for RadioGroup control


func (c *Radio) OnChange(fn func(bool)) {
	c.mtx.Lock()
	defer c.mtx.Unlock()

	c.onChange = fn
}

func ( c * Radio ) OnChange ( fn func ( bool ) ) { c . mtx . Lock ( ) defer c . mtx . Unlock ( ) c . onChange = fn }

// OnChange sets the callback that is called whenever the state
// of the Radio is changed. Argument of callback is the current

OnChange sets the callback that is called whenever the state of the Radio is changed . Argument of callback is the current


func (l *TextView) SetText(text []string) {
	l.lines = make([]string, len(text))
	copy(l.lines, text)

	l.applyLimit()
	l.calculateVirtualSize()

	if l.autoscroll {
		l.end()
	}
}

func ( l * TextView ) SetText ( text [ ] string ) { l . lines = make ( [ ] string , len ( text ) ) copy ( l . lines , text ) l . applyLimit ( ) l . calculateVirtualSize ( ) if l . autoscroll { l . end ( ) } }

// SetText replaces existing content of the control


func (l *TextView) SetWordWrap(wrap bool) {
	if wrap != l.wordWrap {
		l.wordWrap = wrap
		l.calculateVirtualSize()
		l.recalculateTopLine()
		l.Draw()
	}
}

func ( l * TextView ) SetWordWrap ( wrap bool ) { if wrap != l . wordWrap { l . wordWrap = wrap l . calculateVirtualSize ( ) l . recalculateTopLine ( ) l . Draw ( ) } }

// SetWordWrap enables or disables wordwrap mode


func (l *TextView) LoadFile(filename string) bool {
	l.lines = make([]string, 0)

	file, err := os.Open(filename)
	if err != nil {
		return false
	}

	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		line = strings.TrimSpace(line)
		l.lines = append(l.lines, line)
	}

	l.applyLimit()
	l.calculateVirtualSize()

	if l.autoscroll {
		l.end()
	}

	return true
}

func ( l * TextView ) LoadFile ( filename string ) bool { l . lines = make ( [ ] string , 0 ) file , err := os . Open ( filename ) if err != nil { return false } defer file . Close ( ) scanner := bufio . NewScanner ( file ) for scanner . Scan ( ) { line := scanner . Text ( ) line = strings . TrimSpace ( line ) l . lines = append ( l . lines , line ) } l . applyLimit ( ) l . calculateVirtualSize ( ) if l . autoscroll { l . end ( ) } return true }

// LoadFile loads a text from file and replace the control
// text with the file one.
// Function returns false if loading text from file fails

LoadFile loads a text from file and replace the control text with the file one . Function returns false if loading text from file fails


func (l *TextView) AddText(text []string) {
	l.lines = append(l.lines, text...)
	l.applyLimit()
	l.calculateVirtualSize()

	if l.autoscroll {
		l.end()
	}
}

func ( l * TextView ) AddText ( text [ ] string ) { l . lines = append ( l . lines , text ... ) l . applyLimit ( ) l . calculateVirtualSize ( ) if l . autoscroll { l . end ( ) } }

// AddText appends a text to the end of the control content.
// View position may be changed automatically depending on
// value of AutoScroll

AddText appends a text to the end of the control content . View position may be changed automatically depending on value of AutoScroll


func (b *ProgressBar) Value() int {
	b.mtx.RLock()
	defer b.mtx.RUnlock()
	return b.value
}

func ( b * ProgressBar ) Value ( ) int { b . mtx . RLock ( ) defer b . mtx . RUnlock ( ) return b . value }

// Value returns the current ProgressBar value


func (b *ProgressBar) SetLimits(min, max int) {
	b.min = min
	b.max = max

	if b.value < b.min {
		b.value = min
	}
	if b.value > b.max {
		b.value = max
	}
}

func ( b * ProgressBar ) SetLimits ( min , max int ) { b . min = min b . max = max if b . value < b . min { b . value = min } if b . value > b . max { b . value = max } }

// SetLimits set new ProgressBar limits. The current value
// is adjusted if it exceeds new limits

SetLimits set new ProgressBar limits . The current value is adjusted if it exceeds new limits


func (b *ProgressBar) Step() int {
	b.mtx.Lock()
	defer b.mtx.Unlock()
	b.value++

	if b.value > b.max {
		b.value = b.max
	}

	return b.value
}

func ( b * ProgressBar ) Step ( ) int { b . mtx . Lock ( ) defer b . mtx . Unlock ( ) b . value ++ if b . value > b . max { b . value = b . max } return b . value }

// Step increases ProgressBar value by 1 if the value is less
// than ProgressBar high limit

Step increases ProgressBar value by 1 if the value is less than ProgressBar high limit


func (b *ProgressBar) SecondaryColors() (term.Attribute, term.Attribute) {
	return b.emptyFg, b.emptyBg
}

func ( b * ProgressBar ) SecondaryColors ( ) ( term . Attribute , term . Attribute ) { return b . emptyFg , b . emptyBg }

// SecondaryColors returns text and background colors for empty
// part of the ProgressBar

SecondaryColors returns text and background colors for empty part of the ProgressBar


func (b *ProgressBar) SetSecondaryColors(fg, bg term.Attribute) {
	b.emptyFg, b.emptyBg = fg, bg
}

func ( b * ProgressBar ) SetSecondaryColors ( fg , bg term . Attribute ) { b . emptyFg , b . emptyBg = fg , bg }

// SetSecondaryColors sets new text and background colors for
// empty part of the ProgressBar

SetSecondaryColors sets new text and background colors for empty part of the ProgressBar


func (b *BarChart) SetAutoSize(auto bool) {
	b.mtx.Lock()
	defer b.mtx.Unlock()

	b.autosize = auto
}

func ( b * BarChart ) SetAutoSize ( auto bool ) { b . mtx . Lock ( ) defer b . mtx . Unlock ( ) b . autosize = auto }

// SetAutoSize enables or disables automatic bar
// width calculation

SetAutoSize enables or disables automatic bar width calculation


func (b *BarChart) SetBarGap(gap int32) {
	atomic.StoreInt32(&b.gap, gap)
}

func ( b * BarChart ) SetBarGap ( gap int32 ) { atomic . StoreInt32 ( & b . gap , gap ) }

// SetGap sets the space width between two adjacent bars


func (b *BarChart) SetMinBarWidth(size int32) {
	atomic.StoreInt32(&b.barWidth, size)
}

func ( b * BarChart ) SetMinBarWidth ( size int32 ) { atomic . StoreInt32 ( & b . barWidth , size ) }

// SetMinBarWidth changes the minimal bar width


func (b *BarChart) SetShowTitles(show bool) {
	b.mtx.Lock()
	defer b.mtx.Unlock()

	b.showTitles = show
}

func ( b * BarChart ) SetShowTitles ( show bool ) { b . mtx . Lock ( ) defer b . mtx . Unlock ( ) b . showTitles = show }

// SetShowTitles turns on and off horizontal axis and bar titles


func (b *BarChart) SetLegendWidth(width int32) {
	atomic.StoreInt32(&b.legendWidth, width)
}

func ( b * BarChart ) SetLegendWidth ( width int32 ) { atomic . StoreInt32 ( & b . legendWidth , width ) }

// SetLegendWidth sets new legend panel width


func (b *BarChart) OnDrawCell(fn func(*BarDataCell)) {
	b.mtx.Lock()
	defer b.mtx.Unlock()

	b.onDrawCell = fn
}

func ( b * BarChart ) OnDrawCell ( fn func ( * BarDataCell ) ) { b . mtx . Lock ( ) defer b . mtx . Unlock ( ) b . onDrawCell = fn }

// OnDrawCell sets callback that allows to draw multicolored
// bars. BarChart sends the current attrubutes and rune that
// it is going to use to display as well as the current value
// of the bar. A user can change the values of BarDataCell
// depending on some external data or calculations - only
// changing colors and rune makes sense. Changing anything else
// does not affect the chart

OnDrawCell sets callback that allows to draw multicolored bars . BarChart sends the current attrubutes and rune that it is going to use to display as well as the current value of the bar . A user can change the values of BarDataCell depending on some external data or calculations - only changing colors and rune makes sense . Changing anything else does not affect the chart


func (b *BarChart) SetShowMarks(show bool) {
	b.mtx.Lock()
	defer b.mtx.Unlock()

	b.showMarks = show
}

func ( b * BarChart ) SetShowMarks ( show bool ) { b . mtx . Lock ( ) defer b . mtx . Unlock ( ) b . showMarks = show }

// SetShowMarks turns on and off marks under horizontal axis


func (w *Window) OnKeyDown(fn func(Event, interface{}) bool, data interface{}) {
	if fn == nil {
		w.onKeyDown = nil
	} else {
		w.onKeyDown = &keyDownCb{data: data, fn: fn}
	}
}

func ( w * Window ) OnKeyDown ( fn func ( Event , interface { } ) bool , data interface { } ) { if fn == nil { w . onKeyDown = nil } else { w . onKeyDown = & keyDownCb { data : data , fn : fn } } }

// OnKeyDown sets the callback that is called when a user presses a key
// while the Window is active

OnKeyDown sets the callback that is called when a user presses a key while the Window is active


func (w *Window) SetMaximized(maximize bool) {
	if maximize == w.maximized {
		return
	}

	if maximize {
		w.origX, w.origY = w.Pos()
		w.origWidth, w.origHeight = w.Size()
		w.maximized = true
		w.SetPos(0, 0)
		width, height := ScreenSize()
		w.SetSize(width, height)
	} else {
		w.maximized = false
		w.SetPos(w.origX, w.origY)
		w.SetSize(w.origWidth, w.origHeight)
	}
	w.ResizeChildren()
	w.PlaceChildren()
}

func ( w * Window ) SetMaximized ( maximize bool ) { if maximize == w . maximized { return } if maximize { w . origX , w . origY = w . Pos ( ) w . origWidth , w . origHeight = w . Size ( ) w . maximized = true w . SetPos ( 0 , 0 ) width , height := ScreenSize ( ) w . SetSize ( width , height ) } else { w . maximized = false w . SetPos ( w . origX , w . origY ) w . SetSize ( w . origWidth , w . origHeight ) } w . ResizeChildren ( ) w . PlaceChildren ( ) }

// SetMaximized opens the view to full screen or restores its
// previous size

SetMaximized opens the view to full screen or restores its previous size


func (w *Window) SetVisible(visible bool) {
	if w.hidden == visible {
		w.hidden = !visible
		if w.hidden {
			w.SetModal(false)
			if WindowManager().topWindow() == w {
				WindowManager().moveActiveWindowToBottom()
			}
		} else {
			WindowManager().activateWindow(w)
		}
	}
}

func ( w * Window ) SetVisible ( visible bool ) { if w . hidden == visible { w . hidden = ! visible if w . hidden { w . SetModal ( false ) if WindowManager ( ) . topWindow ( ) == w { WindowManager ( ) . moveActiveWindowToBottom ( ) } } else { WindowManager ( ) . activateWindow ( w ) } } }

// SetVisible allows to temporarily remove the window from screen
// and show it later without reconstruction

SetVisible allows to temporarily remove the window from screen and show it later without reconstruction


func (b *SparkChart) SetTop(top float64) {
	b.mtx.Lock()
	defer b.mtx.Unlock()

	b.topValue = top
}

func ( b * SparkChart ) SetTop ( top float64 ) { b . mtx . Lock ( ) defer b . mtx . Unlock ( ) b . topValue = top }

// SetTop sets the theoretical highest value of data flow
// to scale the chart

SetTop sets the theoretical highest value of data flow to scale the chart


func (b *SparkChart) SetAutoScale(auto bool) {
	b.mtx.Lock()
	defer b.mtx.Unlock()

	b.autosize = auto
}

func ( b * SparkChart ) SetAutoScale ( auto bool ) { b . mtx . Lock ( ) defer b . mtx . Unlock ( ) b . autosize = auto }

// SetAutoScale changes the way of scaling the data flow


func (b *SparkChart) SetHilitePeaks(hilite bool) {
	b.mtx.Lock()
	defer b.mtx.Unlock()

	b.hiliteMax = hilite
}

func ( b * SparkChart ) SetHilitePeaks ( hilite bool ) { b . mtx . Lock ( ) defer b . mtx . Unlock ( ) b . hiliteMax = hilite }

// SetHilitePeaks enables or disables hiliting maximum
// values with different colors

SetHilitePeaks enables or disables hiliting maximum values with different colors


func loadEnv() {
	gil.Lock()
	defer gil.Unlock()

	if os.Getenv("GO_ENV") == "" {
		// if the flag "test.v" is *defined*, we're running as a unit test. Note that we don't care
		// about v.Value (verbose test mode); we just want to know if the test environment has defined
		// it. It's also possible that the flags are not yet fully parsed (i.e. flag.Parsed() == false),
		// so we could not depend on v.Value anyway.
		//
		if v := flag.Lookup("test.v"); v != nil {
			env["GO_ENV"] = "test"
		}
	}

	// set the GOPATH if using >= 1.8 and the GOPATH isn't set
	if os.Getenv("GOPATH") == "" {
		out, err := exec.Command("go", "env", "GOPATH").Output()
		if err == nil {
			gp := strings.TrimSpace(string(out))
			os.Setenv("GOPATH", gp)
		}
	}

	for _, e := range os.Environ() {
		pair := strings.Split(e, "=")
		env[pair[0]] = os.Getenv(pair[0])
	}
}

// Load the ENV variables to the env map


func Get(key string, value string) string {
	gil.RLock()
	defer gil.RUnlock()
	if v, ok := env[key]; ok {
		return v
	}
	return value
}

func Get ( key string , value string ) string { gil . RLock ( ) defer gil . RUnlock ( ) if v , ok := env [ key ] ; ok { return v } return value }

// Get a value from the ENV. If it doesn't exist the
// default value will be returned.

Get a value from the ENV . If it doesn t exist the default value will be returned .


func MustGet(key string) (string, error) {
	gil.RLock()
	defer gil.RUnlock()
	if v, ok := env[key]; ok {
		return v, nil
	}
	return "", fmt.Errorf("could not find ENV var with %s", key)
}

func MustGet ( key string ) ( string , error ) { gil . RLock ( ) defer gil . RUnlock ( ) if v , ok := env [ key ] ; ok { return v , nil } return " " , fmt . Errorf ( " " , key ) }

// Get a value from the ENV. If it doesn't exist
// an error will be returned

Get a value from the ENV . If it doesn t exist an error will be returned


func Set(key string, value string) {
	gil.Lock()
	defer gil.Unlock()
	env[key] = value
}

func Set ( key string , value string ) { gil . Lock ( ) defer gil . Unlock ( ) env [ key ] = value }

// Set a value into the ENV. This is NOT permanent. It will
// only affect values accessed through envy.

Set a value into the ENV . This is NOT permanent . It will only affect values accessed through envy .


func MustSet(key string, value string) error {
	gil.Lock()
	defer gil.Unlock()
	err := os.Setenv(key, value)
	if err != nil {
		return err
	}
	env[key] = value
	return nil
}

func MustSet ( key string , value string ) error { gil . Lock ( ) defer gil . Unlock ( ) err := os . Setenv ( key , value ) if err != nil { return err } env [ key ] = value return nil }

// MustSet the value into the underlying ENV, as well as envy.
// This may return an error if there is a problem setting the
// underlying ENV value.

MustSet the value into the underlying ENV as well as envy . This may return an error if there is a problem setting the underlying ENV value .


func GoPaths() []string {
	gp := Get("GOPATH", "")
	if runtime.GOOS == "windows" {
		return strings.Split(gp, ";") // Windows uses a different separator
	}
	return strings.Split(gp, ":")
}

func
GoPaths
(
)
[
]
string
{
gp
:=
Get
(
"
"
,
"
"
)
if
runtime
.
GOOS
==
"
"
{
return
strings
.
Split
(
gp
,
"
"
)
// Windows uses a different separator
}
return
strings
.
Split
(
gp
,
"
"
)
}

// GoPaths returns all possible GOPATHS that are set.

GoPaths returns all possible GOPATHS that are set .


func CurrentModule() (string, error) {
	if !Mods() {
		return CurrentPackage(), nil
	}
	moddata, err := ioutil.ReadFile("go.mod")
	if err != nil {
		return "", errors.New("go.mod cannot be read or does not exist while go module is enabled")
	}
	packagePath := modfile.ModulePath(moddata)
	if packagePath == "" {
		return "", errors.New("go.mod is malformed")
	}
	return packagePath, nil
}

func CurrentModule ( ) ( string , error ) { if ! Mods ( ) { return CurrentPackage ( ) , nil } moddata , err := ioutil . ReadFile ( " " ) if err != nil { return " " , errors . New ( " " ) } packagePath := modfile . ModulePath ( moddata ) if packagePath == " " { return " " , errors . New ( " " ) } return packagePath , nil }

// CurrentModule will attempt to return the module name from `go.mod` if
// modules are enabled.
// If modules are not enabled it will fallback to using CurrentPackage instead.

CurrentModule will attempt to return the module name from go . mod if modules are enabled . If modules are not enabled it will fallback to using CurrentPackage instead .


func request(client *http.Client, method, url string, body []byte) ([]byte, error) {
	req, err := http.NewRequest(method, url, bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return processResponse(resp)
}

func request ( client * http . Client , method , url string , body [ ] byte ) ( [ ] byte , error ) { req , err := http . NewRequest ( method , url , bytes . NewBuffer ( body ) ) req . Header . Set ( " " , " " ) resp , err := client . Do ( req ) if err != nil { return nil , err } defer resp . Body . Close ( ) return processResponse ( resp ) }


func (pn *notificationRequest) validate() error {
	if 0 == len(pn.Interests) || len(pn.Interests) > 10 {
		return errors.New("Interests must contain between 1 and 10 interests")
	}

	if pn.APNS == nil && pn.GCM == nil && pn.FCM == nil {
		return errors.New("PushNotification must contain a GCM, FCM or APNS payload")
	}

	return nil
}

func ( pn * notificationRequest ) validate ( ) error { if 0 == len ( pn . Interests ) || len ( pn . Interests ) > 10 { return errors . New ( " " ) } if pn . APNS == nil && pn . GCM == nil && pn . FCM == nil { return errors . New ( " " ) } return nil }

// validate checks the notificationRequest has 0<Interests<11 and has a
// APNS, GCM or FCM payload

validate checks the notificationRequest has 0<Interests<11 and has a APNS GCM or FCM payload


func NewNetworkNumber(ip net.IP) NetworkNumber {
	if ip == nil {
		return nil
	}
	coercedIP := ip.To4()
	parts := 1
	if coercedIP == nil {
		coercedIP = ip.To16()
		parts = 4
	}
	if coercedIP == nil {
		return nil
	}
	nn := make(NetworkNumber, parts)
	for i := 0; i < parts; i++ {
		idx := i * net.IPv4len
		nn[i] = binary.BigEndian.Uint32(coercedIP[idx : idx+net.IPv4len])
	}
	return nn
}

func NewNetworkNumber ( ip net . IP ) NetworkNumber { if ip == nil { return nil } coercedIP := ip . To4 ( ) parts := 1 if coercedIP == nil { coercedIP = ip . To16 ( ) parts = 4 } if coercedIP == nil { return nil } nn := make ( NetworkNumber , parts ) for i := 0 ; i < parts ; i ++ { idx := i * net . IPv4len nn [ i ] = binary . BigEndian . Uint32 ( coercedIP [ idx : idx + net . IPv4len ] ) } return nn }

// NewNetworkNumber returns a equivalent NetworkNumber to given IP address,
// return nil if ip is neither IPv4 nor IPv6.

NewNetworkNumber returns a equivalent NetworkNumber to given IP address return nil if ip is neither IPv4 nor IPv6 .


func (n NetworkNumber) ToIP() net.IP {
	ip := make(net.IP, len(n)*BytePerUint32)
	for i := 0; i < len(n); i++ {
		idx := i * net.IPv4len
		binary.BigEndian.PutUint32(ip[idx:idx+net.IPv4len], n[i])
	}
	if len(ip) == net.IPv4len {
		ip = net.IPv4(ip[0], ip[1], ip[2], ip[3])
	}
	return ip
}

func ( n NetworkNumber ) ToIP ( ) net . IP { ip := make ( net . IP , len ( n ) * BytePerUint32 ) for i := 0 ; i < len ( n ) ; i ++ { idx := i * net . IPv4len binary . BigEndian . PutUint32 ( ip [ idx : idx + net . IPv4len ] , n [ i ] ) } if len ( ip ) == net . IPv4len { ip = net . IPv4 ( ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] ) } return ip }


func (n NetworkNumber) Equal(n1 NetworkNumber) bool {
	if len(n) != len(n1) {
		return false
	}
	if n[0] != n1[0] {
		return false
	}
	if len(n) == IPv6Uint32Count {
		return n[1] == n1[1] && n[2] == n1[2] && n[3] == n1[3]
	}
	return true
}

func ( n NetworkNumber ) Equal ( n1 NetworkNumber ) bool { if len ( n ) != len ( n1 ) { return false } if n [ 0 ] != n1 [ 0 ] { return false } if len ( n ) == IPv6Uint32Count { return n [ 1 ] == n1 [ 1 ] && n [ 2 ] == n1 [ 2 ] && n [ 3 ] == n1 [ 3 ] } return true }

// Equal is the equality test for 2 network numbers.

Equal is the equality test for 2 network numbers .


func (n NetworkNumber) Next() NetworkNumber {
	newIP := make(NetworkNumber, len(n))
	copy(newIP, n)
	for i := len(newIP) - 1; i >= 0; i-- {
		newIP[i]++
		if newIP[i] > 0 {
			break
		}
	}
	return newIP
}

func ( n NetworkNumber ) Next ( ) NetworkNumber { newIP := make ( NetworkNumber , len ( n ) ) copy ( newIP , n ) for i := len ( newIP ) - 1 ; i >= 0 ; i -- { newIP [ i ] ++ if newIP [ i ] > 0 { break } } return newIP }

// Next returns the next logical network number.

Next returns the next logical network number .


func (n NetworkNumber) Previous() NetworkNumber {
	newIP := make(NetworkNumber, len(n))
	copy(newIP, n)
	for i := len(newIP) - 1; i >= 0; i-- {
		newIP[i]--
		if newIP[i] < math.MaxUint32 {
			break
		}
	}
	return newIP
}

func ( n NetworkNumber ) Previous ( ) NetworkNumber { newIP := make ( NetworkNumber , len ( n ) ) copy ( newIP , n ) for i := len ( newIP ) - 1 ; i >= 0 ; i -- { newIP [ i ] -- if newIP [ i ] < math . MaxUint32 { break } } return newIP }

// Previous returns the previous logical network number.

Previous returns the previous logical network number .


func NewNetwork(ipNet net.IPNet) Network {
	return Network{
		IPNet:  ipNet,
		Number: NewNetworkNumber(ipNet.IP),
		Mask:   NetworkNumberMask(NewNetworkNumber(net.IP(ipNet.Mask))),
	}
}

func NewNetwork ( ipNet net . IPNet ) Network { return Network { IPNet : ipNet , Number : NewNetworkNumber ( ipNet . IP ) , Mask : NetworkNumberMask ( NewNetworkNumber ( net . IP ( ipNet . Mask ) ) ) , } }

// NewNetwork returns Network built using given net.IPNet.

NewNetwork returns Network built using given net . IPNet .


func (n Network) Masked(ones int) Network {
	mask := net.CIDRMask(ones, len(n.Number)*BitsPerUint32)
	return NewNetwork(net.IPNet{
		IP:   n.IP.Mask(mask),
		Mask: mask,
	})
}

func ( n Network ) Masked ( ones int ) Network { mask := net . CIDRMask ( ones , len ( n . Number ) * BitsPerUint32 ) return NewNetwork ( net . IPNet { IP : n . IP . Mask ( mask ) , Mask : mask , } ) }

// Masked returns a new network conforming to new mask.

Masked returns a new network conforming to new mask .


func (n Network) Contains(nn NetworkNumber) bool {
	if len(n.Mask) != len(nn) {
		return false
	}
	if nn[0]&n.Mask[0] != n.Number[0] {
		return false
	}
	if len(nn) == IPv6Uint32Count {
		return nn[1]&n.Mask[1] == n.Number[1] && nn[2]&n.Mask[2] == n.Number[2] && nn[3]&n.Mask[3] == n.Number[3]
	}
	return true
}

func ( n Network ) Contains ( nn NetworkNumber ) bool { if len ( n . Mask ) != len ( nn ) { return false } if nn [ 0 ] & n . Mask [ 0 ] != n . Number [ 0 ] { return false } if len ( nn ) == IPv6Uint32Count { return nn [ 1 ] & n . Mask [ 1 ] == n . Number [ 1 ] && nn [ 2 ] & n . Mask [ 2 ] == n . Number [ 2 ] && nn [ 3 ] & n . Mask [ 3 ] == n . Number [ 3 ] } return true }

// Contains returns true if NetworkNumber is in range of Network, false
// otherwise.

Contains returns true if NetworkNumber is in range of Network false otherwise .


func (n Network) Covers(o Network) bool {
	if len(n.Number) != len(o.Number) {
		return false
	}
	nMaskSize, _ := n.IPNet.Mask.Size()
	oMaskSize, _ := o.IPNet.Mask.Size()
	return n.Contains(o.Number) && nMaskSize <= oMaskSize
}

func ( n Network ) Covers ( o Network ) bool { if len ( n . Number ) != len ( o . Number ) { return false } nMaskSize , _ := n . IPNet . Mask . Size ( ) oMaskSize , _ := o . IPNet . Mask . Size ( ) return n . Contains ( o . Number ) && nMaskSize <= oMaskSize }

// Contains returns true if Network covers o, false otherwise

Contains returns true if Network covers o false otherwise


func (n Network) LeastCommonBitPosition(n1 Network) (uint, error) {
	maskSize, _ := n.IPNet.Mask.Size()
	if maskSize1, _ := n1.IPNet.Mask.Size(); maskSize1 < maskSize {
		maskSize = maskSize1
	}
	maskPosition := len(n1.Number)*BitsPerUint32 - maskSize
	lcb, err := n.Number.LeastCommonBitPosition(n1.Number)
	if err != nil {
		return 0, err
	}
	return uint(math.Max(float64(maskPosition), float64(lcb))), nil
}

func ( n Network ) LeastCommonBitPosition ( n1 Network ) ( uint , error ) { maskSize , _ := n . IPNet . Mask . Size ( ) if maskSize1 , _ := n1 . IPNet . Mask . Size ( ) ; maskSize1 < maskSize { maskSize = maskSize1 } maskPosition := len ( n1 . Number ) * BitsPerUint32 - maskSize lcb , err := n . Number . LeastCommonBitPosition ( n1 . Number ) if err != nil { return 0 , err } return uint ( math . Max ( float64 ( maskPosition ) , float64 ( lcb ) ) ) , nil }

// LeastCommonBitPosition returns the smallest position of the preceding common
// bits of the 2 networks, and returns an error ErrNoGreatestCommonBit
// if the two network number diverges from the first bit.

LeastCommonBitPosition returns the smallest position of the preceding common bits of the 2 networks and returns an error ErrNoGreatestCommonBit if the two network number diverges from the first bit .


func (n Network) Equal(n1 Network) bool {
	return n.String() == n1.String()
}

func ( n Network ) Equal ( n1 Network ) bool { return n . String ( ) == n1 . String ( ) }

// Equal is the equality test for 2 networks.

Equal is the equality test for 2 networks .


func (m NetworkNumberMask) Mask(n NetworkNumber) (NetworkNumber, error) {
	if len(m) != len(n) {
		return nil, ErrVersionMismatch
	}
	result := make(NetworkNumber, len(m))
	result[0] = m[0] & n[0]
	if len(m) == IPv6Uint32Count {
		result[1] = m[1] & n[1]
		result[2] = m[2] & n[2]
		result[3] = m[3] & n[3]
	}
	return result, nil
}

func ( m NetworkNumberMask ) Mask ( n NetworkNumber ) ( NetworkNumber , error ) { if len ( m ) != len ( n ) { return nil , ErrVersionMismatch } result := make ( NetworkNumber , len ( m ) ) result [ 0 ] = m [ 0 ] & n [ 0 ] if len ( m ) == IPv6Uint32Count { result [ 1 ] = m [ 1 ] & n [ 1 ] result [ 2 ] = m [ 2 ] & n [ 2 ] result [ 3 ] = m [ 3 ] & n [ 3 ] } return result , nil }

// Mask returns a new masked NetworkNumber from given NetworkNumber.

Mask returns a new masked NetworkNumber from given NetworkNumber .


func NextIP(ip net.IP) net.IP {
	return NewNetworkNumber(ip).Next().ToIP()
}

func NextIP ( ip net . IP ) net . IP { return NewNetworkNumber ( ip ) . Next ( ) . ToIP ( ) }

// NextIP returns the next sequential ip.


func PreviousIP(ip net.IP) net.IP {
	return NewNetworkNumber(ip).Previous().ToIP()
}

func PreviousIP ( ip net . IP ) net . IP { return NewNetworkNumber ( ip ) . Previous ( ) . ToIP ( ) }

// PreviousIP returns the previous sequential ip.

PreviousIP returns the previous sequential ip .


func newPrefixTree(version rnet.IPVersion) Ranger {
	_, rootNet, _ := net.ParseCIDR("0.0.0.0/0")
	if version == rnet.IPv6 {
		_, rootNet, _ = net.ParseCIDR("0::0/0")
	}
	return &prefixTrie{
		children:       make([]*prefixTrie, 2, 2),
		numBitsSkipped: 0,
		numBitsHandled: 1,
		network:        rnet.NewNetwork(*rootNet),
	}
}

func newPrefixTree ( version rnet . IPVersion ) Ranger { _ , rootNet , _ := net . ParseCIDR ( " " ) if version == rnet . IPv6 { _ , rootNet , _ = net . ParseCIDR ( " " ) } return & prefixTrie { children : make ( [ ] * prefixTrie , 2 , 2 ) , numBitsSkipped : 0 , numBitsHandled : 1 , network : rnet . NewNetwork ( * rootNet ) , } }

// newPrefixTree creates a new prefixTrie.

newPrefixTree creates a new prefixTrie .


func (p *prefixTrie) Insert(entry RangerEntry) error {
	network := entry.Network()
	return p.insert(rnet.NewNetwork(network), entry)
}

func ( p * prefixTrie ) Insert ( entry RangerEntry ) error { network := entry . Network ( ) return p . insert ( rnet . NewNetwork ( network ) , entry ) }

// Insert inserts a RangerEntry into prefix trie.

Insert inserts a RangerEntry into prefix trie .


func (p *prefixTrie) Remove(network net.IPNet) (RangerEntry, error) {
	return p.remove(rnet.NewNetwork(network))
}

func ( p * prefixTrie ) Remove ( network net . IPNet ) ( RangerEntry , error ) { return p . remove ( rnet . NewNetwork ( network ) ) }

// Remove removes RangerEntry identified by given network from trie.

Remove removes RangerEntry identified by given network from trie .


func (p *prefixTrie) Contains(ip net.IP) (bool, error) {
	nn := rnet.NewNetworkNumber(ip)
	if nn == nil {
		return false, ErrInvalidNetworkNumberInput
	}
	return p.contains(nn)
}

func ( p * prefixTrie ) Contains ( ip net . IP ) ( bool , error ) { nn := rnet . NewNetworkNumber ( ip ) if nn == nil { return false , ErrInvalidNetworkNumberInput } return p . contains ( nn ) }

// Contains returns boolean indicating whether given ip is contained in any
// of the inserted networks.

Contains returns boolean indicating whether given ip is contained in any of the inserted networks .


func (p *prefixTrie) String() string {
	children := []string{}
	padding := strings.Repeat("| ", p.level()+1)
	for bits, child := range p.children {
		if child == nil {
			continue
		}
		childStr := fmt.Sprintf("\n%s%d--> %s", padding, bits, child.String())
		children = append(children, childStr)
	}
	return fmt.Sprintf("%s (target_pos:%d:has_entry:%t)%s", p.network,
		p.targetBitPosition(), p.hasEntry(), strings.Join(children, ""))
}

func ( p * prefixTrie ) String ( ) string { children := [ ] string { } padding := strings . Repeat ( " " , p . level ( ) + 1 ) for bits , child := range p . children { if child == nil { continue } childStr := fmt . Sprintf ( " \n " , padding , bits , child . String ( ) ) children = append ( children , childStr ) } return fmt . Sprintf ( " " , p . network , p . targetBitPosition ( ) , p . hasEntry ( ) , strings . Join ( children , " " ) ) }

// String returns string representation of trie, mainly for visualization and
// debugging.

String returns string representation of trie mainly for visualization and debugging .


func (p *prefixTrie) walkDepth() <-chan RangerEntry {
	entries := make(chan RangerEntry)
	go func() {
		if p.hasEntry() {
			entries <- p.entry
		}
		childEntriesList := []<-chan RangerEntry{}
		for _, trie := range p.children {
			if trie == nil {
				continue
			}
			childEntriesList = append(childEntriesList, trie.walkDepth())
		}
		for _, childEntries := range childEntriesList {
			for entry := range childEntries {
				entries <- entry
			}
		}
		close(entries)
	}()
	return entries
}

func ( p * prefixTrie ) walkDepth ( ) <- chan RangerEntry { entries := make ( chan RangerEntry ) go func ( ) { if p . hasEntry ( ) { entries <- p . entry } childEntriesList := [ ] <- chan RangerEntry { } for _ , trie := range p . children { if trie == nil { continue } childEntriesList = append ( childEntriesList , trie . walkDepth ( ) ) } for _ , childEntries := range childEntriesList { for entry := range childEntries { entries <- entry } } close ( entries ) } ( ) return entries }

// walkDepth walks the trie in depth order, for unit testing.

walkDepth walks the trie in depth order for unit testing .


func newBruteRanger() Ranger {
	return &bruteRanger{
		ipV4Entries: make(map[string]RangerEntry),
		ipV6Entries: make(map[string]RangerEntry),
	}
}

func newBruteRanger ( ) Ranger { return & bruteRanger { ipV4Entries : make ( map [ string ] RangerEntry ) , ipV6Entries : make ( map [ string ] RangerEntry ) , } }


func (b *bruteRanger) Insert(entry RangerEntry) error {
	network := entry.Network()
	key := network.String()
	if _, found := b.ipV4Entries[key]; !found {
		entries, err := b.getEntriesByVersion(entry.Network().IP)
		if err != nil {
			return err
		}
		entries[key] = entry
	}
	return nil
}

func ( b * bruteRanger ) Insert ( entry RangerEntry ) error { network := entry . Network ( ) key := network . String ( ) if _ , found := b . ipV4Entries [ key ] ; ! found { entries , err := b . getEntriesByVersion ( entry . Network ( ) . IP ) if err != nil { return err } entries [ key ] = entry } return nil }

// Insert inserts a RangerEntry into ranger.

Insert inserts a RangerEntry into ranger .


func (b *bruteRanger) Remove(network net.IPNet) (RangerEntry, error) {
	networks, err := b.getEntriesByVersion(network.IP)
	if err != nil {
		return nil, err
	}
	key := network.String()
	if networkToDelete, found := networks[key]; found {
		delete(networks, key)
		return networkToDelete, nil
	}
	return nil, nil
}

func ( b * bruteRanger ) Remove ( network net . IPNet ) ( RangerEntry , error ) { networks , err := b . getEntriesByVersion ( network . IP ) if err != nil { return nil , err } key := network . String ( ) if networkToDelete , found := networks [ key ] ; found { delete ( networks , key ) return networkToDelete , nil } return nil , nil }

// Remove removes a RangerEntry identified by given network from ranger.

Remove removes a RangerEntry identified by given network from ranger .


func (b *bruteRanger) Contains(ip net.IP) (bool, error) {
	entries, err := b.getEntriesByVersion(ip)
	if err != nil {
		return false, err
	}
	for _, entry := range entries {
		network := entry.Network()
		if network.Contains(ip) {
			return true, nil
		}
	}
	return false, nil
}

func ( b * bruteRanger ) Contains ( ip net . IP ) ( bool , error ) { entries , err := b . getEntriesByVersion ( ip ) if err != nil { return false , err } for _ , entry := range entries { network := entry . Network ( ) if network . Contains ( ip ) { return true , nil } } return false , nil }

// Contains returns bool indicating whether given ip is contained by any
// network in ranger.

Contains returns bool indicating whether given ip is contained by any network in ranger .


func ParseMessage(line string) Message {
	// Uncomment this and recoverMessage if debugging a message that crashes the parser
	//defer recoverMessage(line)

	ircMessage, err := parseIRCMessage(line)
	if err != nil {
		return parseRawMessage(ircMessage)
	}

	if mt, ok := messageTypeMap[ircMessage.Command]; ok {
		return mt.Parser(ircMessage)
	}

	return parseRawMessage(ircMessage)
}

// ParseMessage parse a raw Twitch IRC message


func NewClient(username, oauth string) *Client {
	return &Client{
		ircUser:         username,
		ircToken:        oauth,
		TLS:             true,
		channels:        map[string]bool{},
		channelUserlist: map[string]map[string]bool{},
		channelsMtx:     &sync.RWMutex{},
		messageReceived: make(chan bool),

		read:  make(chan string, ReadBufferSize),
		write: make(chan string, WriteBufferSize),

		// NOTE: IdlePingInterval must be higher than PongTimeout
		SendPings:        true,
		IdlePingInterval: time.Second * 15,
		PongTimeout:      time.Second * 5,

		channelUserlistMutex: &sync.RWMutex{},
	}
}


func (c *Client) Say(channel, text string) {
	channel = strings.ToLower(channel)

	c.send(fmt.Sprintf("PRIVMSG #%s :%s", channel, text))
}

func ( c * Client ) Say ( channel , text string ) { channel = strings . ToLower ( channel ) c . send ( fmt . Sprintf ( " " , channel , text ) ) }


func (c *Client) Whisper(username, text string) {
	c.send(fmt.Sprintf("PRIVMSG #%s :/w %s %s", c.ircUser, username, text))
}

func ( c * Client ) Whisper ( username , text string ) { c . send ( fmt . Sprintf ( " " , c . ircUser , username , text ) ) }

// Whisper write something in private to someone on twitch
// whispers are heavily spam protected
// so your message might get blocked because of this
// verify your bot to prevent this

Whisper write something in private to someone on twitch whispers are heavily spam protected so your message might get blocked because of this verify your bot to prevent this


func (c *Client) Join(channel string) {
	channel = strings.ToLower(channel)

	// If we don't have the channel in our map AND we have an
	// active connection, explicitly join before we add it to our map
	c.channelsMtx.Lock()
	if !c.channels[channel] && c.connActive.get() {
		go c.send(fmt.Sprintf("JOIN #%s", channel))
	}

	c.channels[channel] = true
	c.channelUserlistMutex.Lock()
	c.channelUserlist[channel] = map[string]bool{}
	c.channelUserlistMutex.Unlock()
	c.channelsMtx.Unlock()
}

// Join enter a twitch channel to read more messages


func (c *Client) Depart(channel string) {
	if c.connActive.get() {
		go c.send(fmt.Sprintf("PART #%s", channel))
	}

	c.channelsMtx.Lock()
	delete(c.channels, channel)
	c.channelUserlistMutex.Lock()
	delete(c.channelUserlist, channel)
	c.channelUserlistMutex.Unlock()
	c.channelsMtx.Unlock()
}

func ( c * Client ) Depart ( channel string ) { if c . connActive . get ( ) { go c . send ( fmt . Sprintf ( " " , channel ) ) } c . channelsMtx . Lock ( ) delete ( c . channels , channel ) c . channelUserlistMutex . Lock ( ) delete ( c . channelUserlist , channel ) c . channelUserlistMutex . Unlock ( ) c . channelsMtx . Unlock ( ) }


func (c *Client) Disconnect() error {
	if !c.connActive.get() {
		return ErrConnectionIsNotOpen
	}

	c.userDisconnect.Close()

	return nil
}

func ( c * Client ) Disconnect ( ) error { if ! c . connActive . get ( ) { return ErrConnectionIsNotOpen } c . userDisconnect . Close ( ) return nil }


func (c *Client) Connect() error {
	if c.IrcAddress == "" && c.TLS {
		c.IrcAddress = ircTwitchTLS
	} else if c.IrcAddress == "" && !c.TLS {
		c.IrcAddress = ircTwitch
	}

	dialer := &net.Dialer{
		KeepAlive: time.Second * 10,
	}

	var conf *tls.Config
	// This means we are connecting to "localhost". Disable certificate chain check
	if strings.HasPrefix(c.IrcAddress, "127.0.0.1:") {
		conf = &tls.Config{
			InsecureSkipVerify: true,
		}
	} else {
		conf = &tls.Config{}
	}

	for {
		err := c.makeConnection(dialer, conf)

		switch err {
		case errReconnect:
			continue

		default:
			return err
		}
	}
}

// Connect connect the client to the irc server


func (c *Client) Userlist(channel string) ([]string, error) {
	c.channelUserlistMutex.RLock()
	defer c.channelUserlistMutex.RUnlock()
	usermap, ok := c.channelUserlist[channel]
	if !ok || usermap == nil {
		return nil, fmt.Errorf("Could not find userlist for channel '%s' in client", channel)
	}
	userlist := make([]string, len(usermap))

	i := 0
	for key := range usermap {
		userlist[i] = key
		i++
	}

	return userlist, nil
}

func ( c * Client ) Userlist ( channel string ) ( [ ] string , error ) { c . channelUserlistMutex . RLock ( ) defer c . channelUserlistMutex . RUnlock ( ) usermap , ok := c . channelUserlist [ channel ] if ! ok || usermap == nil { return nil , fmt . Errorf ( " " , channel ) } userlist := make ( [ ] string , len ( usermap ) ) i := 0 for key := range usermap { userlist [ i ] = key i ++ } return userlist , nil }

// Userlist returns the userlist for a given channel