network: implement asyncblock for polling job results
This implements async blocking if config option is enabled by polling
the async job id and showing a cursor.
Add vendor dependency: briandowns/spinner
Signed-off-by: Rohit Yadav <rohit@apache.org>
diff --git a/cli/completer.go b/cli/completer.go
index 9fb8bd8..bd2822a 100644
--- a/cli/completer.go
+++ b/cli/completer.go
@@ -212,7 +212,7 @@
autocompleteAPIArgs = append(autocompleteAPIArgs, "templatefilter=all")
}
fmt.Printf("\nFetching options, please wait...")
- response, _ := cmd.NewAPIRequest(r, autocompleteAPI.Name, autocompleteAPIArgs)
+ response, _ := cmd.NewAPIRequest(r, autocompleteAPI.Name, autocompleteAPIArgs, false)
fmt.Printf("\r")
var autocompleteOptions []selectOption
diff --git a/cmd/api.go b/cmd/api.go
index ba7b70d..9237ff5 100644
--- a/cmd/api.go
+++ b/cmd/api.go
@@ -160,7 +160,7 @@
return nil
}
- response, err := NewAPIRequest(r, api.Name, apiArgs)
+ response, err := NewAPIRequest(r, api.Name, apiArgs, api.Async)
if err != nil {
return err
}
diff --git a/cmd/network.go b/cmd/network.go
index 3361526..c55998f 100644
--- a/cmd/network.go
+++ b/cmd/network.go
@@ -26,15 +26,25 @@
"encoding/json"
"errors"
"fmt"
+ "github.com/briandowns/spinner"
"io/ioutil"
"net/http"
"net/http/cookiejar"
"net/url"
+ "runtime"
"sort"
"strings"
"time"
)
+var cursor = []string{"\r⣷ 😸", "\r⣯ 😹", "\r⣟ 😺", "\r⡿ 😻", "\r⢿ 😼", "\r⣻ 😽", "\r⣽ 😾", "\r⣾ 😻"}
+
+func init() {
+ if runtime.GOOS == "windows" {
+ cursor = []string{"|", "/", "-", "\\"}
+ }
+}
+
func encodeRequestParams(params url.Values) string {
if params == nil {
return ""
@@ -98,8 +108,49 @@
return client, sessionKey, nil
}
+func getResponseData(data map[string]interface{}) map[string]interface{} {
+ for k := range data {
+ if strings.HasSuffix(k, "response") {
+ return data[k].(map[string]interface{})
+ }
+ }
+ return nil
+}
+
+func pollAsyncJob(r *Request, jobId string) (map[string]interface{}, error) {
+ for timeout := float64(r.Config.Core.Timeout); timeout > 0.0; {
+ startTime := time.Now()
+ s := spinner.New(cursor, 200*time.Millisecond)
+ s.Color("blue", "bold")
+ s.Suffix = " polling for async API job result"
+ s.Start()
+ queryResult, queryError := NewAPIRequest(r, "queryAsyncJobResult", []string{"jobid=" + jobId}, false)
+ diff := time.Duration(1*time.Second).Nanoseconds() - time.Now().Sub(startTime).Nanoseconds()
+ if diff > 0 {
+ time.Sleep(time.Duration(diff) * time.Nanosecond)
+ }
+ s.Stop()
+ timeout = timeout - time.Now().Sub(startTime).Seconds()
+ if queryError != nil {
+ return queryResult, queryError
+ }
+ jobStatus := queryResult["jobstatus"].(float64)
+ if jobStatus == 0 {
+ continue
+ }
+ if jobStatus == 1 {
+ return queryResult["jobresult"].(map[string]interface{}), nil
+
+ }
+ if jobStatus == 2 {
+ return queryResult, errors.New("async API job failed")
+ }
+ }
+ return nil, errors.New("async API job query timed out")
+}
+
// NewAPIRequest makes an API request to configured management server
-func NewAPIRequest(r *Request, api string, args []string) (map[string]interface{}, error) {
+func NewAPIRequest(r *Request, api string, args []string, isAsync bool) (map[string]interface{}, error) {
params := make(url.Values)
params.Add("command", api)
for _, arg := range args {
@@ -156,10 +207,16 @@
var data map[string]interface{}
_ = json.Unmarshal([]byte(body), &data)
- for k := range data {
- if strings.HasSuffix(k, "response") {
- return data[k].(map[string]interface{}), nil
+ if isAsync && r.Config.Core.AsyncBlock {
+ if jobResponse := getResponseData(data); jobResponse != nil && jobResponse["jobid"] != nil {
+ jobId := jobResponse["jobid"].(string)
+ return pollAsyncJob(r, jobId)
}
}
+
+ if apiResponse := getResponseData(data); apiResponse != nil {
+ return apiResponse, nil
+ }
+
return nil, errors.New("failed to decode response")
}
diff --git a/cmd/set.go b/cmd/set.go
index 1755227..70c7de9 100644
--- a/cmd/set.go
+++ b/cmd/set.go
@@ -27,7 +27,7 @@
Name: "set",
Help: "Configures options for cmk",
SubCommands: map[string][]string{
- "prompt": {"🐵", "random"},
+ "prompt": {"🐵", "🐱", "random"},
"asyncblock": {"true", "false"},
"timeout": {"600", "1800", "3600"},
"output": {"json", "text", "table", "xml"},
diff --git a/cmd/sync.go b/cmd/sync.go
index 3bad31e..160aa3f 100644
--- a/cmd/sync.go
+++ b/cmd/sync.go
@@ -26,7 +26,7 @@
Name: "sync",
Help: "Discovers and updates APIs",
Handle: func(r *Request) error {
- response, err := NewAPIRequest(r, "listApis", []string{"listall=true"})
+ response, err := NewAPIRequest(r, "listApis", []string{"listall=true"}, false)
if err != nil {
return err
}
diff --git a/vendor/github.com/briandowns/spinner/LICENSE b/vendor/github.com/briandowns/spinner/LICENSE
new file mode 100644
index 0000000..dd5b3a5
--- /dev/null
+++ b/vendor/github.com/briandowns/spinner/LICENSE
@@ -0,0 +1,174 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
diff --git a/vendor/github.com/briandowns/spinner/character_sets.go b/vendor/github.com/briandowns/spinner/character_sets.go
new file mode 100644
index 0000000..1efe6e6
--- /dev/null
+++ b/vendor/github.com/briandowns/spinner/character_sets.go
@@ -0,0 +1,59 @@
+package spinner
+
+const (
+ clockOneOClock = '\U0001F550'
+ clockOneThirty = '\U0001F55C'
+)
+
+// CharSets contains the available character sets
+var CharSets = map[int][]string{
+ 0: {"←", "↖", "↑", "↗", "→", "↘", "↓", "↙"},
+ 1: {"▁", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃", "▁"},
+ 2: {"▖", "▘", "▝", "▗"},
+ 3: {"┤", "┘", "┴", "└", "├", "┌", "┬", "┐"},
+ 4: {"◢", "◣", "◤", "◥"},
+ 5: {"◰", "◳", "◲", "◱"},
+ 6: {"◴", "◷", "◶", "◵"},
+ 7: {"◐", "◓", "◑", "◒"},
+ 8: {".", "o", "O", "@", "*"},
+ 9: {"|", "/", "-", "\\"},
+ 10: {"◡◡", "⊙⊙", "◠◠"},
+ 11: {"⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"},
+ 12: {">))'>", " >))'>", " >))'>", " >))'>", " >))'>", " <'((<", " <'((<", " <'((<"},
+ 13: {"⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"},
+ 14: {"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"},
+ 15: {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"},
+ 16: {"▉", "▊", "▋", "▌", "▍", "▎", "▏", "▎", "▍", "▌", "▋", "▊", "▉"},
+ 17: {"■", "□", "▪", "▫"},
+ 18: {"←", "↑", "→", "↓"},
+ 19: {"╫", "╪"},
+ 20: {"⇐", "⇖", "⇑", "⇗", "⇒", "⇘", "⇓", "⇙"},
+ 21: {"⠁", "⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄", "⠄", "⠤", "⠠", "⠠", "⠤", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈", "⠈"},
+ 22: {"⠈", "⠉", "⠋", "⠓", "⠒", "⠐", "⠐", "⠒", "⠖", "⠦", "⠤", "⠠", "⠠", "⠤", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈"},
+ 23: {"⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄", "⠄", "⠤", "⠴", "⠲", "⠒", "⠂", "⠂", "⠒", "⠚", "⠙", "⠉", "⠁"},
+ 24: {"⠋", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋"},
+ 25: {"ヲ", "ァ", "ィ", "ゥ", "ェ", "ォ", "ャ", "ュ", "ョ", "ッ", "ア", "イ", "ウ", "エ", "オ", "カ", "キ", "ク", "ケ", "コ", "サ", "シ", "ス", "セ", "ソ", "タ", "チ", "ツ", "テ", "ト", "ナ", "ニ", "ヌ", "ネ", "ノ", "ハ", "ヒ", "フ", "ヘ", "ホ", "マ", "ミ", "ム", "メ", "モ", "ヤ", "ユ", "ヨ", "ラ", "リ", "ル", "レ", "ロ", "ワ", "ン"},
+ 26: {".", "..", "..."},
+ 27: {"▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "▉", "▊", "▋", "▌", "▍", "▎", "▏", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█", "▇", "▆", "▅", "▄", "▃", "▂", "▁"},
+ 28: {".", "o", "O", "°", "O", "o", "."},
+ 29: {"+", "x"},
+ 30: {"v", "<", "^", ">"},
+ 31: {">>--->", " >>--->", " >>--->", " >>--->", " >>--->", " <---<<", " <---<<", " <---<<", " <---<<", "<---<<"},
+ 32: {"|", "||", "|||", "||||", "|||||", "|||||||", "||||||||", "|||||||", "||||||", "|||||", "||||", "|||", "||", "|"},
+ 33: {"[ ]", "[= ]", "[== ]", "[=== ]", "[==== ]", "[===== ]", "[====== ]", "[======= ]", "[======== ]", "[========= ]", "[==========]"},
+ 34: {"(*---------)", "(-*--------)", "(--*-------)", "(---*------)", "(----*-----)", "(-----*----)", "(------*---)", "(-------*--)", "(--------*-)", "(---------*)"},
+ 35: {"█▒▒▒▒▒▒▒▒▒", "███▒▒▒▒▒▒▒", "█████▒▒▒▒▒", "███████▒▒▒", "██████████"},
+ 36: {"[ ]", "[=> ]", "[===> ]", "[=====> ]", "[======> ]", "[========> ]", "[==========> ]", "[============> ]", "[==============> ]", "[================> ]", "[==================> ]", "[===================>]"},
+ 39: {"🌍", "🌎", "🌏"},
+ 40: {"◜", "◝", "◞", "◟"},
+ 41: {"⬒", "⬔", "⬓", "⬕"},
+ 42: {"⬖", "⬘", "⬗", "⬙"},
+ 43: {"[>>> >]", "[]>>>> []", "[] >>>> []", "[] >>>> []", "[] >>>> []", "[] >>>>[]", "[>> >>]"},
+}
+
+func init() {
+ for i := rune(0); i < 12; i++ {
+ CharSets[37] = append(CharSets[37], string([]rune{clockOneOClock + i}))
+ CharSets[38] = append(CharSets[38], string([]rune{clockOneOClock + i}), string([]rune{clockOneThirty + i}))
+ }
+}
diff --git a/vendor/github.com/briandowns/spinner/spinner.go b/vendor/github.com/briandowns/spinner/spinner.go
new file mode 100644
index 0000000..2cd0414
--- /dev/null
+++ b/vendor/github.com/briandowns/spinner/spinner.go
@@ -0,0 +1,316 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package spinner is a simple package to add a spinner / progress indicator to any terminal application.
+package spinner
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "strconv"
+ "sync"
+ "time"
+ "unicode/utf8"
+
+ "github.com/fatih/color"
+)
+
+// errInvalidColor is returned when attempting to set an invalid color
+var errInvalidColor = errors.New("invalid color")
+
+// validColors holds an array of the only colors allowed
+var validColors = map[string]bool{
+ // default colors for backwards compatibility
+ "black": true,
+ "red": true,
+ "green": true,
+ "yellow": true,
+ "blue": true,
+ "magenta": true,
+ "cyan": true,
+ "white": true,
+
+ // attributes
+ "reset": true,
+ "bold": true,
+ "faint": true,
+ "italic": true,
+ "underline": true,
+ "blinkslow": true,
+ "blinkrapid": true,
+ "reversevideo": true,
+ "concealed": true,
+ "crossedout": true,
+
+ // foreground text
+ "fgBlack": true,
+ "fgRed": true,
+ "fgGreen": true,
+ "fgYellow": true,
+ "fgBlue": true,
+ "fgMagenta": true,
+ "fgCyan": true,
+ "fgWhite": true,
+
+ // foreground Hi-Intensity text
+ "fgHiBlack": true,
+ "fgHiRed": true,
+ "fgHiGreen": true,
+ "fgHiYellow": true,
+ "fgHiBlue": true,
+ "fgHiMagenta": true,
+ "fgHiCyan": true,
+ "fgHiWhite": true,
+
+ // background text
+ "bgBlack": true,
+ "bgRed": true,
+ "bgGreen": true,
+ "bgYellow": true,
+ "bgBlue": true,
+ "bgMagenta": true,
+ "bgCyan": true,
+ "bgWhite": true,
+
+ // background Hi-Intensity text
+ "bgHiBlack": true,
+ "bgHiRed": true,
+ "bgHiGreen": true,
+ "bgHiYellow": true,
+ "bgHiBlue": true,
+ "bgHiMagenta": true,
+ "bgHiCyan": true,
+ "bgHiWhite": true,
+}
+
+// returns a valid color's foreground text color attribute
+var colorAttributeMap = map[string]color.Attribute{
+ // default colors for backwards compatibility
+ "black": color.FgBlack,
+ "red": color.FgRed,
+ "green": color.FgGreen,
+ "yellow": color.FgYellow,
+ "blue": color.FgBlue,
+ "magenta": color.FgMagenta,
+ "cyan": color.FgCyan,
+ "white": color.FgWhite,
+
+ // attributes
+ "reset": color.Reset,
+ "bold": color.Bold,
+ "faint": color.Faint,
+ "italic": color.Italic,
+ "underline": color.Underline,
+ "blinkslow": color.BlinkSlow,
+ "blinkrapid": color.BlinkRapid,
+ "reversevideo": color.ReverseVideo,
+ "concealed": color.Concealed,
+ "crossedout": color.CrossedOut,
+
+ // foreground text colors
+ "fgBlack": color.FgBlack,
+ "fgRed": color.FgRed,
+ "fgGreen": color.FgGreen,
+ "fgYellow": color.FgYellow,
+ "fgBlue": color.FgBlue,
+ "fgMagenta": color.FgMagenta,
+ "fgCyan": color.FgCyan,
+ "fgWhite": color.FgWhite,
+
+ // foreground Hi-Intensity text colors
+ "fgHiBlack": color.FgHiBlack,
+ "fgHiRed": color.FgHiRed,
+ "fgHiGreen": color.FgHiGreen,
+ "fgHiYellow": color.FgHiYellow,
+ "fgHiBlue": color.FgHiBlue,
+ "fgHiMagenta": color.FgHiMagenta,
+ "fgHiCyan": color.FgHiCyan,
+ "fgHiWhite": color.FgHiWhite,
+
+ // background text colors
+ "bgBlack": color.BgBlack,
+ "bgRed": color.BgRed,
+ "bgGreen": color.BgGreen,
+ "bgYellow": color.BgYellow,
+ "bgBlue": color.BgBlue,
+ "bgMagenta": color.BgMagenta,
+ "bgCyan": color.BgCyan,
+ "bgWhite": color.BgWhite,
+
+ // background Hi-Intensity text colors
+ "bgHiBlack": color.BgHiBlack,
+ "bgHiRed": color.BgHiRed,
+ "bgHiGreen": color.BgHiGreen,
+ "bgHiYellow": color.BgHiYellow,
+ "bgHiBlue": color.BgHiBlue,
+ "bgHiMagenta": color.BgHiMagenta,
+ "bgHiCyan": color.BgHiCyan,
+ "bgHiWhite": color.BgHiWhite,
+}
+
+// validColor will make sure the given color is actually allowed
+func validColor(c string) bool {
+ valid := false
+ if validColors[c] {
+ valid = true
+ }
+ return valid
+}
+
+// Spinner struct to hold the provided options
+type Spinner struct {
+ Delay time.Duration // Delay is the speed of the indicator
+ chars []string // chars holds the chosen character set
+ Prefix string // Prefix is the text preppended to the indicator
+ Suffix string // Suffix is the text appended to the indicator
+ FinalMSG string // string displayed after Stop() is called
+ lastOutput string // last character(set) written
+ color func(a ...interface{}) string // default color is white
+ lock *sync.RWMutex //
+ Writer io.Writer // to make testing better, exported so users have access
+ active bool // active holds the state of the spinner
+ stopChan chan struct{} // stopChan is a channel used to stop the indicator
+}
+
+// New provides a pointer to an instance of Spinner with the supplied options
+func New(cs []string, d time.Duration) *Spinner {
+ return &Spinner{
+ Delay: d,
+ chars: cs,
+ color: color.New(color.FgWhite).SprintFunc(),
+ lock: &sync.RWMutex{},
+ Writer: color.Output,
+ active: false,
+ stopChan: make(chan struct{}, 1),
+ }
+}
+
+// Active will return whether or not the spinner is currently active
+func (s *Spinner) Active() bool {
+ return s.active
+}
+
+// Start will start the indicator
+func (s *Spinner) Start() {
+ if s.active {
+ return
+ }
+ s.active = true
+
+ go func() {
+ for {
+ for i := 0; i < len(s.chars); i++ {
+ select {
+ case <-s.stopChan:
+ return
+ default:
+ s.lock.Lock()
+ s.erase()
+ outColor := fmt.Sprintf("%s%s%s ", s.Prefix, s.color(s.chars[i]), s.Suffix)
+ outPlain := fmt.Sprintf("%s%s%s ", s.Prefix, s.chars[i], s.Suffix)
+ fmt.Fprint(s.Writer, outColor)
+ s.lastOutput = outPlain
+ delay := s.Delay
+ s.lock.Unlock()
+
+ time.Sleep(delay)
+ }
+ }
+ }
+ }()
+}
+
+// Stop stops the indicator
+func (s *Spinner) Stop() {
+ s.lock.Lock()
+ defer s.lock.Unlock()
+ if s.active {
+ s.active = false
+ s.erase()
+ if s.FinalMSG != "" {
+ fmt.Fprintf(s.Writer, s.FinalMSG)
+ }
+ s.stopChan <- struct{}{}
+ }
+}
+
+// Restart will stop and start the indicator
+func (s *Spinner) Restart() {
+ s.Stop()
+ s.Start()
+}
+
+// Reverse will reverse the order of the slice assigned to the indicator
+func (s *Spinner) Reverse() {
+ s.lock.Lock()
+ defer s.lock.Unlock()
+ for i, j := 0, len(s.chars)-1; i < j; i, j = i+1, j-1 {
+ s.chars[i], s.chars[j] = s.chars[j], s.chars[i]
+ }
+}
+
+// Color will set the struct field for the given color to be used
+func (s *Spinner) Color(colors ...string) error {
+
+ colorAttributes := make([]color.Attribute, len(colors))
+
+ // Verify colours are valid and place the appropriate attribute in the array
+ for index, c := range colors {
+ if !validColor(c) {
+ return errInvalidColor
+ }
+
+ colorAttributes[index] = colorAttributeMap[c]
+ }
+
+ s.color = color.New(colorAttributes...).SprintFunc()
+ s.Restart()
+ return nil
+}
+
+// UpdateSpeed will set the indicator delay to the given value
+func (s *Spinner) UpdateSpeed(d time.Duration) {
+ s.lock.Lock()
+ defer s.lock.Unlock()
+ s.Delay = d
+}
+
+// UpdateCharSet will change the current character set to the given one
+func (s *Spinner) UpdateCharSet(cs []string) {
+ s.lock.Lock()
+ defer s.lock.Unlock()
+ s.chars = cs
+}
+
+// erase deletes written characters
+//
+// Caller must already hold s.lock.
+func (s *Spinner) erase() {
+ n := utf8.RuneCountInString(s.lastOutput)
+ for _, c := range []string{"\b", " ", "\b"} {
+ for i := 0; i < n; i++ {
+ fmt.Fprintf(s.Writer, c)
+ }
+ }
+ s.lastOutput = ""
+}
+
+// GenerateNumberSequence will generate a slice of integers at the
+// provided length and convert them each to a string
+func GenerateNumberSequence(length int) []string {
+ numSeq := make([]string, length)
+ for i := 0; i < length; i++ {
+ numSeq[i] = strconv.Itoa(i)
+ }
+ return numSeq
+}
diff --git a/vendor/github.com/fatih/color/LICENSE.md b/vendor/github.com/fatih/color/LICENSE.md
new file mode 100644
index 0000000..25fdaf6
--- /dev/null
+++ b/vendor/github.com/fatih/color/LICENSE.md
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Fatih Arslan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go
new file mode 100644
index 0000000..91c8e9f
--- /dev/null
+++ b/vendor/github.com/fatih/color/color.go
@@ -0,0 +1,603 @@
+package color
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+ "sync"
+
+ "github.com/mattn/go-colorable"
+ "github.com/mattn/go-isatty"
+)
+
+var (
+ // NoColor defines if the output is colorized or not. It's dynamically set to
+ // false or true based on the stdout's file descriptor referring to a terminal
+ // or not. This is a global option and affects all colors. For more control
+ // over each color block use the methods DisableColor() individually.
+ NoColor = os.Getenv("TERM") == "dumb" ||
+ (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd()))
+
+ // Output defines the standard output of the print functions. By default
+ // os.Stdout is used.
+ Output = colorable.NewColorableStdout()
+
+ // Error defines a color supporting writer for os.Stderr.
+ Error = colorable.NewColorableStderr()
+
+ // colorsCache is used to reduce the count of created Color objects and
+ // allows to reuse already created objects with required Attribute.
+ colorsCache = make(map[Attribute]*Color)
+ colorsCacheMu sync.Mutex // protects colorsCache
+)
+
+// Color defines a custom color object which is defined by SGR parameters.
+type Color struct {
+ params []Attribute
+ noColor *bool
+}
+
+// Attribute defines a single SGR Code
+type Attribute int
+
+const escape = "\x1b"
+
+// Base attributes
+const (
+ Reset Attribute = iota
+ Bold
+ Faint
+ Italic
+ Underline
+ BlinkSlow
+ BlinkRapid
+ ReverseVideo
+ Concealed
+ CrossedOut
+)
+
+// Foreground text colors
+const (
+ FgBlack Attribute = iota + 30
+ FgRed
+ FgGreen
+ FgYellow
+ FgBlue
+ FgMagenta
+ FgCyan
+ FgWhite
+)
+
+// Foreground Hi-Intensity text colors
+const (
+ FgHiBlack Attribute = iota + 90
+ FgHiRed
+ FgHiGreen
+ FgHiYellow
+ FgHiBlue
+ FgHiMagenta
+ FgHiCyan
+ FgHiWhite
+)
+
+// Background text colors
+const (
+ BgBlack Attribute = iota + 40
+ BgRed
+ BgGreen
+ BgYellow
+ BgBlue
+ BgMagenta
+ BgCyan
+ BgWhite
+)
+
+// Background Hi-Intensity text colors
+const (
+ BgHiBlack Attribute = iota + 100
+ BgHiRed
+ BgHiGreen
+ BgHiYellow
+ BgHiBlue
+ BgHiMagenta
+ BgHiCyan
+ BgHiWhite
+)
+
+// New returns a newly created color object.
+func New(value ...Attribute) *Color {
+ c := &Color{params: make([]Attribute, 0)}
+ c.Add(value...)
+ return c
+}
+
+// Set sets the given parameters immediately. It will change the color of
+// output with the given SGR parameters until color.Unset() is called.
+func Set(p ...Attribute) *Color {
+ c := New(p...)
+ c.Set()
+ return c
+}
+
+// Unset resets all escape attributes and clears the output. Usually should
+// be called after Set().
+func Unset() {
+ if NoColor {
+ return
+ }
+
+ fmt.Fprintf(Output, "%s[%dm", escape, Reset)
+}
+
+// Set sets the SGR sequence.
+func (c *Color) Set() *Color {
+ if c.isNoColorSet() {
+ return c
+ }
+
+ fmt.Fprintf(Output, c.format())
+ return c
+}
+
+func (c *Color) unset() {
+ if c.isNoColorSet() {
+ return
+ }
+
+ Unset()
+}
+
+func (c *Color) setWriter(w io.Writer) *Color {
+ if c.isNoColorSet() {
+ return c
+ }
+
+ fmt.Fprintf(w, c.format())
+ return c
+}
+
+func (c *Color) unsetWriter(w io.Writer) {
+ if c.isNoColorSet() {
+ return
+ }
+
+ if NoColor {
+ return
+ }
+
+ fmt.Fprintf(w, "%s[%dm", escape, Reset)
+}
+
+// Add is used to chain SGR parameters. Use as many as parameters to combine
+// and create custom color objects. Example: Add(color.FgRed, color.Underline).
+func (c *Color) Add(value ...Attribute) *Color {
+ c.params = append(c.params, value...)
+ return c
+}
+
+func (c *Color) prepend(value Attribute) {
+ c.params = append(c.params, 0)
+ copy(c.params[1:], c.params[0:])
+ c.params[0] = value
+}
+
+// Fprint formats using the default formats for its operands and writes to w.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+// On Windows, users should wrap w with colorable.NewColorable() if w is of
+// type *os.File.
+func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
+ c.setWriter(w)
+ defer c.unsetWriter(w)
+
+ return fmt.Fprint(w, a...)
+}
+
+// Print formats using the default formats for its operands and writes to
+// standard output. Spaces are added between operands when neither is a
+// string. It returns the number of bytes written and any write error
+// encountered. This is the standard fmt.Print() method wrapped with the given
+// color.
+func (c *Color) Print(a ...interface{}) (n int, err error) {
+ c.Set()
+ defer c.unset()
+
+ return fmt.Fprint(Output, a...)
+}
+
+// Fprintf formats according to a format specifier and writes to w.
+// It returns the number of bytes written and any write error encountered.
+// On Windows, users should wrap w with colorable.NewColorable() if w is of
+// type *os.File.
+func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
+ c.setWriter(w)
+ defer c.unsetWriter(w)
+
+ return fmt.Fprintf(w, format, a...)
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+// This is the standard fmt.Printf() method wrapped with the given color.
+func (c *Color) Printf(format string, a ...interface{}) (n int, err error) {
+ c.Set()
+ defer c.unset()
+
+ return fmt.Fprintf(Output, format, a...)
+}
+
+// Fprintln formats using the default formats for its operands and writes to w.
+// Spaces are always added between operands and a newline is appended.
+// On Windows, users should wrap w with colorable.NewColorable() if w is of
+// type *os.File.
+func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
+ c.setWriter(w)
+ defer c.unsetWriter(w)
+
+ return fmt.Fprintln(w, a...)
+}
+
+// Println formats using the default formats for its operands and writes to
+// standard output. Spaces are always added between operands and a newline is
+// appended. It returns the number of bytes written and any write error
+// encountered. This is the standard fmt.Print() method wrapped with the given
+// color.
+func (c *Color) Println(a ...interface{}) (n int, err error) {
+ c.Set()
+ defer c.unset()
+
+ return fmt.Fprintln(Output, a...)
+}
+
+// Sprint is just like Print, but returns a string instead of printing it.
+func (c *Color) Sprint(a ...interface{}) string {
+ return c.wrap(fmt.Sprint(a...))
+}
+
+// Sprintln is just like Println, but returns a string instead of printing it.
+func (c *Color) Sprintln(a ...interface{}) string {
+ return c.wrap(fmt.Sprintln(a...))
+}
+
+// Sprintf is just like Printf, but returns a string instead of printing it.
+func (c *Color) Sprintf(format string, a ...interface{}) string {
+ return c.wrap(fmt.Sprintf(format, a...))
+}
+
+// FprintFunc returns a new function that prints the passed arguments as
+// colorized with color.Fprint().
+func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) {
+ return func(w io.Writer, a ...interface{}) {
+ c.Fprint(w, a...)
+ }
+}
+
+// PrintFunc returns a new function that prints the passed arguments as
+// colorized with color.Print().
+func (c *Color) PrintFunc() func(a ...interface{}) {
+ return func(a ...interface{}) {
+ c.Print(a...)
+ }
+}
+
+// FprintfFunc returns a new function that prints the passed arguments as
+// colorized with color.Fprintf().
+func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) {
+ return func(w io.Writer, format string, a ...interface{}) {
+ c.Fprintf(w, format, a...)
+ }
+}
+
+// PrintfFunc returns a new function that prints the passed arguments as
+// colorized with color.Printf().
+func (c *Color) PrintfFunc() func(format string, a ...interface{}) {
+ return func(format string, a ...interface{}) {
+ c.Printf(format, a...)
+ }
+}
+
+// FprintlnFunc returns a new function that prints the passed arguments as
+// colorized with color.Fprintln().
+func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) {
+ return func(w io.Writer, a ...interface{}) {
+ c.Fprintln(w, a...)
+ }
+}
+
+// PrintlnFunc returns a new function that prints the passed arguments as
+// colorized with color.Println().
+func (c *Color) PrintlnFunc() func(a ...interface{}) {
+ return func(a ...interface{}) {
+ c.Println(a...)
+ }
+}
+
+// SprintFunc returns a new function that returns colorized strings for the
+// given arguments with fmt.Sprint(). Useful to put into or mix into other
+// string. Windows users should use this in conjunction with color.Output, example:
+//
+// put := New(FgYellow).SprintFunc()
+// fmt.Fprintf(color.Output, "This is a %s", put("warning"))
+func (c *Color) SprintFunc() func(a ...interface{}) string {
+ return func(a ...interface{}) string {
+ return c.wrap(fmt.Sprint(a...))
+ }
+}
+
+// SprintfFunc returns a new function that returns colorized strings for the
+// given arguments with fmt.Sprintf(). Useful to put into or mix into other
+// string. Windows users should use this in conjunction with color.Output.
+func (c *Color) SprintfFunc() func(format string, a ...interface{}) string {
+ return func(format string, a ...interface{}) string {
+ return c.wrap(fmt.Sprintf(format, a...))
+ }
+}
+
+// SprintlnFunc returns a new function that returns colorized strings for the
+// given arguments with fmt.Sprintln(). Useful to put into or mix into other
+// string. Windows users should use this in conjunction with color.Output.
+func (c *Color) SprintlnFunc() func(a ...interface{}) string {
+ return func(a ...interface{}) string {
+ return c.wrap(fmt.Sprintln(a...))
+ }
+}
+
+// sequence returns a formatted SGR sequence to be plugged into a "\x1b[...m"
+// an example output might be: "1;36" -> bold cyan
+func (c *Color) sequence() string {
+ format := make([]string, len(c.params))
+ for i, v := range c.params {
+ format[i] = strconv.Itoa(int(v))
+ }
+
+ return strings.Join(format, ";")
+}
+
+// wrap wraps the s string with the colors attributes. The string is ready to
+// be printed.
+func (c *Color) wrap(s string) string {
+ if c.isNoColorSet() {
+ return s
+ }
+
+ return c.format() + s + c.unformat()
+}
+
+func (c *Color) format() string {
+ return fmt.Sprintf("%s[%sm", escape, c.sequence())
+}
+
+func (c *Color) unformat() string {
+ return fmt.Sprintf("%s[%dm", escape, Reset)
+}
+
+// DisableColor disables the color output. Useful to not change any existing
+// code and still being able to output. Can be used for flags like
+// "--no-color". To enable back use EnableColor() method.
+func (c *Color) DisableColor() {
+ c.noColor = boolPtr(true)
+}
+
+// EnableColor enables the color output. Use it in conjunction with
+// DisableColor(). Otherwise this method has no side effects.
+func (c *Color) EnableColor() {
+ c.noColor = boolPtr(false)
+}
+
+func (c *Color) isNoColorSet() bool {
+ // check first if we have user setted action
+ if c.noColor != nil {
+ return *c.noColor
+ }
+
+ // if not return the global option, which is disabled by default
+ return NoColor
+}
+
+// Equals returns a boolean value indicating whether two colors are equal.
+func (c *Color) Equals(c2 *Color) bool {
+ if len(c.params) != len(c2.params) {
+ return false
+ }
+
+ for _, attr := range c.params {
+ if !c2.attrExists(attr) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (c *Color) attrExists(a Attribute) bool {
+ for _, attr := range c.params {
+ if attr == a {
+ return true
+ }
+ }
+
+ return false
+}
+
+func boolPtr(v bool) *bool {
+ return &v
+}
+
+func getCachedColor(p Attribute) *Color {
+ colorsCacheMu.Lock()
+ defer colorsCacheMu.Unlock()
+
+ c, ok := colorsCache[p]
+ if !ok {
+ c = New(p)
+ colorsCache[p] = c
+ }
+
+ return c
+}
+
+func colorPrint(format string, p Attribute, a ...interface{}) {
+ c := getCachedColor(p)
+
+ if !strings.HasSuffix(format, "\n") {
+ format += "\n"
+ }
+
+ if len(a) == 0 {
+ c.Print(format)
+ } else {
+ c.Printf(format, a...)
+ }
+}
+
+func colorString(format string, p Attribute, a ...interface{}) string {
+ c := getCachedColor(p)
+
+ if len(a) == 0 {
+ return c.SprintFunc()(format)
+ }
+
+ return c.SprintfFunc()(format, a...)
+}
+
+// Black is a convenient helper function to print with black foreground. A
+// newline is appended to format by default.
+func Black(format string, a ...interface{}) { colorPrint(format, FgBlack, a...) }
+
+// Red is a convenient helper function to print with red foreground. A
+// newline is appended to format by default.
+func Red(format string, a ...interface{}) { colorPrint(format, FgRed, a...) }
+
+// Green is a convenient helper function to print with green foreground. A
+// newline is appended to format by default.
+func Green(format string, a ...interface{}) { colorPrint(format, FgGreen, a...) }
+
+// Yellow is a convenient helper function to print with yellow foreground.
+// A newline is appended to format by default.
+func Yellow(format string, a ...interface{}) { colorPrint(format, FgYellow, a...) }
+
+// Blue is a convenient helper function to print with blue foreground. A
+// newline is appended to format by default.
+func Blue(format string, a ...interface{}) { colorPrint(format, FgBlue, a...) }
+
+// Magenta is a convenient helper function to print with magenta foreground.
+// A newline is appended to format by default.
+func Magenta(format string, a ...interface{}) { colorPrint(format, FgMagenta, a...) }
+
+// Cyan is a convenient helper function to print with cyan foreground. A
+// newline is appended to format by default.
+func Cyan(format string, a ...interface{}) { colorPrint(format, FgCyan, a...) }
+
+// White is a convenient helper function to print with white foreground. A
+// newline is appended to format by default.
+func White(format string, a ...interface{}) { colorPrint(format, FgWhite, a...) }
+
+// BlackString is a convenient helper function to return a string with black
+// foreground.
+func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) }
+
+// RedString is a convenient helper function to return a string with red
+// foreground.
+func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) }
+
+// GreenString is a convenient helper function to return a string with green
+// foreground.
+func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) }
+
+// YellowString is a convenient helper function to return a string with yellow
+// foreground.
+func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) }
+
+// BlueString is a convenient helper function to return a string with blue
+// foreground.
+func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) }
+
+// MagentaString is a convenient helper function to return a string with magenta
+// foreground.
+func MagentaString(format string, a ...interface{}) string {
+ return colorString(format, FgMagenta, a...)
+}
+
+// CyanString is a convenient helper function to return a string with cyan
+// foreground.
+func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) }
+
+// WhiteString is a convenient helper function to return a string with white
+// foreground.
+func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) }
+
+// HiBlack is a convenient helper function to print with hi-intensity black foreground. A
+// newline is appended to format by default.
+func HiBlack(format string, a ...interface{}) { colorPrint(format, FgHiBlack, a...) }
+
+// HiRed is a convenient helper function to print with hi-intensity red foreground. A
+// newline is appended to format by default.
+func HiRed(format string, a ...interface{}) { colorPrint(format, FgHiRed, a...) }
+
+// HiGreen is a convenient helper function to print with hi-intensity green foreground. A
+// newline is appended to format by default.
+func HiGreen(format string, a ...interface{}) { colorPrint(format, FgHiGreen, a...) }
+
+// HiYellow is a convenient helper function to print with hi-intensity yellow foreground.
+// A newline is appended to format by default.
+func HiYellow(format string, a ...interface{}) { colorPrint(format, FgHiYellow, a...) }
+
+// HiBlue is a convenient helper function to print with hi-intensity blue foreground. A
+// newline is appended to format by default.
+func HiBlue(format string, a ...interface{}) { colorPrint(format, FgHiBlue, a...) }
+
+// HiMagenta is a convenient helper function to print with hi-intensity magenta foreground.
+// A newline is appended to format by default.
+func HiMagenta(format string, a ...interface{}) { colorPrint(format, FgHiMagenta, a...) }
+
+// HiCyan is a convenient helper function to print with hi-intensity cyan foreground. A
+// newline is appended to format by default.
+func HiCyan(format string, a ...interface{}) { colorPrint(format, FgHiCyan, a...) }
+
+// HiWhite is a convenient helper function to print with hi-intensity white foreground. A
+// newline is appended to format by default.
+func HiWhite(format string, a ...interface{}) { colorPrint(format, FgHiWhite, a...) }
+
+// HiBlackString is a convenient helper function to return a string with hi-intensity black
+// foreground.
+func HiBlackString(format string, a ...interface{}) string {
+ return colorString(format, FgHiBlack, a...)
+}
+
+// HiRedString is a convenient helper function to return a string with hi-intensity red
+// foreground.
+func HiRedString(format string, a ...interface{}) string { return colorString(format, FgHiRed, a...) }
+
+// HiGreenString is a convenient helper function to return a string with hi-intensity green
+// foreground.
+func HiGreenString(format string, a ...interface{}) string {
+ return colorString(format, FgHiGreen, a...)
+}
+
+// HiYellowString is a convenient helper function to return a string with hi-intensity yellow
+// foreground.
+func HiYellowString(format string, a ...interface{}) string {
+ return colorString(format, FgHiYellow, a...)
+}
+
+// HiBlueString is a convenient helper function to return a string with hi-intensity blue
+// foreground.
+func HiBlueString(format string, a ...interface{}) string { return colorString(format, FgHiBlue, a...) }
+
+// HiMagentaString is a convenient helper function to return a string with hi-intensity magenta
+// foreground.
+func HiMagentaString(format string, a ...interface{}) string {
+ return colorString(format, FgHiMagenta, a...)
+}
+
+// HiCyanString is a convenient helper function to return a string with hi-intensity cyan
+// foreground.
+func HiCyanString(format string, a ...interface{}) string { return colorString(format, FgHiCyan, a...) }
+
+// HiWhiteString is a convenient helper function to return a string with hi-intensity white
+// foreground.
+func HiWhiteString(format string, a ...interface{}) string {
+ return colorString(format, FgHiWhite, a...)
+}