cord-776 create build / runtime containers for autmation uservices

Change-Id: I246973192adef56a250ffe93a5f65fff488840c1
diff --git a/config-generator/vendor/github.com/Sirupsen/logrus/.gitignore b/config-generator/vendor/github.com/Sirupsen/logrus/.gitignore
deleted file mode 100644
index 66be63a..0000000
--- a/config-generator/vendor/github.com/Sirupsen/logrus/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-logrus
diff --git a/config-generator/vendor/github.com/Sirupsen/logrus/.travis.yml b/config-generator/vendor/github.com/Sirupsen/logrus/.travis.yml
deleted file mode 100644
index dee4eb2..0000000
--- a/config-generator/vendor/github.com/Sirupsen/logrus/.travis.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-language: go
-go:
-  - 1.3
-  - 1.4
-  - 1.5
-  - 1.6
-  - tip
-install:
-  - go get -t ./...
-script: GOMAXPROCS=4 GORACE="halt_on_error=1" go test -race -v ./...
diff --git a/config-generator/vendor/github.com/Sirupsen/logrus/README.md b/config-generator/vendor/github.com/Sirupsen/logrus/README.md
index 6f04c8a..206c746 100644
--- a/config-generator/vendor/github.com/Sirupsen/logrus/README.md
+++ b/config-generator/vendor/github.com/Sirupsen/logrus/README.md
@@ -1,5 +1,11 @@
 # Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>&nbsp;[![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus)&nbsp;[![GoDoc](https://godoc.org/github.com/Sirupsen/logrus?status.svg)](https://godoc.org/github.com/Sirupsen/logrus)
 
+**Seeing weird case-sensitive problems?** See [this
+issue](https://github.com/sirupsen/logrus/issues/451#issuecomment-264332021).
+This change has been reverted. I apologize for causing this. I greatly
+underestimated the impact this would have. Logrus strives for stability and
+backwards compatibility and failed to provide that.
+
 Logrus is a structured logger for Go (golang), completely API compatible with
 the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
 yet stable (pre 1.0). Logrus itself is completely stable and has been used in
@@ -81,8 +87,8 @@
   // Log as JSON instead of the default ASCII formatter.
   log.SetFormatter(&log.JSONFormatter{})
 
-  // Output to stderr instead of stdout, could also be a file.
-  log.SetOutput(os.Stderr)
+  // Output to stdout instead of the default stderr, could also be a file.
+  log.SetOutput(os.Stdout)
 
   // Only log the warning severity or above.
   log.SetLevel(log.WarnLevel)
@@ -228,7 +234,14 @@
 | [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
 | [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
 | [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
+| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)|
 | [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
+| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash |
+| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) |
+| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) |
+| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) |
+| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) |
+
 
 #### Level logging
 
@@ -306,14 +319,10 @@
     field to `true`.  To force no colored output even if there is a TTY  set the
     `DisableColors` field to `true`
 * `logrus.JSONFormatter`. Logs fields as JSON.
-* `logrus/formatters/logstash.LogstashFormatter`. Logs fields as [Logstash](http://logstash.net) Events.
-
-    ```go
-      logrus.SetFormatter(&logstash.LogstashFormatter{Type: "application_name"})
-    ```
 
 Third party logging formatters:
 
+* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
 * [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
 * [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
 
@@ -369,6 +378,7 @@
 | Tool | Description |
 | ---- | ----------- |
 |[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
+|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper arround Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) |
 
 #### Testing
 
@@ -388,3 +398,36 @@
 hook.Reset()
 assert.Nil(hook.LastEntry())
 ```
+
+#### Fatal handlers
+
+Logrus can register one or more functions that will be called when any `fatal`
+level message is logged. The registered handlers will be executed before
+logrus performs a `os.Exit(1)`. This behavior may be helpful if callers need
+to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted.
+
+```
+...
+handler := func() {
+  // gracefully shutdown something...
+}
+logrus.RegisterExitHandler(handler)
+...
+```
+
+#### Thread safety
+
+By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs.
+If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
+
+Situation when locking is not needed includes:
+
+* You have no hooks registered, or hooks calling is already thread-safe.
+
+* Writing to logger.Out is already thread-safe, for example:
+
+  1) logger.Out is protected by locks.
+
+  2) logger.Out is a os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allow multi-thread/multi-process writing)
+
+     (Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/)
diff --git a/config-generator/vendor/github.com/Sirupsen/logrus/alt_exit.go b/config-generator/vendor/github.com/Sirupsen/logrus/alt_exit.go
new file mode 100644
index 0000000..b4c9e84
--- /dev/null
+++ b/config-generator/vendor/github.com/Sirupsen/logrus/alt_exit.go
@@ -0,0 +1,64 @@
+package logrus
+
+// The following code was sourced and modified from the
+// https://bitbucket.org/tebeka/atexit package governed by the following license:
+//
+// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
+//
+// 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.
+
+import (
+	"fmt"
+	"os"
+)
+
+var handlers = []func(){}
+
+func runHandler(handler func()) {
+	defer func() {
+		if err := recover(); err != nil {
+			fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err)
+		}
+	}()
+
+	handler()
+}
+
+func runHandlers() {
+	for _, handler := range handlers {
+		runHandler(handler)
+	}
+}
+
+// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code)
+func Exit(code int) {
+	runHandlers()
+	os.Exit(code)
+}
+
+// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke
+// all handlers. The handlers will also be invoked when any Fatal log entry is
+// made.
+//
+// This method is useful when a caller wishes to use logrus to log a fatal
+// message but also needs to gracefully shutdown. An example usecase could be
+// closing database connections, or sending a alert that the application is
+// closing.
+func RegisterExitHandler(handler func()) {
+	handlers = append(handlers, handler)
+}
diff --git a/config-generator/vendor/github.com/Sirupsen/logrus/entry.go b/config-generator/vendor/github.com/Sirupsen/logrus/entry.go
index 89e966e..4edbe7a 100644
--- a/config-generator/vendor/github.com/Sirupsen/logrus/entry.go
+++ b/config-generator/vendor/github.com/Sirupsen/logrus/entry.go
@@ -3,11 +3,21 @@
 import (
 	"bytes"
 	"fmt"
-	"io"
 	"os"
+	"sync"
 	"time"
 )
 
+var bufferPool *sync.Pool
+
+func init() {
+	bufferPool = &sync.Pool{
+		New: func() interface{} {
+			return new(bytes.Buffer)
+		},
+	}
+}
+
 // Defines the key when adding errors using WithError.
 var ErrorKey = "error"
 
@@ -29,6 +39,9 @@
 
 	// Message passed to Debug, Info, Warn, Error, Fatal or Panic
 	Message string
+
+	// When formatter is called in entry.log(), an Buffer may be set to entry
+	Buffer *bytes.Buffer
 }
 
 func NewEntry(logger *Logger) *Entry {
@@ -39,21 +52,15 @@
 	}
 }
 
-// Returns a reader for the entry, which is a proxy to the formatter.
-func (entry *Entry) Reader() (*bytes.Buffer, error) {
-	serialized, err := entry.Logger.Formatter.Format(entry)
-	return bytes.NewBuffer(serialized), err
-}
-
 // Returns the string representation from the reader and ultimately the
 // formatter.
 func (entry *Entry) String() (string, error) {
-	reader, err := entry.Reader()
+	serialized, err := entry.Logger.Formatter.Format(entry)
 	if err != nil {
 		return "", err
 	}
-
-	return reader.String(), err
+	str := string(serialized)
+	return str, nil
 }
 
 // Add an error as single field (using the key defined in ErrorKey) to the Entry.
@@ -81,6 +88,7 @@
 // This function is not declared with a pointer value because otherwise
 // race conditions will occur when using multiple goroutines
 func (entry Entry) log(level Level, msg string) {
+	var buffer *bytes.Buffer
 	entry.Time = time.Now()
 	entry.Level = level
 	entry.Message = msg
@@ -90,20 +98,23 @@
 		fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
 		entry.Logger.mu.Unlock()
 	}
-
-	reader, err := entry.Reader()
+	buffer = bufferPool.Get().(*bytes.Buffer)
+	buffer.Reset()
+	defer bufferPool.Put(buffer)
+	entry.Buffer = buffer
+	serialized, err := entry.Logger.Formatter.Format(&entry)
+	entry.Buffer = nil
 	if err != nil {
 		entry.Logger.mu.Lock()
 		fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
 		entry.Logger.mu.Unlock()
-	}
-
-	entry.Logger.mu.Lock()
-	defer entry.Logger.mu.Unlock()
-
-	_, err = io.Copy(entry.Logger.Out, reader)
-	if err != nil {
-		fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
+	} else {
+		entry.Logger.mu.Lock()
+		_, err = entry.Logger.Out.Write(serialized)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
+		}
+		entry.Logger.mu.Unlock()
 	}
 
 	// To avoid Entry#log() returning a value that only would make sense for
@@ -150,7 +161,7 @@
 	if entry.Logger.Level >= FatalLevel {
 		entry.log(FatalLevel, fmt.Sprint(args...))
 	}
-	os.Exit(1)
+	Exit(1)
 }
 
 func (entry *Entry) Panic(args ...interface{}) {
@@ -198,7 +209,7 @@
 	if entry.Logger.Level >= FatalLevel {
 		entry.Fatal(fmt.Sprintf(format, args...))
 	}
-	os.Exit(1)
+	Exit(1)
 }
 
 func (entry *Entry) Panicf(format string, args ...interface{}) {
@@ -245,7 +256,7 @@
 	if entry.Logger.Level >= FatalLevel {
 		entry.Fatal(entry.sprintlnn(args...))
 	}
-	os.Exit(1)
+	Exit(1)
 }
 
 func (entry *Entry) Panicln(args ...interface{}) {
diff --git a/config-generator/vendor/github.com/Sirupsen/logrus/json_formatter.go b/config-generator/vendor/github.com/Sirupsen/logrus/json_formatter.go
index 2ad6dc5..266554e 100644
--- a/config-generator/vendor/github.com/Sirupsen/logrus/json_formatter.go
+++ b/config-generator/vendor/github.com/Sirupsen/logrus/json_formatter.go
@@ -5,9 +5,40 @@
 	"fmt"
 )
 
+type fieldKey string
+type FieldMap map[fieldKey]string
+
+const (
+	FieldKeyMsg   = "msg"
+	FieldKeyLevel = "level"
+	FieldKeyTime  = "time"
+)
+
+func (f FieldMap) resolve(key fieldKey) string {
+	if k, ok := f[key]; ok {
+		return k
+	}
+
+	return string(key)
+}
+
 type JSONFormatter struct {
 	// TimestampFormat sets the format used for marshaling timestamps.
 	TimestampFormat string
+
+	// DisableTimestamp allows disabling automatic timestamps in output
+	DisableTimestamp bool
+
+	// FieldMap allows users to customize the names of keys for various fields.
+	// As an example:
+	// formatter := &JSONFormatter{
+	//   	FieldMap: FieldMap{
+	// 		 FieldKeyTime: "@timestamp",
+	// 		 FieldKeyLevel: "@level",
+	// 		 FieldKeyLevel: "@message",
+	//    },
+	// }
+	FieldMap FieldMap
 }
 
 func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
@@ -29,9 +60,11 @@
 		timestampFormat = DefaultTimestampFormat
 	}
 
-	data["time"] = entry.Time.Format(timestampFormat)
-	data["msg"] = entry.Message
-	data["level"] = entry.Level.String()
+	if !f.DisableTimestamp {
+		data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
+	}
+	data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
+	data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
 
 	serialized, err := json.Marshal(data)
 	if err != nil {
diff --git a/config-generator/vendor/github.com/Sirupsen/logrus/logger.go b/config-generator/vendor/github.com/Sirupsen/logrus/logger.go
index 2fdb231..b769f3d 100644
--- a/config-generator/vendor/github.com/Sirupsen/logrus/logger.go
+++ b/config-generator/vendor/github.com/Sirupsen/logrus/logger.go
@@ -26,8 +26,31 @@
 	// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
 	// logged. `logrus.Debug` is useful in
 	Level Level
-	// Used to sync writing to the log.
-	mu sync.Mutex
+	// Used to sync writing to the log. Locking is enabled by Default
+	mu MutexWrap
+	// Reusable empty entry
+	entryPool sync.Pool
+}
+
+type MutexWrap struct {
+	lock     sync.Mutex
+	disabled bool
+}
+
+func (mw *MutexWrap) Lock() {
+	if !mw.disabled {
+		mw.lock.Lock()
+	}
+}
+
+func (mw *MutexWrap) Unlock() {
+	if !mw.disabled {
+		mw.lock.Unlock()
+	}
+}
+
+func (mw *MutexWrap) Disable() {
+	mw.disabled = true
 }
 
 // Creates a new logger. Configuration should be set by changing `Formatter`,
@@ -51,162 +74,235 @@
 	}
 }
 
-// Adds a field to the log entry, note that you it doesn't log until you call
+func (logger *Logger) newEntry() *Entry {
+	entry, ok := logger.entryPool.Get().(*Entry)
+	if ok {
+		return entry
+	}
+	return NewEntry(logger)
+}
+
+func (logger *Logger) releaseEntry(entry *Entry) {
+	logger.entryPool.Put(entry)
+}
+
+// Adds a field to the log entry, note that it doesn't log until you call
 // Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
 // If you want multiple fields, use `WithFields`.
 func (logger *Logger) WithField(key string, value interface{}) *Entry {
-	return NewEntry(logger).WithField(key, value)
+	entry := logger.newEntry()
+	defer logger.releaseEntry(entry)
+	return entry.WithField(key, value)
 }
 
 // Adds a struct of fields to the log entry. All it does is call `WithField` for
 // each `Field`.
 func (logger *Logger) WithFields(fields Fields) *Entry {
-	return NewEntry(logger).WithFields(fields)
+	entry := logger.newEntry()
+	defer logger.releaseEntry(entry)
+	return entry.WithFields(fields)
 }
 
 // Add an error as single field to the log entry.  All it does is call
 // `WithError` for the given `error`.
 func (logger *Logger) WithError(err error) *Entry {
-	return NewEntry(logger).WithError(err)
+	entry := logger.newEntry()
+	defer logger.releaseEntry(entry)
+	return entry.WithError(err)
 }
 
 func (logger *Logger) Debugf(format string, args ...interface{}) {
 	if logger.Level >= DebugLevel {
-		NewEntry(logger).Debugf(format, args...)
+		entry := logger.newEntry()
+		entry.Debugf(format, args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Infof(format string, args ...interface{}) {
 	if logger.Level >= InfoLevel {
-		NewEntry(logger).Infof(format, args...)
+		entry := logger.newEntry()
+		entry.Infof(format, args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Printf(format string, args ...interface{}) {
-	NewEntry(logger).Printf(format, args...)
+	entry := logger.newEntry()
+	entry.Printf(format, args...)
+	logger.releaseEntry(entry)
 }
 
 func (logger *Logger) Warnf(format string, args ...interface{}) {
 	if logger.Level >= WarnLevel {
-		NewEntry(logger).Warnf(format, args...)
+		entry := logger.newEntry()
+		entry.Warnf(format, args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Warningf(format string, args ...interface{}) {
 	if logger.Level >= WarnLevel {
-		NewEntry(logger).Warnf(format, args...)
+		entry := logger.newEntry()
+		entry.Warnf(format, args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Errorf(format string, args ...interface{}) {
 	if logger.Level >= ErrorLevel {
-		NewEntry(logger).Errorf(format, args...)
+		entry := logger.newEntry()
+		entry.Errorf(format, args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Fatalf(format string, args ...interface{}) {
 	if logger.Level >= FatalLevel {
-		NewEntry(logger).Fatalf(format, args...)
+		entry := logger.newEntry()
+		entry.Fatalf(format, args...)
+		logger.releaseEntry(entry)
 	}
-	os.Exit(1)
+	Exit(1)
 }
 
 func (logger *Logger) Panicf(format string, args ...interface{}) {
 	if logger.Level >= PanicLevel {
-		NewEntry(logger).Panicf(format, args...)
+		entry := logger.newEntry()
+		entry.Panicf(format, args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Debug(args ...interface{}) {
 	if logger.Level >= DebugLevel {
-		NewEntry(logger).Debug(args...)
+		entry := logger.newEntry()
+		entry.Debug(args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Info(args ...interface{}) {
 	if logger.Level >= InfoLevel {
-		NewEntry(logger).Info(args...)
+		entry := logger.newEntry()
+		entry.Info(args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Print(args ...interface{}) {
-	NewEntry(logger).Info(args...)
+	entry := logger.newEntry()
+	entry.Info(args...)
+	logger.releaseEntry(entry)
 }
 
 func (logger *Logger) Warn(args ...interface{}) {
 	if logger.Level >= WarnLevel {
-		NewEntry(logger).Warn(args...)
+		entry := logger.newEntry()
+		entry.Warn(args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Warning(args ...interface{}) {
 	if logger.Level >= WarnLevel {
-		NewEntry(logger).Warn(args...)
+		entry := logger.newEntry()
+		entry.Warn(args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Error(args ...interface{}) {
 	if logger.Level >= ErrorLevel {
-		NewEntry(logger).Error(args...)
+		entry := logger.newEntry()
+		entry.Error(args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Fatal(args ...interface{}) {
 	if logger.Level >= FatalLevel {
-		NewEntry(logger).Fatal(args...)
+		entry := logger.newEntry()
+		entry.Fatal(args...)
+		logger.releaseEntry(entry)
 	}
-	os.Exit(1)
+	Exit(1)
 }
 
 func (logger *Logger) Panic(args ...interface{}) {
 	if logger.Level >= PanicLevel {
-		NewEntry(logger).Panic(args...)
+		entry := logger.newEntry()
+		entry.Panic(args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Debugln(args ...interface{}) {
 	if logger.Level >= DebugLevel {
-		NewEntry(logger).Debugln(args...)
+		entry := logger.newEntry()
+		entry.Debugln(args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Infoln(args ...interface{}) {
 	if logger.Level >= InfoLevel {
-		NewEntry(logger).Infoln(args...)
+		entry := logger.newEntry()
+		entry.Infoln(args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Println(args ...interface{}) {
-	NewEntry(logger).Println(args...)
+	entry := logger.newEntry()
+	entry.Println(args...)
+	logger.releaseEntry(entry)
 }
 
 func (logger *Logger) Warnln(args ...interface{}) {
 	if logger.Level >= WarnLevel {
-		NewEntry(logger).Warnln(args...)
+		entry := logger.newEntry()
+		entry.Warnln(args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Warningln(args ...interface{}) {
 	if logger.Level >= WarnLevel {
-		NewEntry(logger).Warnln(args...)
+		entry := logger.newEntry()
+		entry.Warnln(args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Errorln(args ...interface{}) {
 	if logger.Level >= ErrorLevel {
-		NewEntry(logger).Errorln(args...)
+		entry := logger.newEntry()
+		entry.Errorln(args...)
+		logger.releaseEntry(entry)
 	}
 }
 
 func (logger *Logger) Fatalln(args ...interface{}) {
 	if logger.Level >= FatalLevel {
-		NewEntry(logger).Fatalln(args...)
+		entry := logger.newEntry()
+		entry.Fatalln(args...)
+		logger.releaseEntry(entry)
 	}
-	os.Exit(1)
+	Exit(1)
 }
 
 func (logger *Logger) Panicln(args ...interface{}) {
 	if logger.Level >= PanicLevel {
-		NewEntry(logger).Panicln(args...)
+		entry := logger.newEntry()
+		entry.Panicln(args...)
+		logger.releaseEntry(entry)
 	}
 }
+
+//When file is opened with appending mode, it's safe to
+//write concurrently to a file (within 4k message on Linux).
+//In these cases user can choose to disable the lock.
+func (logger *Logger) SetNoLock() {
+	logger.mu.Disable()
+}
diff --git a/config-generator/vendor/github.com/Sirupsen/logrus/terminal_appengine.go b/config-generator/vendor/github.com/Sirupsen/logrus/terminal_appengine.go
new file mode 100644
index 0000000..1960169
--- /dev/null
+++ b/config-generator/vendor/github.com/Sirupsen/logrus/terminal_appengine.go
@@ -0,0 +1,8 @@
+// +build appengine
+
+package logrus
+
+// IsTerminal returns true if stderr's file descriptor is a terminal.
+func IsTerminal() bool {
+	return true
+}
diff --git a/config-generator/vendor/github.com/Sirupsen/logrus/terminal_bsd.go b/config-generator/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
index 71f8d67..5f6be4d 100644
--- a/config-generator/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
+++ b/config-generator/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
@@ -1,4 +1,5 @@
 // +build darwin freebsd openbsd netbsd dragonfly
+// +build !appengine
 
 package logrus
 
diff --git a/config-generator/vendor/github.com/Sirupsen/logrus/terminal_linux.go b/config-generator/vendor/github.com/Sirupsen/logrus/terminal_linux.go
index a2c0b40..308160c 100644
--- a/config-generator/vendor/github.com/Sirupsen/logrus/terminal_linux.go
+++ b/config-generator/vendor/github.com/Sirupsen/logrus/terminal_linux.go
@@ -3,6 +3,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build !appengine
+
 package logrus
 
 import "syscall"
diff --git a/config-generator/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go b/config-generator/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
index b343b3a..329038f 100644
--- a/config-generator/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
+++ b/config-generator/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
@@ -4,6 +4,7 @@
 // license that can be found in the LICENSE file.
 
 // +build linux darwin freebsd openbsd netbsd dragonfly
+// +build !appengine
 
 package logrus
 
diff --git a/config-generator/vendor/github.com/Sirupsen/logrus/terminal_solaris.go b/config-generator/vendor/github.com/Sirupsen/logrus/terminal_solaris.go
index 3e70bf7..a3c6f6e 100644
--- a/config-generator/vendor/github.com/Sirupsen/logrus/terminal_solaris.go
+++ b/config-generator/vendor/github.com/Sirupsen/logrus/terminal_solaris.go
@@ -1,4 +1,4 @@
-// +build solaris
+// +build solaris,!appengine
 
 package logrus
 
diff --git a/config-generator/vendor/github.com/Sirupsen/logrus/terminal_windows.go b/config-generator/vendor/github.com/Sirupsen/logrus/terminal_windows.go
index 0146845..3727e8a 100644
--- a/config-generator/vendor/github.com/Sirupsen/logrus/terminal_windows.go
+++ b/config-generator/vendor/github.com/Sirupsen/logrus/terminal_windows.go
@@ -3,7 +3,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build windows
+// +build windows,!appengine
 
 package logrus
 
diff --git a/config-generator/vendor/github.com/Sirupsen/logrus/text_formatter.go b/config-generator/vendor/github.com/Sirupsen/logrus/text_formatter.go
index 6afd0e0..076de5d 100644
--- a/config-generator/vendor/github.com/Sirupsen/logrus/text_formatter.go
+++ b/config-generator/vendor/github.com/Sirupsen/logrus/text_formatter.go
@@ -28,10 +28,6 @@
 	isTerminal = IsTerminal()
 }
 
-func miniTS() int {
-	return int(time.Since(baseTimestamp) / time.Second)
-}
-
 type TextFormatter struct {
 	// Set to true to bypass checking for a TTY before outputting colors.
 	ForceColors bool
@@ -57,7 +53,8 @@
 }
 
 func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
-	var keys []string = make([]string, 0, len(entry.Data))
+	var b *bytes.Buffer
+	keys := make([]string, 0, len(entry.Data))
 	for k := range entry.Data {
 		keys = append(keys, k)
 	}
@@ -65,8 +62,11 @@
 	if !f.DisableSorting {
 		sort.Strings(keys)
 	}
-
-	b := &bytes.Buffer{}
+	if entry.Buffer != nil {
+		b = entry.Buffer
+	} else {
+		b = &bytes.Buffer{}
+	}
 
 	prefixFieldClashes(entry.Data)
 
@@ -111,14 +111,17 @@
 
 	levelText := strings.ToUpper(entry.Level.String())[0:4]
 
-	if !f.FullTimestamp {
-		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
+	if f.DisableTimestamp {
+		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
+	} else if !f.FullTimestamp {
+		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message)
 	} else {
 		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
 	}
 	for _, k := range keys {
 		v := entry.Data[k]
-		fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v)
+		fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
+		f.appendValue(b, v)
 	}
 }
 
@@ -138,7 +141,11 @@
 
 	b.WriteString(key)
 	b.WriteByte('=')
+	f.appendValue(b, value)
+	b.WriteByte(' ')
+}
 
+func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
 	switch value := value.(type) {
 	case string:
 		if !needsQuoting(value) {
@@ -151,11 +158,9 @@
 		if !needsQuoting(errmsg) {
 			b.WriteString(errmsg)
 		} else {
-			fmt.Fprintf(b, "%q", value)
+			fmt.Fprintf(b, "%q", errmsg)
 		}
 	default:
 		fmt.Fprint(b, value)
 	}
-
-	b.WriteByte(' ')
 }
diff --git a/config-generator/vendor/github.com/gorilla/context/.travis.yml b/config-generator/vendor/github.com/gorilla/context/.travis.yml
deleted file mode 100644
index 24882fc..0000000
--- a/config-generator/vendor/github.com/gorilla/context/.travis.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-language: go
-sudo: false
-
-matrix:
-  include:
-    - go: 1.3
-    - go: 1.4
-    - go: 1.5
-    - go: 1.6
-    - go: tip
-  allow_failures:
-    - go: tip
-
-script:
-  - go get -t -v ./...
-  - diff -u <(echo -n) <(gofmt -d .)
-  - go vet $(go list ./... | grep -v /vendor/)
-  - go test -v -race ./...
diff --git a/config-generator/vendor/github.com/gorilla/context/LICENSE b/config-generator/vendor/github.com/gorilla/context/LICENSE
deleted file mode 100644
index 0e5fb87..0000000
--- a/config-generator/vendor/github.com/gorilla/context/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-	 * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-	 * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-	 * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/config-generator/vendor/github.com/gorilla/context/README.md b/config-generator/vendor/github.com/gorilla/context/README.md
deleted file mode 100644
index c60a31b..0000000
--- a/config-generator/vendor/github.com/gorilla/context/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-context
-=======
-[![Build Status](https://travis-ci.org/gorilla/context.png?branch=master)](https://travis-ci.org/gorilla/context)
-
-gorilla/context is a general purpose registry for global request variables.
-
-Read the full documentation here: http://www.gorillatoolkit.org/pkg/context
diff --git a/config-generator/vendor/github.com/gorilla/context/context.go b/config-generator/vendor/github.com/gorilla/context/context.go
deleted file mode 100644
index 81cb128..0000000
--- a/config-generator/vendor/github.com/gorilla/context/context.go
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package context
-
-import (
-	"net/http"
-	"sync"
-	"time"
-)
-
-var (
-	mutex sync.RWMutex
-	data  = make(map[*http.Request]map[interface{}]interface{})
-	datat = make(map[*http.Request]int64)
-)
-
-// Set stores a value for a given key in a given request.
-func Set(r *http.Request, key, val interface{}) {
-	mutex.Lock()
-	if data[r] == nil {
-		data[r] = make(map[interface{}]interface{})
-		datat[r] = time.Now().Unix()
-	}
-	data[r][key] = val
-	mutex.Unlock()
-}
-
-// Get returns a value stored for a given key in a given request.
-func Get(r *http.Request, key interface{}) interface{} {
-	mutex.RLock()
-	if ctx := data[r]; ctx != nil {
-		value := ctx[key]
-		mutex.RUnlock()
-		return value
-	}
-	mutex.RUnlock()
-	return nil
-}
-
-// GetOk returns stored value and presence state like multi-value return of map access.
-func GetOk(r *http.Request, key interface{}) (interface{}, bool) {
-	mutex.RLock()
-	if _, ok := data[r]; ok {
-		value, ok := data[r][key]
-		mutex.RUnlock()
-		return value, ok
-	}
-	mutex.RUnlock()
-	return nil, false
-}
-
-// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests.
-func GetAll(r *http.Request) map[interface{}]interface{} {
-	mutex.RLock()
-	if context, ok := data[r]; ok {
-		result := make(map[interface{}]interface{}, len(context))
-		for k, v := range context {
-			result[k] = v
-		}
-		mutex.RUnlock()
-		return result
-	}
-	mutex.RUnlock()
-	return nil
-}
-
-// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if
-// the request was registered.
-func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) {
-	mutex.RLock()
-	context, ok := data[r]
-	result := make(map[interface{}]interface{}, len(context))
-	for k, v := range context {
-		result[k] = v
-	}
-	mutex.RUnlock()
-	return result, ok
-}
-
-// Delete removes a value stored for a given key in a given request.
-func Delete(r *http.Request, key interface{}) {
-	mutex.Lock()
-	if data[r] != nil {
-		delete(data[r], key)
-	}
-	mutex.Unlock()
-}
-
-// Clear removes all values stored for a given request.
-//
-// This is usually called by a handler wrapper to clean up request
-// variables at the end of a request lifetime. See ClearHandler().
-func Clear(r *http.Request) {
-	mutex.Lock()
-	clear(r)
-	mutex.Unlock()
-}
-
-// clear is Clear without the lock.
-func clear(r *http.Request) {
-	delete(data, r)
-	delete(datat, r)
-}
-
-// Purge removes request data stored for longer than maxAge, in seconds.
-// It returns the amount of requests removed.
-//
-// If maxAge <= 0, all request data is removed.
-//
-// This is only used for sanity check: in case context cleaning was not
-// properly set some request data can be kept forever, consuming an increasing
-// amount of memory. In case this is detected, Purge() must be called
-// periodically until the problem is fixed.
-func Purge(maxAge int) int {
-	mutex.Lock()
-	count := 0
-	if maxAge <= 0 {
-		count = len(data)
-		data = make(map[*http.Request]map[interface{}]interface{})
-		datat = make(map[*http.Request]int64)
-	} else {
-		min := time.Now().Unix() - int64(maxAge)
-		for r := range data {
-			if datat[r] < min {
-				clear(r)
-				count++
-			}
-		}
-	}
-	mutex.Unlock()
-	return count
-}
-
-// ClearHandler wraps an http.Handler and clears request values at the end
-// of a request lifetime.
-func ClearHandler(h http.Handler) http.Handler {
-	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		defer Clear(r)
-		h.ServeHTTP(w, r)
-	})
-}
diff --git a/config-generator/vendor/github.com/gorilla/context/doc.go b/config-generator/vendor/github.com/gorilla/context/doc.go
deleted file mode 100644
index 73c7400..0000000
--- a/config-generator/vendor/github.com/gorilla/context/doc.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Package context stores values shared during a request lifetime.
-
-For example, a router can set variables extracted from the URL and later
-application handlers can access those values, or it can be used to store
-sessions values to be saved at the end of a request. There are several
-others common uses.
-
-The idea was posted by Brad Fitzpatrick to the go-nuts mailing list:
-
-	http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53
-
-Here's the basic usage: first define the keys that you will need. The key
-type is interface{} so a key can be of any type that supports equality.
-Here we define a key using a custom int type to avoid name collisions:
-
-	package foo
-
-	import (
-		"github.com/gorilla/context"
-	)
-
-	type key int
-
-	const MyKey key = 0
-
-Then set a variable. Variables are bound to an http.Request object, so you
-need a request instance to set a value:
-
-	context.Set(r, MyKey, "bar")
-
-The application can later access the variable using the same key you provided:
-
-	func MyHandler(w http.ResponseWriter, r *http.Request) {
-		// val is "bar".
-		val := context.Get(r, foo.MyKey)
-
-		// returns ("bar", true)
-		val, ok := context.GetOk(r, foo.MyKey)
-		// ...
-	}
-
-And that's all about the basic usage. We discuss some other ideas below.
-
-Any type can be stored in the context. To enforce a given type, make the key
-private and wrap Get() and Set() to accept and return values of a specific
-type:
-
-	type key int
-
-	const mykey key = 0
-
-	// GetMyKey returns a value for this package from the request values.
-	func GetMyKey(r *http.Request) SomeType {
-		if rv := context.Get(r, mykey); rv != nil {
-			return rv.(SomeType)
-		}
-		return nil
-	}
-
-	// SetMyKey sets a value for this package in the request values.
-	func SetMyKey(r *http.Request, val SomeType) {
-		context.Set(r, mykey, val)
-	}
-
-Variables must be cleared at the end of a request, to remove all values
-that were stored. This can be done in an http.Handler, after a request was
-served. Just call Clear() passing the request:
-
-	context.Clear(r)
-
-...or use ClearHandler(), which conveniently wraps an http.Handler to clear
-variables at the end of a request lifetime.
-
-The Routers from the packages gorilla/mux and gorilla/pat call Clear()
-so if you are using either of them you don't need to clear the context manually.
-*/
-package context
diff --git a/config-generator/vendor/github.com/gorilla/mux/.travis.yml b/config-generator/vendor/github.com/gorilla/mux/.travis.yml
deleted file mode 100644
index f4084bd..0000000
--- a/config-generator/vendor/github.com/gorilla/mux/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-language: go
-sudo: false
-
-matrix:
-  include:
-    - go: 1.2
-    - go: 1.3
-    - go: 1.4
-    - go: 1.5
-    - go: 1.6
-    - go: tip
-
-script:
-  - go get -t -v ./...
-  - diff -u <(echo -n) <(gofmt -d .)
-  - go tool vet .
-  - go test -v -race ./...
diff --git a/config-generator/vendor/github.com/gorilla/mux/README.md b/config-generator/vendor/github.com/gorilla/mux/README.md
index 960ef7c..94d396c 100644
--- a/config-generator/vendor/github.com/gorilla/mux/README.md
+++ b/config-generator/vendor/github.com/gorilla/mux/README.md
@@ -1,19 +1,44 @@
-mux
+gorilla/mux
 ===
 [![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux)
 [![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux)
 
+![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png)
+
 http://www.gorillatoolkit.org/pkg/mux
 
-Package `gorilla/mux` implements a request router and dispatcher.
+Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to
+their respective handler.
 
 The name mux stands for "HTTP request multiplexer". Like the standard `http.ServeMux`, `mux.Router` matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL or other conditions. The main features are:
 
+* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`.
 * Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers.
 * URL hosts and paths can have variables with an optional regular expression.
 * Registered URLs can be built, or "reversed", which helps maintaining references to resources.
 * Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching.
-* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`.
+
+---
+
+* [Install](#install)
+* [Examples](#examples)
+* [Matching Routes](#matching-routes)
+* [Listing Routes](#listing-routes)
+* [Static Files](#static-files)
+* [Registered URLs](#registered-urls)
+* [Full Example](#full-example)
+
+---
+
+## Install
+
+With a [correctly configured](https://golang.org/doc/install#testing) Go toolchain:
+
+```sh
+go get -u github.com/gorilla/mux
+```
+
+## Examples
 
 Let's start registering a couple of URL paths and handlers:
 
@@ -41,12 +66,17 @@
 The names are used to create a map of route variables which can be retrieved calling `mux.Vars()`:
 
 ```go
-vars := mux.Vars(request)
-category := vars["category"]
+func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) {
+	vars := mux.Vars(r)
+	w.WriteHeader(http.StatusOK)
+	fmt.Fprintf(w, "Category: %v\n", vars["category"])
+}
 ```
 
 And this is all you need to know about the basic usage. More advanced options are explained below.
 
+### Matching Routes
+
 Routes can also be restricted to a domain or subdomain. Just define a host pattern to be matched. They can also have variables:
 
 ```go
@@ -118,7 +148,7 @@
 ```go
 s.HandleFunc("/products/", ProductsHandler)
 s.HandleFunc("/products/{key}", ProductHandler)
-s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
+s.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
 ```
 
 The three URL paths we registered above will only be tested if the domain is `www.example.com`, because the subrouter is tested first. This is not only convenient, but also optimizes request matching. You can create subrouters combining any attribute matchers accepted by a route.
@@ -138,6 +168,73 @@
 s.HandleFunc("/{key}/details", ProductDetailsHandler)
 ```
 
+### Listing Routes
+
+Routes on a mux can be listed using the Router.Walk method—useful for generating documentation:
+
+```go
+package main
+
+import (
+    "fmt"
+    "net/http"
+
+    "github.com/gorilla/mux"
+)
+
+func handler(w http.ResponseWriter, r *http.Request) {
+    return
+}
+
+func main() {
+    r := mux.NewRouter()
+    r.HandleFunc("/", handler)
+    r.HandleFunc("/products", handler)
+    r.HandleFunc("/articles", handler)
+    r.HandleFunc("/articles/{id}", handler)
+    r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
+        t, err := route.GetPathTemplate()
+        if err != nil {
+            return err
+        }
+        fmt.Println(t)
+        return nil
+    })
+    http.Handle("/", r)
+}
+```
+
+### Static Files
+
+Note that the path provided to `PathPrefix()` represents a "wildcard": calling
+`PathPrefix("/static/").Handler(...)` means that the handler will be passed any
+request that matches "/static/*". This makes it easy to serve static files with mux:
+
+```go
+func main() {
+	var dir string
+
+	flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
+	flag.Parse()
+	r := mux.NewRouter()
+
+	// This will serve files under http://localhost:8000/static/<filename>
+	r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
+
+	srv := &http.Server{
+		Handler:      r,
+		Addr:         "127.0.0.1:8000",
+		// Good practice: enforce timeouts for servers you create!
+		WriteTimeout: 15 * time.Second,
+		ReadTimeout:  15 * time.Second,
+	}
+
+	log.Fatal(srv.ListenAndServe())
+}
+```
+
+### Registered URLs
+
 Now let's see how to build registered URLs.
 
 Routes can be named. All routes that define a name can have their URLs built, or "reversed". We define a name calling `Name()` on a route. For example:
diff --git a/config-generator/vendor/github.com/gorilla/mux/context_gorilla.go b/config-generator/vendor/github.com/gorilla/mux/context_gorilla.go
new file mode 100644
index 0000000..d7adaa8
--- /dev/null
+++ b/config-generator/vendor/github.com/gorilla/mux/context_gorilla.go
@@ -0,0 +1,26 @@
+// +build !go1.7
+
+package mux
+
+import (
+	"net/http"
+
+	"github.com/gorilla/context"
+)
+
+func contextGet(r *http.Request, key interface{}) interface{} {
+	return context.Get(r, key)
+}
+
+func contextSet(r *http.Request, key, val interface{}) *http.Request {
+	if val == nil {
+		return r
+	}
+
+	context.Set(r, key, val)
+	return r
+}
+
+func contextClear(r *http.Request) {
+	context.Clear(r)
+}
diff --git a/config-generator/vendor/github.com/gorilla/mux/context_native.go b/config-generator/vendor/github.com/gorilla/mux/context_native.go
new file mode 100644
index 0000000..209cbea
--- /dev/null
+++ b/config-generator/vendor/github.com/gorilla/mux/context_native.go
@@ -0,0 +1,24 @@
+// +build go1.7
+
+package mux
+
+import (
+	"context"
+	"net/http"
+)
+
+func contextGet(r *http.Request, key interface{}) interface{} {
+	return r.Context().Value(key)
+}
+
+func contextSet(r *http.Request, key, val interface{}) *http.Request {
+	if val == nil {
+		return r
+	}
+
+	return r.WithContext(context.WithValue(r.Context(), key, val))
+}
+
+func contextClear(r *http.Request) {
+	return
+}
diff --git a/config-generator/vendor/github.com/gorilla/mux/doc.go b/config-generator/vendor/github.com/gorilla/mux/doc.go
index 835f534..00daf4a 100644
--- a/config-generator/vendor/github.com/gorilla/mux/doc.go
+++ b/config-generator/vendor/github.com/gorilla/mux/doc.go
@@ -47,12 +47,21 @@
 	r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
 	r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
 
+Groups can be used inside patterns, as long as they are non-capturing (?:re). For example:
+
+	r.HandleFunc("/articles/{category}/{sort:(?:asc|desc|new)}", ArticlesCategoryHandler)
+
 The names are used to create a map of route variables which can be retrieved
 calling mux.Vars():
 
 	vars := mux.Vars(request)
 	category := vars["category"]
 
+Note that if any capturing groups are present, mux will panic() during parsing. To prevent
+this, convert any capturing groups to non-capturing, e.g. change "/{sort:(asc|desc)}" to
+"/{sort:(?:asc|desc)}". This is a change from prior versions which behaved unpredictably
+when capturing groups were present.
+
 And this is all you need to know about the basic usage. More advanced options
 are explained below.
 
@@ -136,6 +145,31 @@
 	// "/products/{key}/details"
 	s.HandleFunc("/{key}/details", ProductDetailsHandler)
 
+Note that the path provided to PathPrefix() represents a "wildcard": calling
+PathPrefix("/static/").Handler(...) means that the handler will be passed any
+request that matches "/static/*". This makes it easy to serve static files with mux:
+
+	func main() {
+		var dir string
+
+		flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
+		flag.Parse()
+		r := mux.NewRouter()
+
+		// This will serve files under http://localhost:8000/static/<filename>
+		r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
+
+		srv := &http.Server{
+			Handler:      r,
+			Addr:         "127.0.0.1:8000",
+			// Good practice: enforce timeouts for servers you create!
+			WriteTimeout: 15 * time.Second,
+			ReadTimeout:  15 * time.Second,
+		}
+
+		log.Fatal(srv.ListenAndServe())
+	}
+
 Now let's see how to build registered URLs.
 
 Routes can be named. All routes that define a name can have their URLs built,
diff --git a/config-generator/vendor/github.com/gorilla/mux/mux.go b/config-generator/vendor/github.com/gorilla/mux/mux.go
index 94f5ddd..d66ec38 100644
--- a/config-generator/vendor/github.com/gorilla/mux/mux.go
+++ b/config-generator/vendor/github.com/gorilla/mux/mux.go
@@ -10,8 +10,7 @@
 	"net/http"
 	"path"
 	"regexp"
-
-	"github.com/gorilla/context"
+	"strings"
 )
 
 // NewRouter returns a new router instance.
@@ -50,8 +49,12 @@
 	strictSlash bool
 	// See Router.SkipClean(). This defines the flag for new routes.
 	skipClean bool
-	// If true, do not clear the request context after handling the request
+	// If true, do not clear the request context after handling the request.
+	// This has no effect when go1.7+ is used, since the context is stored
+	// on the request itself.
 	KeepContext bool
+	// see Router.UseEncodedPath(). This defines a flag for all routes.
+	useEncodedPath bool
 }
 
 // Match matches registered routes against the request.
@@ -76,8 +79,12 @@
 // mux.Vars(request).
 func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 	if !r.skipClean {
+		path := req.URL.Path
+		if r.useEncodedPath {
+			path = getPath(req)
+		}
 		// Clean path to canonical form and redirect.
-		if p := cleanPath(req.URL.Path); p != req.URL.Path {
+		if p := cleanPath(path); p != path {
 
 			// Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.
 			// This matches with fix in go 1.2 r.c. 4 for same problem.  Go Issue:
@@ -95,14 +102,14 @@
 	var handler http.Handler
 	if r.Match(req, &match) {
 		handler = match.Handler
-		setVars(req, match.Vars)
-		setCurrentRoute(req, match.Route)
+		req = setVars(req, match.Vars)
+		req = setCurrentRoute(req, match.Route)
 	}
 	if handler == nil {
 		handler = http.NotFoundHandler()
 	}
 	if !r.KeepContext {
-		defer context.Clear(req)
+		defer contextClear(req)
 	}
 	handler.ServeHTTP(w, req)
 }
@@ -150,6 +157,21 @@
 	return r
 }
 
+// UseEncodedPath tells the router to match the encoded original path
+// to the routes.
+// For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to".
+// This behavior has the drawback of needing to match routes against
+// r.RequestURI instead of r.URL.Path. Any modifications (such as http.StripPrefix)
+// to r.URL.Path will not affect routing when this flag is on and thus may
+// induce unintended behavior.
+//
+// If not called, the router will match the unencoded path to the routes.
+// For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to"
+func (r *Router) UseEncodedPath() *Router {
+	r.useEncodedPath = true
+	return r
+}
+
 // ----------------------------------------------------------------------------
 // parentRoute
 // ----------------------------------------------------------------------------
@@ -187,7 +209,7 @@
 
 // NewRoute registers an empty route.
 func (r *Router) NewRoute() *Route {
-	route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean}
+	route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean, useEncodedPath: r.useEncodedPath}
 	r.routes = append(r.routes, route)
 	return route
 }
@@ -285,6 +307,9 @@
 		if err == SkipRouter {
 			continue
 		}
+		if err != nil {
+			return err
+		}
 		for _, sr := range t.matchers {
 			if h, ok := sr.(*Router); ok {
 				err := h.walk(walkFn, ancestors)
@@ -325,7 +350,7 @@
 
 // Vars returns the route variables for the current request, if any.
 func Vars(r *http.Request) map[string]string {
-	if rv := context.Get(r, varsKey); rv != nil {
+	if rv := contextGet(r, varsKey); rv != nil {
 		return rv.(map[string]string)
 	}
 	return nil
@@ -337,28 +362,46 @@
 // after the handler returns, unless the KeepContext option is set on the
 // Router.
 func CurrentRoute(r *http.Request) *Route {
-	if rv := context.Get(r, routeKey); rv != nil {
+	if rv := contextGet(r, routeKey); rv != nil {
 		return rv.(*Route)
 	}
 	return nil
 }
 
-func setVars(r *http.Request, val interface{}) {
-	if val != nil {
-		context.Set(r, varsKey, val)
-	}
+func setVars(r *http.Request, val interface{}) *http.Request {
+	return contextSet(r, varsKey, val)
 }
 
-func setCurrentRoute(r *http.Request, val interface{}) {
-	if val != nil {
-		context.Set(r, routeKey, val)
-	}
+func setCurrentRoute(r *http.Request, val interface{}) *http.Request {
+	return contextSet(r, routeKey, val)
 }
 
 // ----------------------------------------------------------------------------
 // Helpers
 // ----------------------------------------------------------------------------
 
+// getPath returns the escaped path if possible; doing what URL.EscapedPath()
+// which was added in go1.5 does
+func getPath(req *http.Request) string {
+	if req.RequestURI != "" {
+		// Extract the path from RequestURI (which is escaped unlike URL.Path)
+		// as detailed here as detailed in https://golang.org/pkg/net/url/#URL
+		// for < 1.5 server side workaround
+		// http://localhost/path/here?v=1 -> /path/here
+		path := req.RequestURI
+		path = strings.TrimPrefix(path, req.URL.Scheme+`://`)
+		path = strings.TrimPrefix(path, req.URL.Host)
+		if i := strings.LastIndex(path, "?"); i > -1 {
+			path = path[:i]
+		}
+		if i := strings.LastIndex(path, "#"); i > -1 {
+			path = path[:i]
+		}
+		return path
+	}
+	return req.URL.Path
+}
+
 // cleanPath returns the canonical path for p, eliminating . and .. elements.
 // Borrowed from the net/http package.
 func cleanPath(p string) string {
diff --git a/config-generator/vendor/github.com/gorilla/mux/regexp.go b/config-generator/vendor/github.com/gorilla/mux/regexp.go
index 08710bc..0189ad3 100644
--- a/config-generator/vendor/github.com/gorilla/mux/regexp.go
+++ b/config-generator/vendor/github.com/gorilla/mux/regexp.go
@@ -24,7 +24,7 @@
 // Previously we accepted only Python-like identifiers for variable
 // names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that
 // name and pattern can't be empty, and names can't contain a colon.
-func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash bool) (*routeRegexp, error) {
+func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash, useEncodedPath bool) (*routeRegexp, error) {
 	// Check if it is well-formed.
 	idxs, errBraces := braceIndices(tpl)
 	if errBraces != nil {
@@ -109,16 +109,24 @@
 	if errCompile != nil {
 		return nil, errCompile
 	}
+
+	// Check for capturing groups which used to work in older versions
+	if reg.NumSubexp() != len(idxs)/2 {
+		panic(fmt.Sprintf("route %s contains capture groups in its regexp. ", template) +
+			"Only non-capturing groups are accepted: e.g. (?:pattern) instead of (pattern)")
+	}
+
 	// Done!
 	return &routeRegexp{
-		template:    template,
-		matchHost:   matchHost,
-		matchQuery:  matchQuery,
-		strictSlash: strictSlash,
-		regexp:      reg,
-		reverse:     reverse.String(),
-		varsN:       varsN,
-		varsR:       varsR,
+		template:       template,
+		matchHost:      matchHost,
+		matchQuery:     matchQuery,
+		strictSlash:    strictSlash,
+		useEncodedPath: useEncodedPath,
+		regexp:         reg,
+		reverse:        reverse.String(),
+		varsN:          varsN,
+		varsR:          varsR,
 	}, nil
 }
 
@@ -133,6 +141,9 @@
 	matchQuery bool
 	// The strictSlash value defined on the route, but disabled if PathPrefix was used.
 	strictSlash bool
+	// Determines whether to use encoded path from getPath function or unencoded
+	// req.URL.Path for path matching
+	useEncodedPath bool
 	// Expanded regexp.
 	regexp *regexp.Regexp
 	// Reverse template.
@@ -149,8 +160,11 @@
 		if r.matchQuery {
 			return r.matchQueryString(req)
 		}
-
-		return r.regexp.MatchString(req.URL.Path)
+		path := req.URL.Path
+		if r.useEncodedPath {
+			path = getPath(req)
+		}
+		return r.regexp.MatchString(path)
 	}
 
 	return r.regexp.MatchString(getHost(req))
@@ -253,14 +267,18 @@
 			extractVars(host, matches, v.host.varsN, m.Vars)
 		}
 	}
+	path := req.URL.Path
+	if r.useEncodedPath {
+		path = getPath(req)
+	}
 	// Store path variables.
 	if v.path != nil {
-		matches := v.path.regexp.FindStringSubmatchIndex(req.URL.Path)
+		matches := v.path.regexp.FindStringSubmatchIndex(path)
 		if len(matches) > 0 {
-			extractVars(req.URL.Path, matches, v.path.varsN, m.Vars)
+			extractVars(path, matches, v.path.varsN, m.Vars)
 			// Check if we should redirect.
 			if v.path.strictSlash {
-				p1 := strings.HasSuffix(req.URL.Path, "/")
+				p1 := strings.HasSuffix(path, "/")
 				p2 := strings.HasSuffix(v.path.template, "/")
 				if p1 != p2 {
 					u, _ := url.Parse(req.URL.String())
@@ -299,14 +317,7 @@
 }
 
 func extractVars(input string, matches []int, names []string, output map[string]string) {
-	matchesCount := 0
-	prevEnd := -1
-	for i := 2; i < len(matches) && matchesCount < len(names); i += 2 {
-		if prevEnd < matches[i+1] {
-			value := input[matches[i]:matches[i+1]]
-			output[names[matchesCount]] = value
-			prevEnd = matches[i+1]
-			matchesCount++
-		}
+	for i, name := range names {
+		output[name] = input[matches[2*i+2]:matches[2*i+3]]
 	}
 }
diff --git a/config-generator/vendor/github.com/gorilla/mux/route.go b/config-generator/vendor/github.com/gorilla/mux/route.go
index 6c53f9f..9221915 100644
--- a/config-generator/vendor/github.com/gorilla/mux/route.go
+++ b/config-generator/vendor/github.com/gorilla/mux/route.go
@@ -29,6 +29,8 @@
 	// If true, when the path pattern is "/path//to", accessing "/path//to"
 	// will not redirect
 	skipClean bool
+	// If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to"
+	useEncodedPath bool
 	// If true, this route never matches: it is only used to build URLs.
 	buildOnly bool
 	// The name used to build URLs.
@@ -151,14 +153,14 @@
 	}
 	r.regexp = r.getRegexpGroup()
 	if !matchHost && !matchQuery {
-		if len(tpl) == 0 || tpl[0] != '/' {
+		if tpl == "/" && (len(tpl) == 0 || tpl[0] != '/') {
 			return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
 		}
 		if r.regexp.path != nil {
 			tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl
 		}
 	}
-	rr, err := newRouteRegexp(tpl, matchHost, matchPrefix, matchQuery, r.strictSlash)
+	rr, err := newRouteRegexp(tpl, matchHost, matchPrefix, matchQuery, r.strictSlash, r.useEncodedPath)
 	if err != nil {
 		return err
 	}
diff --git a/config-generator/vendor/github.com/kelseyhightower/envconfig/.travis.yml b/config-generator/vendor/github.com/kelseyhightower/envconfig/.travis.yml
deleted file mode 100644
index e15301a..0000000
--- a/config-generator/vendor/github.com/kelseyhightower/envconfig/.travis.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-language: go
-
-go:
-  - 1.4
-  - 1.5
-  - 1.6
-  - tip
diff --git a/config-generator/vendor/github.com/kelseyhightower/envconfig/README.md b/config-generator/vendor/github.com/kelseyhightower/envconfig/README.md
index dd516a2..09de74b 100644
--- a/config-generator/vendor/github.com/kelseyhightower/envconfig/README.md
+++ b/config-generator/vendor/github.com/kelseyhightower/envconfig/README.md
@@ -87,20 +87,30 @@
 
 ```Go
 type Specification struct {
-    MultiWordVar string `envconfig:"multi_word_var"`
-    DefaultVar   string `default:"foobar"`
-    RequiredVar  string `required:"true"`
-    IgnoredVar   string `ignored:"true"`
+    ManualOverride1 string `envconfig:"manual_override_1"`
+    DefaultVar      string `default:"foobar"`
+    RequiredVar     string `required:"true"`
+    IgnoredVar      string `ignored:"true"`
+    AutoSplitVar    string `split_words:"true"`
 }
 ```
 
-Envconfig will process value for `MultiWordVar` by populating it with the
-value for `MYAPP_MULTI_WORD_VAR`.
+Envconfig has automatic support for CamelCased struct elements when the
+`split_words:"true"` tag is supplied. Without this tag, `AutoSplitVar` above
+would look for an environment variable called `MYAPP_AUTOSPLITVAR`. With the
+setting applied it will look for `MYAPP_AUTO_SPLIT_VAR`. Note that numbers
+will get globbed into the previous word. If the setting does not do the
+right thing, you may use a manual override.
+
+Envconfig will process value for `ManualOverride1` by populating it with the
+value for `MYAPP_MANUAL_OVERRIDE_1`. Without this struct tag, it would have
+instead looked up `MYAPP_MANUALOVERRIDE1`. With the `split_words:"true"` tag
+it would have looked up `MYAPP_MANUAL_OVERRIDE1`.
 
 ```Bash
-export MYAPP_MULTI_WORD_VAR="this will be the value"
+export MYAPP_MANUAL_OVERRIDE_1="this will be the value"
 
-# export MYAPP_MULTIWORDVAR="and this will not"
+# export MYAPP_MANUALOVERRIDE1="and this will not"
 ```
 
 If envconfig can't find an environment variable value for `MYAPP_DEFAULTVAR`,
@@ -135,6 +145,7 @@
   * int8, int16, int32, int64
   * bool
   * float32, float64
+  * [encoding.TextUnmarshaler](https://golang.org/pkg/encoding/#TextUnmarshaler)
 
 Embedded structs using these fields are also supported.
 
@@ -159,3 +170,6 @@
     Address IPDecoder `envconfig:"DNS_SERVER"`
 }
 ```
+
+Also, envconfig will use a `Set(string) error` method like from the
+[flag.Value](https://godoc.org/flag#Value) interface if implemented.
diff --git a/config-generator/vendor/github.com/kelseyhightower/envconfig/env_os.go b/config-generator/vendor/github.com/kelseyhightower/envconfig/env_os.go
new file mode 100644
index 0000000..a6a014a
--- /dev/null
+++ b/config-generator/vendor/github.com/kelseyhightower/envconfig/env_os.go
@@ -0,0 +1,7 @@
+// +build appengine
+
+package envconfig
+
+import "os"
+
+var lookupEnv = os.LookupEnv
diff --git a/config-generator/vendor/github.com/kelseyhightower/envconfig/env_syscall.go b/config-generator/vendor/github.com/kelseyhightower/envconfig/env_syscall.go
new file mode 100644
index 0000000..9d98085
--- /dev/null
+++ b/config-generator/vendor/github.com/kelseyhightower/envconfig/env_syscall.go
@@ -0,0 +1,7 @@
+// +build !appengine
+
+package envconfig
+
+import "syscall"
+
+var lookupEnv = syscall.Getenv
diff --git a/config-generator/vendor/github.com/kelseyhightower/envconfig/envconfig.go b/config-generator/vendor/github.com/kelseyhightower/envconfig/envconfig.go
index 1daf389..3ad5e7d 100644
--- a/config-generator/vendor/github.com/kelseyhightower/envconfig/envconfig.go
+++ b/config-generator/vendor/github.com/kelseyhightower/envconfig/envconfig.go
@@ -5,12 +5,13 @@
 package envconfig
 
 import (
+	"encoding"
 	"errors"
 	"fmt"
 	"reflect"
+	"regexp"
 	"strconv"
 	"strings"
-	"syscall"
 	"time"
 )
 
@@ -24,83 +25,164 @@
 	FieldName string
 	TypeName  string
 	Value     string
+	Err       error
 }
 
-// A Decoder is a type that knows how to de-serialize environment variables
-// into itself.
+// Decoder has the same semantics as Setter, but takes higher precedence.
+// It is provided for historical compatibility.
 type Decoder interface {
 	Decode(value string) error
 }
 
+// Setter is implemented by types can self-deserialize values.
+// Any type that implements flag.Value also implements Setter.
+type Setter interface {
+	Set(value string) error
+}
+
 func (e *ParseError) Error() string {
-	return fmt.Sprintf("envconfig.Process: assigning %[1]s to %[2]s: converting '%[3]s' to type %[4]s", e.KeyName, e.FieldName, e.Value, e.TypeName)
+	return fmt.Sprintf("envconfig.Process: assigning %[1]s to %[2]s: converting '%[3]s' to type %[4]s. details: %[5]s", e.KeyName, e.FieldName, e.Value, e.TypeName, e.Err)
+}
+
+// varInfo maintains information about the configuration variable
+type varInfo struct {
+	Name  string
+	Alt   string
+	Key   string
+	Field reflect.Value
+	Tags  reflect.StructTag
+}
+
+// GatherInfo gathers information about the specified struct
+func gatherInfo(prefix string, spec interface{}) ([]varInfo, error) {
+	expr := regexp.MustCompile("([^A-Z]+|[A-Z][^A-Z]+|[A-Z]+)")
+	s := reflect.ValueOf(spec)
+
+	if s.Kind() != reflect.Ptr {
+		return nil, ErrInvalidSpecification
+	}
+	s = s.Elem()
+	if s.Kind() != reflect.Struct {
+		return nil, ErrInvalidSpecification
+	}
+	typeOfSpec := s.Type()
+
+	// over allocate an info array, we will extend if needed later
+	infos := make([]varInfo, 0, s.NumField())
+	for i := 0; i < s.NumField(); i++ {
+		f := s.Field(i)
+		ftype := typeOfSpec.Field(i)
+		if !f.CanSet() || ftype.Tag.Get("ignored") == "true" {
+			continue
+		}
+
+		for f.Kind() == reflect.Ptr {
+			if f.IsNil() {
+				if f.Type().Elem().Kind() != reflect.Struct {
+					// nil pointer to a non-struct: leave it alone
+					break
+				}
+				// nil pointer to struct: create a zero instance
+				f.Set(reflect.New(f.Type().Elem()))
+			}
+			f = f.Elem()
+		}
+
+		// Capture information about the config variable
+		info := varInfo{
+			Name:  ftype.Name,
+			Field: f,
+			Tags:  ftype.Tag,
+			Alt:   strings.ToUpper(ftype.Tag.Get("envconfig")),
+		}
+
+		// Default to the field name as the env var name (will be upcased)
+		info.Key = info.Name
+
+		// Best effort to un-pick camel casing as separate words
+		if ftype.Tag.Get("split_words") == "true" {
+			words := expr.FindAllStringSubmatch(ftype.Name, -1)
+			if len(words) > 0 {
+				var name []string
+				for _, words := range words {
+					name = append(name, words[0])
+				}
+
+				info.Key = strings.Join(name, "_")
+			}
+		}
+		if info.Alt != "" {
+			info.Key = info.Alt
+		}
+		if prefix != "" {
+			info.Key = fmt.Sprintf("%s_%s", prefix, info.Key)
+		}
+		info.Key = strings.ToUpper(info.Key)
+		infos = append(infos, info)
+
+		if f.Kind() == reflect.Struct {
+			// honor Decode if present
+			if decoderFrom(f) == nil && setterFrom(f) == nil && textUnmarshaler(f) == nil {
+				innerPrefix := prefix
+				if !ftype.Anonymous {
+					innerPrefix = info.Key
+				}
+
+				embeddedPtr := f.Addr().Interface()
+				embeddedInfos, err := gatherInfo(innerPrefix, embeddedPtr)
+				if err != nil {
+					return nil, err
+				}
+				infos = append(infos[:len(infos)-1], embeddedInfos...)
+
+				continue
+			}
+		}
+	}
+	return infos, nil
 }
 
 // Process populates the specified struct based on environment variables
 func Process(prefix string, spec interface{}) error {
-	s := reflect.ValueOf(spec)
+	infos, err := gatherInfo(prefix, spec)
 
-	if s.Kind() != reflect.Ptr {
-		return ErrInvalidSpecification
-	}
-	s = s.Elem()
-	if s.Kind() != reflect.Struct {
-		return ErrInvalidSpecification
-	}
-	typeOfSpec := s.Type()
-	for i := 0; i < s.NumField(); i++ {
-		f := s.Field(i)
-		if !f.CanSet() || typeOfSpec.Field(i).Tag.Get("ignored") == "true" {
-			continue
-		}
+	for _, info := range infos {
 
-		if typeOfSpec.Field(i).Anonymous && f.Kind() == reflect.Struct {
-			embeddedPtr := f.Addr().Interface()
-			if err := Process(prefix, embeddedPtr); err != nil {
-				return err
-			}
-			f.Set(reflect.ValueOf(embeddedPtr).Elem())
-		}
-
-		alt := typeOfSpec.Field(i).Tag.Get("envconfig")
-		fieldName := typeOfSpec.Field(i).Name
-		if alt != "" {
-			fieldName = alt
-		}
-		key := strings.ToUpper(fmt.Sprintf("%s_%s", prefix, fieldName))
 		// `os.Getenv` cannot differentiate between an explicitly set empty value
 		// and an unset value. `os.LookupEnv` is preferred to `syscall.Getenv`,
-		// but it is only available in go1.5 or newer.
-		value, ok := syscall.Getenv(key)
-		if !ok && alt != "" {
-			key := strings.ToUpper(fieldName)
-			value, ok = syscall.Getenv(key)
+		// but it is only available in go1.5 or newer. We're using Go build tags
+		// here to use os.LookupEnv for >=go1.5
+		value, ok := lookupEnv(info.Key)
+		if !ok && info.Alt != "" {
+			value, ok = lookupEnv(info.Alt)
 		}
 
-		def := typeOfSpec.Field(i).Tag.Get("default")
+		def := info.Tags.Get("default")
 		if def != "" && !ok {
 			value = def
 		}
 
-		req := typeOfSpec.Field(i).Tag.Get("required")
+		req := info.Tags.Get("required")
 		if !ok && def == "" {
 			if req == "true" {
-				return fmt.Errorf("required key %s missing value", key)
+				return fmt.Errorf("required key %s missing value", info.Key)
 			}
 			continue
 		}
 
-		err := processField(value, f)
+		err := processField(value, info.Field)
 		if err != nil {
 			return &ParseError{
-				KeyName:   key,
-				FieldName: fieldName,
-				TypeName:  f.Type().String(),
+				KeyName:   info.Key,
+				FieldName: info.Name,
+				TypeName:  info.Field.Type().String(),
 				Value:     value,
+				Err:       err,
 			}
 		}
 	}
-	return nil
+
+	return err
 }
 
 // MustProcess is the same as Process but panics if an error occurs
@@ -117,6 +199,15 @@
 	if decoder != nil {
 		return decoder.Decode(value)
 	}
+	// look for Set method if Decode not defined
+	setter := setterFrom(field)
+	if setter != nil {
+		return setter.Set(value)
+	}
+
+	if t := textUnmarshaler(field); t != nil {
+		return t.UnmarshalText([]byte(value))
+	}
 
 	if typ.Kind() == reflect.Ptr {
 		typ = typ.Elem()
@@ -179,23 +270,29 @@
 	return nil
 }
 
-func decoderFrom(field reflect.Value) Decoder {
-	if field.CanInterface() {
-		dec, ok := field.Interface().(Decoder)
-		if ok {
-			return dec
-		}
+func interfaceFrom(field reflect.Value, fn func(interface{}, *bool)) {
+	// it may be impossible for a struct field to fail this check
+	if !field.CanInterface() {
+		return
 	}
-
-	// also check if pointer-to-type implements Decoder,
-	// and we can get a pointer to our field
-	if field.CanAddr() {
-		field = field.Addr()
-		dec, ok := field.Interface().(Decoder)
-		if ok {
-			return dec
-		}
+	var ok bool
+	fn(field.Interface(), &ok)
+	if !ok && field.CanAddr() {
+		fn(field.Addr().Interface(), &ok)
 	}
+}
 
-	return nil
+func decoderFrom(field reflect.Value) (d Decoder) {
+	interfaceFrom(field, func(v interface{}, ok *bool) { d, *ok = v.(Decoder) })
+	return d
+}
+
+func setterFrom(field reflect.Value) (s Setter) {
+	interfaceFrom(field, func(v interface{}, ok *bool) { s, *ok = v.(Setter) })
+	return s
+}
+
+func textUnmarshaler(field reflect.Value) (t encoding.TextUnmarshaler) {
+	interfaceFrom(field, func(v interface{}, ok *bool) { t, *ok = v.(encoding.TextUnmarshaler) })
+	return t
 }
diff --git a/config-generator/vendor/github.com/kelseyhightower/envconfig/usage.go b/config-generator/vendor/github.com/kelseyhightower/envconfig/usage.go
new file mode 100644
index 0000000..4870237
--- /dev/null
+++ b/config-generator/vendor/github.com/kelseyhightower/envconfig/usage.go
@@ -0,0 +1,152 @@
+// Copyright (c) 2016 Kelsey Hightower and others. All rights reserved.
+// Use of this source code is governed by the MIT License that can be found in
+// the LICENSE file.
+
+package envconfig
+
+import (
+	"encoding"
+	"fmt"
+	"io"
+	"os"
+	"reflect"
+	"strconv"
+	"strings"
+	"text/tabwriter"
+	"text/template"
+)
+
+const (
+	// DefaultListFormat constant to use to display usage in a list format
+	DefaultListFormat = `This application is configured via the environment. The following environment
+variables can be used:
+{{range .}}
+{{usage_key .}}
+  [description] {{usage_description .}}
+  [type]        {{usage_type .}}
+  [default]     {{usage_default .}}
+  [required]    {{usage_required .}}{{end}}
+`
+	// DefaultTableFormat constant to use to display usage in a tabluar format
+	DefaultTableFormat = `This application is configured via the environment. The following environment
+variables can be used:
+
+KEY	TYPE	DEFAULT	REQUIRED	DESCRIPTION
+{{range .}}{{usage_key .}}	{{usage_type .}}	{{usage_default .}}	{{usage_required .}}	{{usage_description .}}
+{{end}}`
+)
+
+var (
+	decoderType     = reflect.TypeOf((*Decoder)(nil)).Elem()
+	setterType      = reflect.TypeOf((*Setter)(nil)).Elem()
+	unmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
+)
+
+func implementsInterface(t reflect.Type) bool {
+	return t.Implements(decoderType) ||
+		reflect.PtrTo(t).Implements(decoderType) ||
+		t.Implements(setterType) ||
+		reflect.PtrTo(t).Implements(setterType) ||
+		t.Implements(unmarshalerType) ||
+		reflect.PtrTo(t).Implements(unmarshalerType)
+}
+
+// toTypeDescription converts Go types into a human readable description
+func toTypeDescription(t reflect.Type) string {
+	switch t.Kind() {
+	case reflect.Array, reflect.Slice:
+		return fmt.Sprintf("Comma-separated list of %s", toTypeDescription(t.Elem()))
+	case reflect.Ptr:
+		return toTypeDescription(t.Elem())
+	case reflect.Struct:
+		if implementsInterface(t) && t.Name() != "" {
+			return t.Name()
+		}
+		return ""
+	case reflect.String:
+		name := t.Name()
+		if name != "" && name != "string" {
+			return name
+		}
+		return "String"
+	case reflect.Bool:
+		name := t.Name()
+		if name != "" && name != "bool" {
+			return name
+		}
+		return "True or False"
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		name := t.Name()
+		if name != "" && !strings.HasPrefix(name, "int") {
+			return name
+		}
+		return "Integer"
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		name := t.Name()
+		if name != "" && !strings.HasPrefix(name, "uint") {
+			return name
+		}
+		return "Unsigned Integer"
+	case reflect.Float32, reflect.Float64:
+		name := t.Name()
+		if name != "" && !strings.HasPrefix(name, "float") {
+			return name
+		}
+		return "Float"
+	}
+	return fmt.Sprintf("%+v", t)
+}
+
+// Usage writes usage information to stderr using the default header and table format
+func Usage(prefix string, spec interface{}) error {
+	// The default is to output the usage information as a table
+	// Create tabwriter instance to support table output
+	tabs := tabwriter.NewWriter(os.Stdout, 1, 0, 4, ' ', 0)
+
+	err := Usagef(prefix, spec, tabs, DefaultTableFormat)
+	tabs.Flush()
+	return err
+}
+
+// Usagef writes usage information to the specified io.Writer using the specifed template specification
+func Usagef(prefix string, spec interface{}, out io.Writer, format string) error {
+
+	// Specify the default usage template functions
+	functions := template.FuncMap{
+		"usage_key":         func(v varInfo) string { return v.Key },
+		"usage_description": func(v varInfo) string { return v.Tags.Get("desc") },
+		"usage_type":        func(v varInfo) string { return toTypeDescription(v.Field.Type()) },
+		"usage_default":     func(v varInfo) string { return v.Tags.Get("default") },
+		"usage_required": func(v varInfo) (string, error) {
+			req := v.Tags.Get("required")
+			if req != "" {
+				reqB, err := strconv.ParseBool(req)
+				if err != nil {
+					return "", err
+				}
+				if reqB {
+					req = "true"
+				}
+			}
+			return req, nil
+		},
+	}
+
+	tmpl, err := template.New("envconfig").Funcs(functions).Parse(format)
+	if err != nil {
+		return err
+	}
+
+	return Usaget(prefix, spec, out, tmpl)
+}
+
+// Usaget writes usage information to the specified io.Writer using the specified template
+func Usaget(prefix string, spec interface{}, out io.Writer, tmpl *template.Template) error {
+	// gather first
+	infos, err := gatherInfo(prefix, spec)
+	if err != nil {
+		return err
+	}
+
+	return tmpl.Execute(out, infos)
+}
diff --git a/config-generator/vendor/vendor.json b/config-generator/vendor/vendor.json
new file mode 100644
index 0000000..c09c103
--- /dev/null
+++ b/config-generator/vendor/vendor.json
@@ -0,0 +1,25 @@
+{
+	"comment": "",
+	"ignore": "test",
+	"package": [
+		{
+			"checksumSHA1": "dGXnnR7ZhsrZNnEqFimk6q7YCqs=",
+			"path": "github.com/Sirupsen/logrus",
+			"revision": "61e43dc76f7ee59a82bdf3d71033dc12bea4c77d",
+			"revisionTime": "2017-01-13T01:19:11Z"
+		},
+		{
+			"checksumSHA1": "F5dR3/i70EhSIMZfeIV+H8/PtvM=",
+			"path": "github.com/gorilla/mux",
+			"revision": "392c28fe23e1c45ddba891b0320b3b5df220beea",
+			"revisionTime": "2017-01-18T13:43:44Z"
+		},
+		{
+			"checksumSHA1": "pNria08/hqW7nnWb0erRBMdJU3M=",
+			"path": "github.com/kelseyhightower/envconfig",
+			"revision": "4069f29f08928c54bcb1fdf632b31b1bb54b4fdb",
+			"revisionTime": "2017-01-13T19:16:37Z"
+		}
+	],
+	"rootPath": "gerrit.opencord.org/maas/config-generator"
+}