func (provider) Transform(cfg map[string]interface{}) error {
	metaURL, ok := cfg["packetMetaDataUrl"].(string)
	if !ok {
		metaURL = defaultPacketMetaDataURL
	}

	var data metadata

	return config.ReplaceObjects(cfg, "packet", func(val map[string]interface{}) (interface{}, error) {
		// Fetch packet metadata, if not already done
		if data.InstanceID == "" {
			g := got.New()
			res, err := g.Get(metaURL).Send()
			if err != nil {
				return nil, fmt.Errorf("Failed to fetch packet metadata, error: %s", err)
			}
			err = json.Unmarshal(res.Body, &data)
			if err != nil {
				return nil, fmt.Errorf("Failed to parse packet metadata, error: %s", err)
			}
			if data.InstanceID == "" {
				return nil, errors.New("Packet metadata isn't valid missing 'id' property")
			}
		}

		key := val["$packet"].(string)
		switch key {
		case "instance-id":
			return data.InstanceID, nil
		case "hostname":
			return data.Hostname, nil
		case "facility":
			return data.Facility, nil
		case "instance-type":
			return data.InstanceType, nil
		case "public-ipv4":
			for _, addr := range data.Network.Addresses {
				if addr.Family == 4 && addr.Public {
					return addr.Address, nil
				}
			}
			return nil, ErrNoPublicIPv4Address
		case "public-ipv6":
			for _, addr := range data.Network.Addresses {
				if addr.Family == 6 && addr.Public {
					return addr.Address, nil
				}
			}
			return nil, ErrNoPublicIPv6Address
		default:
			return nil, fmt.Errorf("Unknown $packet variable: %s", key)
		}
	})
}
// ListDisplays will fetch a list of displays offered by the socketURL.
func ListDisplays(socketURL string) ([]Display, error) {
	// Parse socketURL and get query string
	u, err := url.Parse(socketURL)
	if err != nil {
		return nil, fmt.Errorf("Invalid socketURL: %s, parsing error: %s",
			socketURL, err)
	}

	// Ensure the URL has http or https as scheme
	switch u.Scheme {
	case "ws":
		u.Scheme = "http"
	case "wss":
		u.Scheme = "https"
	}

	// Create a new got client
	g := got.New()
	g.Client = &http.Client{Timeout: 30 * time.Second}
	g.MaxSize = 10 * 1024 * 1024 // 10 MiB should be more than enough

	// Send a request
	res, err := g.Get(u.String()).Send()

	// If non-2xx error we try to parse the error
	if rerr, ok := err.(*got.BadResponseCodeError); ok {
		var errorMsg displayconsts.ErrorMessage
		if json.Unmarshal(rerr.Response.Body, &errorMsg) == nil {
			return nil, &errorMsg
		}
		return nil, fmt.Errorf("Failed to list displays got status code: %d",
			res.StatusCode)
	}
	// Otherwise we just wrap the error for better interpretation
	if err != nil {
		return nil, fmt.Errorf("Failed to list displays, error: %s", err)
	}

	// If no error, we try to parse the response
	var displays []Display
	err = json.Unmarshal(res.Body, &displays)
	if err != nil {
		return nil, fmt.Errorf("Failed to parse JSON response, error: %s", err)
	}

	// Set socketURL on all display structures
	for i := range displays {
		displays[i].socketURL = socketURL
	}

	return displays, nil
}