func resourceLibratoSpaceChartUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*librato.Client)

	spaceID := uint(d.Get("space_id").(int))
	chartID, err := strconv.ParseUint(d.Id(), 10, 0)
	if err != nil {
		return err
	}

	spaceChart := new(librato.SpaceChart)
	if d.HasChange("name") {
		spaceChart.Name = librato.String(d.Get("name").(string))
	}
	if d.HasChange("min") {
		if math.IsNaN(d.Get("min").(float64)) {
			spaceChart.Min = nil
		} else {
			spaceChart.Min = librato.Float(d.Get("min").(float64))
		}
	}
	if d.HasChange("max") {
		if math.IsNaN(d.Get("max").(float64)) {
			spaceChart.Max = nil
		} else {
			spaceChart.Max = librato.Float(d.Get("max").(float64))
		}
	}
	if d.HasChange("label") {
		spaceChart.Label = librato.String(d.Get("label").(string))
	}
	if d.HasChange("related_space") {
		spaceChart.RelatedSpace = librato.Uint(d.Get("related_space").(uint))
	}
	if d.HasChange("stream") {
		vs := d.Get("stream").(*schema.Set)
		streams := make([]librato.SpaceChartStream, vs.Len())
		for i, streamDataM := range vs.List() {
			streamData := streamDataM.(map[string]interface{})
			var stream librato.SpaceChartStream
			if v, ok := streamData["metric"].(string); ok && v != "" {
				stream.Metric = librato.String(v)
			}
			if v, ok := streamData["source"].(string); ok && v != "" {
				stream.Source = librato.String(v)
			}
			if v, ok := streamData["composite"].(string); ok && v != "" {
				stream.Composite = librato.String(v)
			}
			if v, ok := streamData["group_function"].(string); ok && v != "" {
				stream.GroupFunction = librato.String(v)
			}
			if v, ok := streamData["summary_function"].(string); ok && v != "" {
				stream.SummaryFunction = librato.String(v)
			}
			if v, ok := streamData["transform_function"].(string); ok && v != "" {
				stream.TransformFunction = librato.String(v)
			}
			if v, ok := streamData["color"].(string); ok && v != "" {
				stream.Color = librato.String(v)
			}
			if v, ok := streamData["units_short"].(string); ok && v != "" {
				stream.UnitsShort = librato.String(v)
			}
			if v, ok := streamData["units_longs"].(string); ok && v != "" {
				stream.UnitsLong = librato.String(v)
			}
			if v, ok := streamData["min"].(float64); ok && !math.IsNaN(v) {
				stream.Min = librato.Float(v)
			}
			if v, ok := streamData["max"].(float64); ok && !math.IsNaN(v) {
				stream.Max = librato.Float(v)
			}
			streams[i] = stream
		}
		spaceChart.Streams = streams
	}

	_, err = client.Spaces.EditChart(spaceID, uint(chartID), spaceChart)
	if err != nil {
		return fmt.Errorf("Error updating Librato space chart %s: %s", *spaceChart.Name, err)
	}

	return resourceLibratoSpaceChartRead(d, meta)
}
func resourceLibratoSpaceChartCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*librato.Client)

	spaceID := uint(d.Get("space_id").(int))

	spaceChart := new(librato.SpaceChart)
	if v, ok := d.GetOk("name"); ok {
		spaceChart.Name = librato.String(v.(string))
	}
	if v, ok := d.GetOk("type"); ok {
		spaceChart.Type = librato.String(v.(string))
	}
	if v, ok := d.GetOk("min"); ok {
		if math.IsNaN(v.(float64)) {
			spaceChart.Min = nil
		} else {
			spaceChart.Min = librato.Float(v.(float64))
		}
	}
	if v, ok := d.GetOk("max"); ok {
		if math.IsNaN(v.(float64)) {
			spaceChart.Max = nil
		} else {
			spaceChart.Max = librato.Float(v.(float64))
		}
	}
	if v, ok := d.GetOk("label"); ok {
		spaceChart.Label = librato.String(v.(string))
	}
	if v, ok := d.GetOk("related_space"); ok {
		spaceChart.RelatedSpace = librato.Uint(uint(v.(int)))
	}
	if v, ok := d.GetOk("stream"); ok {
		vs := v.(*schema.Set)
		streams := make([]librato.SpaceChartStream, vs.Len())
		for i, streamDataM := range vs.List() {
			streamData := streamDataM.(map[string]interface{})
			var stream librato.SpaceChartStream
			if v, ok := streamData["metric"].(string); ok && v != "" {
				stream.Metric = librato.String(v)
			}
			if v, ok := streamData["source"].(string); ok && v != "" {
				stream.Source = librato.String(v)
			}
			if v, ok := streamData["composite"].(string); ok && v != "" {
				stream.Composite = librato.String(v)
			}
			if v, ok := streamData["group_function"].(string); ok && v != "" {
				stream.GroupFunction = librato.String(v)
			}
			if v, ok := streamData["summary_function"].(string); ok && v != "" {
				stream.SummaryFunction = librato.String(v)
			}
			if v, ok := streamData["transform_function"].(string); ok && v != "" {
				stream.TransformFunction = librato.String(v)
			}
			if v, ok := streamData["color"].(string); ok && v != "" {
				stream.Color = librato.String(v)
			}
			if v, ok := streamData["units_short"].(string); ok && v != "" {
				stream.UnitsShort = librato.String(v)
			}
			if v, ok := streamData["units_longs"].(string); ok && v != "" {
				stream.UnitsLong = librato.String(v)
			}
			if v, ok := streamData["min"].(float64); ok && !math.IsNaN(v) {
				stream.Min = librato.Float(v)
			}
			if v, ok := streamData["max"].(float64); ok && !math.IsNaN(v) {
				stream.Max = librato.Float(v)
			}
			streams[i] = stream
		}
		spaceChart.Streams = streams
	}

	spaceChartResult, _, err := client.Spaces.CreateChart(spaceID, spaceChart)
	if err != nil {
		return fmt.Errorf("Error creating Librato space chart %s: %s", *spaceChart.Name, err)
	}

	resource.Retry(1*time.Minute, func() *resource.RetryError {
		_, _, err := client.Spaces.GetChart(spaceID, *spaceChartResult.ID)
		if err != nil {
			if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
				return resource.RetryableError(err)
			}
			return resource.NonRetryableError(err)
		}
		return nil
	})

	return resourceLibratoSpaceChartReadResult(d, spaceChartResult)
}