function Spring.__index(n,A)if Spring[A]then return Spring[A]elseif A=="\086\097\108\117\101"or A=="\080\111\115\105\116\105\111\110"or A=="\112"then local A,M=n:_positionVelocity(n._clock())return A elseif A=="\086\101\108\111\099\105\116\121"or A=="\118"then local A,M=n:_positionVelocity(n._clock())return M elseif A=="\084\097\114\103\101\116"or A=="\116"then return n._target elseif A=="\068\097\109\112\101\114"or A=="\100"then return n._damper elseif A=="\083\112\101\101\100"or A=="\115"then return n._speed elseif A=="\067\108\111\099\107"then return n._clock else error(("\037\113 \105\115 \110\111\116 \097 \118\097\108\105\100 \109\101\109\098\101\114 \111\102 \083\112\114\105\110\103"):format(tostring(A)),2)end end function Spring.__newindex(M,A,n)local N=M._clock()if A=="\086\097\108\117\101"or A=="\080\111\115\105\116\105\111\110"or A=="\112"then local A,y=M:_positionVelocity(N)M._position0=n M._velocity0=y M._time0=N elseif A=="\086\101\108\111\099\105\116\121"or A=="\118"then local A,y=M:_positionVelocity(N)M._position0=A M._velocity0=n M._time0=N elseif A=="\084\097\114\103\101\116"or A=="\116"then local A,y=M:_positionVelocity(N)M._position0=A M._velocity0=y M._target=n M._time0=N elseif A=="\068\097\109\112\101\114"or A=="\100"then local A,y=M:_positionVelocity(N)M._position0=A M._velocity0=y M._damper=n M._time0=N elseif A=="\083\112\101\101\100"or A=="\115"then local A,y=M:_positionVelocity(N)M._position0=A M._velocity0=y M._speed=n<0 and 0 or n M._time0=N elseif A=="\067\108\111\099\107"then local A,y=M:_positionVelocity(N)M._position0=A M._velocity0=y M._clock=n M._time0=n()else error(("\037\113 \105\115 \110\111\116 \097 \118\097\108\105\100 \109\101\109\098\101\114 \111\102 \083\112\114\105\110\103"):format(tostring(A)),2)end end function Spring._positionVelocity(n,A)local M=n._position0 local N=n._velocity0 local y=n._target local S=n._damper local Q=n._speed local p=Q*(A-n._time0)local z=S*S local k,I,w if z<1 then k=math.sqrt(1-z)local A=math.exp(-S*p)/k w,I=A*math.cos(k*p),A*math.sin(k*p)elseif z==1 then k=1 local A=math.exp(-S*p)/k w,I=A,A*p else k=math.sqrt(z-1)local A=math.exp((-S+k)*p)/(2*k)local n=math.exp((-S-k)*p)/(2*k)w,I=A+n,A-n end local j=k*w+S*I local q=1-(k*w+S*I)local d=I/Q local B=-Q*I local H=Q*I local D=k*w-S*I return(j*M+q*y)+d*N,(B*M+H*y)+D*N end return Spring

function Spring:__index(index)
	if Spring[index] then
		return Spring[index]
	elseif index == "Value" or index == "Position" or index == "p" then
		local position, _ = self:_positionVelocity(self._clock())
		return position
	elseif index == "Velocity" or index == "v" then
		local _, velocity = self:_positionVelocity(self._clock())
		return velocity
	elseif index == "Target" or index == "t" then
		return self._target
	elseif index == "Damper" or index == "d" then
		return self._damper
	elseif index == "Speed" or index == "s" then
		return self._speed
	elseif index == "Clock" then
		return self._clock
	else
		error(("%q is not a valid member of Spring"):format(tostring(index)), 2)
	end
end

function Spring:__newindex(index, value)
	local now = self._clock()

	if index == "Value" or index == "Position" or index == "p" then
		local _, velocity = self:_positionVelocity(now)
		self._position0 = value
		self._velocity0 = velocity
		self._time0 = now
	elseif index == "Velocity" or index == "v" then
		local position, _ = self:_positionVelocity(now)
		self._position0 = position
		self._velocity0 = value
		self._time0 = now
	elseif index == "Target" or index == "t" then
		local position, velocity = self:_positionVelocity(now)
		self._position0 = position
		self._velocity0 = velocity
		self._target = value
		self._time0 = now
	elseif index == "Damper" or index == "d" then
		local position, velocity = self:_positionVelocity(now)
		self._position0 = position
		self._velocity0 = velocity
		self._damper = value
		self._time0 = now
	elseif index == "Speed" or index == "s" then
		local position, velocity = self:_positionVelocity(now)
		self._position0 = position
		self._velocity0 = velocity
		self._speed = value < 0 and 0 or value
		self._time0 = now
	elseif index == "Clock" then
		local position, velocity = self:_positionVelocity(now)
		self._position0 = position
		self._velocity0 = velocity
		self._clock = value
		self._time0 = value()
	else
		error(("%q is not a valid member of Spring"):format(tostring(index)), 2)
	end
end

function Spring:_positionVelocity(now)
	local p0 = self._position0
	local v0 = self._velocity0
	local p1 = self._target
	local d = self._damper
	local s = self._speed

	local t = s*(now - self._time0)
	local d2 = d*d

	local h, si, co
	if d2 < 1 then
		h = math.sqrt(1 - d2)
		local ep = math.exp(-d*t)/h
		co, si = ep*math.cos(h*t), ep*math.sin(h*t)
	elseif d2 == 1 then
		h = 1
		local ep = math.exp(-d*t)/h
		co, si = ep, ep*t
	else
		h = math.sqrt(d2 - 1)
		local u = math.exp((-d + h)*t)/(2*h)
		local v = math.exp((-d - h)*t)/(2*h)
		co, si = u + v, u - v
	end

	local a0 = h*co + d*si
	local a1 = 1 - (h*co + d*si)
	local a2 = si/s

	local b0 = -s*si
	local b1 = s*si
	local b2 = h*co - d*si

	return
		a0*p0 + a1*p1 + a2*v0,
		b0*p0 + b1*p1 + b2*v0
end

return Spring
