function Blend.Spring(z,c,I)local u=Blend.toPropertyObservable(z)or Rx.of(z)local F=Blend.toNumberObservable(c)local P=Blend.toNumberObservable(I)local function S(z,c)local I=Spring.new(c)if F then z:GiveTask(F:Subscribe(function(z)assert(type(z)=="\110\117\109\098\101\114","\066\097\100 \118\097\108\117\101")I.Speed=z end))end if P then z:GiveTask(P:Subscribe(function(z)assert(type(z)=="\110\117\109\098\101\114","\066\097\100 \118\097\108\117\101")I.Damper=z end))end return I end return Observable.new(function(z)local c local I=Maid.new()local F,P=StepUtils.bindToRenderStep(function()local I,u=SpringUtils.animating(c)z:Fire(SpringUtils.fromLinearIfNeeded(u))return I end)I:GiveTask(P)I:GiveTask(u:Subscribe(function(z)if z then local u=SpringUtils.toLinearIfNeeded(z)c=c or S(I,u)c.t=SpringUtils.toLinearIfNeeded(z)F()else warn("\071\111\116 \110\105\108 \118\097\108\117\101 \102\114\111\109 \101\109\105\116\116\101\100 \115\111\117\114\099\101")end end))return I end)end
--[=[
	Converts this arbitrary value into an observable that will initialize a spring
	and interpolate it between values upon subscription.

	```lua
	local percentVisible = Blend.State(0)
	local visibleSpring = Blend.Spring(percentVisible, 30)
	local transparency = Blend.Computed(visibleSpring, function(percent)
		return 1 - percent
	end);

	Blend.mount(frame, {
		BackgroundTransparency = visibleSpring;
	})
	```

	@param source any
	@param speed any
	@param damper any
	@return Observable?
]=]
function Blend.Spring(source, speed, damper)
	local sourceObservable = Blend.toPropertyObservable(source) or Rx.of(source)
	local speedObservable = Blend.toNumberObservable(speed)
	local damperObservable = Blend.toNumberObservable(damper)

	local function createSpring(maid, initialValue)
		local spring = Spring.new(initialValue)

		if speedObservable then
			maid:GiveTask(speedObservable:Subscribe(function(value)
				assert(type(value) == "number", "Bad value")
				spring.Speed = value
			end))
		end

		if damperObservable then
			maid:GiveTask(damperObservable:Subscribe(function(value)
				assert(type(value) == "number", "Bad value")

				spring.Damper = value
			end))
		end

		return spring
	end

	-- TODO: Centralize and cache
	return Observable.new(function(sub)
		local spring
		local maid = Maid.new()

		local startAnimate, stopAnimate = StepUtils.bindToRenderStep(function()
			local animating, position = SpringUtils.animating(spring)
			sub:Fire(SpringUtils.fromLinearIfNeeded(position))
			return animating
		end)

		maid:GiveTask(stopAnimate)
		maid:GiveTask(sourceObservable:Subscribe(function(value)
			if value then
				local linearValue = SpringUtils.toLinearIfNeeded(value)
				spring = spring or createSpring(maid, linearValue)
				spring.t = SpringUtils.toLinearIfNeeded(value)
				startAnimate()
			else
				warn("Got nil value from emitted source")
			end
		end))

		return maid
	end)
end
