vendorify
diff --git a/go/vendor/github.com/StackExchange/wmi/swbemservices.go b/go/vendor/github.com/StackExchange/wmi/swbemservices.go
new file mode 100644
index 0000000..9765a53
--- /dev/null
+++ b/go/vendor/github.com/StackExchange/wmi/swbemservices.go
@@ -0,0 +1,260 @@
+// +build windows
+
+package wmi
+
+import (
+	"fmt"
+	"reflect"
+	"runtime"
+	"sync"
+
+	"github.com/go-ole/go-ole"
+	"github.com/go-ole/go-ole/oleutil"
+)
+
+// SWbemServices is used to access wmi. See https://msdn.microsoft.com/en-us/library/aa393719(v=vs.85).aspx
+type SWbemServices struct {
+	//TODO: track namespace. Not sure if we can re connect to a different namespace using the same instance
+	cWMIClient            *Client //This could also be an embedded struct, but then we would need to branch on Client vs SWbemServices in the Query method
+	sWbemLocatorIUnknown  *ole.IUnknown
+	sWbemLocatorIDispatch *ole.IDispatch
+	queries               chan *queryRequest
+	closeError            chan error
+	lQueryorClose         sync.Mutex
+}
+
+type queryRequest struct {
+	query    string
+	dst      interface{}
+	args     []interface{}
+	finished chan error
+}
+
+// InitializeSWbemServices will return a new SWbemServices object that can be used to query WMI
+func InitializeSWbemServices(c *Client, connectServerArgs ...interface{}) (*SWbemServices, error) {
+	//fmt.Println("InitializeSWbemServices: Starting")
+	//TODO: implement connectServerArgs as optional argument for init with connectServer call
+	s := new(SWbemServices)
+	s.cWMIClient = c
+	s.queries = make(chan *queryRequest)
+	initError := make(chan error)
+	go s.process(initError)
+
+	err, ok := <-initError
+	if ok {
+		return nil, err //Send error to caller
+	}
+	//fmt.Println("InitializeSWbemServices: Finished")
+	return s, nil
+}
+
+// Close will clear and release all of the SWbemServices resources
+func (s *SWbemServices) Close() error {
+	s.lQueryorClose.Lock()
+	if s == nil || s.sWbemLocatorIDispatch == nil {
+		s.lQueryorClose.Unlock()
+		return fmt.Errorf("SWbemServices is not Initialized")
+	}
+	if s.queries == nil {
+		s.lQueryorClose.Unlock()
+		return fmt.Errorf("SWbemServices has been closed")
+	}
+	//fmt.Println("Close: sending close request")
+	var result error
+	ce := make(chan error)
+	s.closeError = ce //Race condition if multiple callers to close. May need to lock here
+	close(s.queries)  //Tell background to shut things down
+	s.lQueryorClose.Unlock()
+	err, ok := <-ce
+	if ok {
+		result = err
+	}
+	//fmt.Println("Close: finished")
+	return result
+}
+
+func (s *SWbemServices) process(initError chan error) {
+	//fmt.Println("process: starting background thread initialization")
+	//All OLE/WMI calls must happen on the same initialized thead, so lock this goroutine
+	runtime.LockOSThread()
+	defer runtime.LockOSThread()
+
+	err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED)
+	if err != nil {
+		oleCode := err.(*ole.OleError).Code()
+		if oleCode != ole.S_OK && oleCode != S_FALSE {
+			initError <- fmt.Errorf("ole.CoInitializeEx error: %v", err)
+			return
+		}
+	}
+	defer ole.CoUninitialize()
+
+	unknown, err := oleutil.CreateObject("WbemScripting.SWbemLocator")
+	if err != nil {
+		initError <- fmt.Errorf("CreateObject SWbemLocator error: %v", err)
+		return
+	} else if unknown == nil {
+		initError <- ErrNilCreateObject
+		return
+	}
+	defer unknown.Release()
+	s.sWbemLocatorIUnknown = unknown
+
+	dispatch, err := s.sWbemLocatorIUnknown.QueryInterface(ole.IID_IDispatch)
+	if err != nil {
+		initError <- fmt.Errorf("SWbemLocator QueryInterface error: %v", err)
+		return
+	}
+	defer dispatch.Release()
+	s.sWbemLocatorIDispatch = dispatch
+
+	// we can't do the ConnectServer call outside the loop unless we find a way to track and re-init the connectServerArgs
+	//fmt.Println("process: initialized. closing initError")
+	close(initError)
+	//fmt.Println("process: waiting for queries")
+	for q := range s.queries {
+		//fmt.Printf("process: new query: len(query)=%d\n", len(q.query))
+		errQuery := s.queryBackground(q)
+		//fmt.Println("process: s.queryBackground finished")
+		if errQuery != nil {
+			q.finished <- errQuery
+		}
+		close(q.finished)
+	}
+	//fmt.Println("process: queries channel closed")
+	s.queries = nil //set channel to nil so we know it is closed
+	//TODO: I think the Release/Clear calls can panic if things are in a bad state.
+	//TODO: May need to recover from panics and send error to method caller instead.
+	close(s.closeError)
+}
+
+// Query runs the WQL query using a SWbemServices instance and appends the values to dst.
+//
+// dst must have type *[]S or *[]*S, for some struct type S. Fields selected in
+// the query must have the same name in dst. Supported types are all signed and
+// unsigned integers, time.Time, string, bool, or a pointer to one of those.
+// Array types are not supported.
+//
+// By default, the local machine and default namespace are used. These can be
+// changed using connectServerArgs. See
+// http://msdn.microsoft.com/en-us/library/aa393720.aspx for details.
+func (s *SWbemServices) Query(query string, dst interface{}, connectServerArgs ...interface{}) error {
+	s.lQueryorClose.Lock()
+	if s == nil || s.sWbemLocatorIDispatch == nil {
+		s.lQueryorClose.Unlock()
+		return fmt.Errorf("SWbemServices is not Initialized")
+	}
+	if s.queries == nil {
+		s.lQueryorClose.Unlock()
+		return fmt.Errorf("SWbemServices has been closed")
+	}
+
+	//fmt.Println("Query: Sending query request")
+	qr := queryRequest{
+		query:    query,
+		dst:      dst,
+		args:     connectServerArgs,
+		finished: make(chan error),
+	}
+	s.queries <- &qr
+	s.lQueryorClose.Unlock()
+	err, ok := <-qr.finished
+	if ok {
+		//fmt.Println("Query: Finished with error")
+		return err //Send error to caller
+	}
+	//fmt.Println("Query: Finished")
+	return nil
+}
+
+func (s *SWbemServices) queryBackground(q *queryRequest) error {
+	if s == nil || s.sWbemLocatorIDispatch == nil {
+		return fmt.Errorf("SWbemServices is not Initialized")
+	}
+	wmi := s.sWbemLocatorIDispatch //Should just rename in the code, but this will help as we break things apart
+	//fmt.Println("queryBackground: Starting")
+
+	dv := reflect.ValueOf(q.dst)
+	if dv.Kind() != reflect.Ptr || dv.IsNil() {
+		return ErrInvalidEntityType
+	}
+	dv = dv.Elem()
+	mat, elemType := checkMultiArg(dv)
+	if mat == multiArgTypeInvalid {
+		return ErrInvalidEntityType
+	}
+
+	// service is a SWbemServices
+	serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer", q.args...)
+	if err != nil {
+		return err
+	}
+	service := serviceRaw.ToIDispatch()
+	defer serviceRaw.Clear()
+
+	// result is a SWBemObjectSet
+	resultRaw, err := oleutil.CallMethod(service, "ExecQuery", q.query)
+	if err != nil {
+		return err
+	}
+	result := resultRaw.ToIDispatch()
+	defer resultRaw.Clear()
+
+	count, err := oleInt64(result, "Count")
+	if err != nil {
+		return err
+	}
+
+	enumProperty, err := result.GetProperty("_NewEnum")
+	if err != nil {
+		return err
+	}
+	defer enumProperty.Clear()
+
+	enum, err := enumProperty.ToIUnknown().IEnumVARIANT(ole.IID_IEnumVariant)
+	if err != nil {
+		return err
+	}
+	if enum == nil {
+		return fmt.Errorf("can't get IEnumVARIANT, enum is nil")
+	}
+	defer enum.Release()
+
+	// Initialize a slice with Count capacity
+	dv.Set(reflect.MakeSlice(dv.Type(), 0, int(count)))
+
+	var errFieldMismatch error
+	for itemRaw, length, err := enum.Next(1); length > 0; itemRaw, length, err = enum.Next(1) {
+		if err != nil {
+			return err
+		}
+
+		err := func() error {
+			// item is a SWbemObject, but really a Win32_Process
+			item := itemRaw.ToIDispatch()
+			defer item.Release()
+
+			ev := reflect.New(elemType)
+			if err = s.cWMIClient.loadEntity(ev.Interface(), item); err != nil {
+				if _, ok := err.(*ErrFieldMismatch); ok {
+					// We continue loading entities even in the face of field mismatch errors.
+					// If we encounter any other error, that other error is returned. Otherwise,
+					// an ErrFieldMismatch is returned.
+					errFieldMismatch = err
+				} else {
+					return err
+				}
+			}
+			if mat != multiArgTypeStructPtr {
+				ev = ev.Elem()
+			}
+			dv.Set(reflect.Append(dv, ev))
+			return nil
+		}()
+		if err != nil {
+			return err
+		}
+	}
+	//fmt.Println("queryBackground: Finished")
+	return errFieldMismatch
+}