Making server action result types more consistent
diff --git a/_site/openstack/identity/v2/tokens/results.go b/_site/openstack/identity/v2/tokens/results.go
new file mode 100644
index 0000000..e88b2c7
--- /dev/null
+++ b/_site/openstack/identity/v2/tokens/results.go
@@ -0,0 +1,133 @@
+package tokens
+
+import (
+	"time"
+
+	"github.com/mitchellh/mapstructure"
+	"github.com/rackspace/gophercloud"
+	"github.com/rackspace/gophercloud/openstack/identity/v2/tenants"
+)
+
+// Token provides only the most basic information related to an authentication token.
+type Token struct {
+	// ID provides the primary means of identifying a user to the OpenStack API.
+	// OpenStack defines this field as an opaque value, so do not depend on its content.
+	// It is safe, however, to compare for equality.
+	ID string
+
+	// ExpiresAt provides a timestamp in ISO 8601 format, indicating when the authentication token becomes invalid.
+	// After this point in time, future API requests made using this authentication token will respond with errors.
+	// Either the caller will need to reauthenticate manually, or more preferably, the caller should exploit automatic re-authentication.
+	// See the AuthOptions structure for more details.
+	ExpiresAt time.Time
+
+	// Tenant provides information about the tenant to which this token grants access.
+	Tenant tenants.Tenant
+}
+
+// Endpoint represents a single API endpoint offered by a service.
+// It provides the public and internal URLs, if supported, along with a region specifier, again if provided.
+// The significance of the Region field will depend upon your provider.
+//
+// In addition, the interface offered by the service will have version information associated with it
+// through the VersionId, VersionInfo, and VersionList fields, if provided or supported.
+//
+// In all cases, fields which aren't supported by the provider and service combined will assume a zero-value ("").
+type Endpoint struct {
+	TenantID    string `mapstructure:"tenantId"`
+	PublicURL   string `mapstructure:"publicURL"`
+	InternalURL string `mapstructure:"internalURL"`
+	AdminURL    string `mapstructure:"adminURL"`
+	Region      string `mapstructure:"region"`
+	VersionID   string `mapstructure:"versionId"`
+	VersionInfo string `mapstructure:"versionInfo"`
+	VersionList string `mapstructure:"versionList"`
+}
+
+// CatalogEntry provides a type-safe interface to an Identity API V2 service catalog listing.
+// Each class of service, such as cloud DNS or block storage services, will have a single
+// CatalogEntry representing it.
+//
+// Note: when looking for the desired service, try, whenever possible, to key off the type field.
+// Otherwise, you'll tie the representation of the service to a specific provider.
+type CatalogEntry struct {
+	// Name will contain the provider-specified name for the service.
+	Name string `mapstructure:"name"`
+
+	// Type will contain a type string if OpenStack defines a type for the service.
+	// Otherwise, for provider-specific services, the provider may assign their own type strings.
+	Type string `mapstructure:"type"`
+
+	// Endpoints will let the caller iterate over all the different endpoints that may exist for
+	// the service.
+	Endpoints []Endpoint `mapstructure:"endpoints"`
+}
+
+// ServiceCatalog provides a view into the service catalog from a previous, successful authentication.
+type ServiceCatalog struct {
+	Entries []CatalogEntry
+}
+
+// CreateResult defers the interpretation of a created token.
+// Use ExtractToken() to interpret it as a Token, or ExtractServiceCatalog() to interpret it as a service catalog.
+type CreateResult struct {
+	gophercloud.CommonResult
+}
+
+// ExtractToken returns the just-created Token from a CreateResult.
+func (result CreateResult) ExtractToken() (*Token, error) {
+	if result.Err != nil {
+		return nil, result.Err
+	}
+
+	var response struct {
+		Access struct {
+			Token struct {
+				Expires string         `mapstructure:"expires"`
+				ID      string         `mapstructure:"id"`
+				Tenant  tenants.Tenant `mapstructure:"tenant"`
+			} `mapstructure:"token"`
+		} `mapstructure:"access"`
+	}
+
+	err := mapstructure.Decode(result.Resp, &response)
+	if err != nil {
+		return nil, err
+	}
+
+	expiresTs, err := time.Parse(gophercloud.RFC3339Milli, response.Access.Token.Expires)
+	if err != nil {
+		return nil, err
+	}
+
+	return &Token{
+		ID:        response.Access.Token.ID,
+		ExpiresAt: expiresTs,
+		Tenant:    response.Access.Token.Tenant,
+	}, nil
+}
+
+// ExtractServiceCatalog returns the ServiceCatalog that was generated along with the user's Token.
+func (result CreateResult) ExtractServiceCatalog() (*ServiceCatalog, error) {
+	if result.Err != nil {
+		return nil, result.Err
+	}
+
+	var response struct {
+		Access struct {
+			Entries []CatalogEntry `mapstructure:"serviceCatalog"`
+		} `mapstructure:"access"`
+	}
+
+	err := mapstructure.Decode(result.Resp, &response)
+	if err != nil {
+		return nil, err
+	}
+
+	return &ServiceCatalog{Entries: response.Access.Entries}, nil
+}
+
+// createErr quickly packs an error in a CreateResult.
+func createErr(err error) CreateResult {
+	return CreateResult{gophercloud.CommonResult{Err: err}}
+}