This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack-cloudmonkey.git

commit 263ea076e6700600002e7eb6f237c6055bbcabcd
Author: Rohit Yadav <ro...@apache.org>
AuthorDate: Sat Jun 23 20:44:04 2018 +0530

    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 <ro...@apache.org>
---
 cli/completer.go                                   |   2 +-
 cmd/api.go                                         |   2 +-
 cmd/network.go                                     |  65 ++-
 cmd/set.go                                         |   2 +-
 cmd/sync.go                                        |   2 +-
 vendor/github.com/briandowns/spinner/LICENSE       | 174 ++++++
 .../briandowns/spinner/character_sets.go           |  59 ++
 vendor/github.com/briandowns/spinner/spinner.go    | 316 +++++++++++
 vendor/github.com/fatih/color/LICENSE.md           |  20 +
 vendor/github.com/fatih/color/color.go             | 603 +++++++++++++++++++++
 10 files changed, 1237 insertions(+), 8 deletions(-)

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 @@ func (t *autoCompleter) Do(line []rune, pos int) (options 
[][]rune, offset int)
                                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 @@ func init() {
                                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 @@ import (
        "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 @@ func Login(r *Request) (*http.Client, string, error) {
        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 @@ func NewAPIRequest(r *Request, api string, args []string) 
(map[string]interface{
        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 @@ func init() {
                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 @@ func init() {
                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...)
+}

Reply via email to