Roblox/luau_corpus huggingface dataset:
--[[ END OF SERVICES ]]

local LocalPlayer = PlayersService.LocalPlayer
while LocalPlayer == nil do
	PlayersService.ChildAdded:wait()
	LocalPlayer = PlayersService.LocalPlayer
end

local PlayerGui = LocalPlayer:WaitForChild("PlayerGui")

local success, UserShouldLocalizeGameChatBubble = pcall(function()
	return UserSettings():IsUserFeatureEnabled("UserShouldLocalizeGameChatBubble")
end)
local UserShouldLocalizeGameChatBubble = success and UserShouldLocalizeGameChatBubble

local UserFixBubbleChatText do
	local success, value = pcall(function()
		return UserSettings():IsUserFeatureEnabled("UserFixBubbleChatText")
	end)
	UserFixBubbleChatText = success and value
end

local UserRoactBubbleChatBeta do
	local success, value = pcall(function()
		return UserSettings():IsUserFeatureEnabled("UserRoactBubbleChatBeta")
	end)
	UserRoactBubbleChatBeta = success and value
end

local UserPreventOldBubbleChatOverlap do
	local success, value = pcall(function()
		return UserSettings():IsUserFeatureEnabled("UserPreventOldBubbleChatOverlap")
	end)
	UserPreventOldBubbleChatOverlap = success and value
end

local function getMessageLength(message)
	return utf8.len(utf8.nfcnormalize(message))
end
-- Ensures that SenseManager does nothing if accidentally required on client
if not RunService:IsServer() then
	return SenseManager
end

local octree = Octree.new()
local budgetRunner = BudgetRunner.new(FRAME_BUDGET)
local agentQueue = CircularQueue.new()
local agentIdToRootPart = {}
local enabled = true

local queryCount = 0
local queryDuration = 0
local lastMetricReportTime = tick()

function SenseManager.registerEvent(eventData)
	if enabled then
		return octree:registerEvent(eventData)
	else
		return nil
	end
end

function SenseManager.registerAgent(agentId, rootPart)
	if enabled then
		agentIdToRootPart[agentId] = rootPart
		agentQueue:push(agentId)
	end
end

function SenseManager.unregisterAgent(agentId)
	if enabled then
		agentIdToRootPart[agentId] = nil
		agentQueue:remove(agentId)
	end
end

function SenseManager.removeEventById(eventId)
	if enabled then
		octree:removeEventById(eventId)
	end
end

function SenseManager.queryRegion(center, volume)
	if enabled then
		local startTime = tick()
		local result = octree:queryRegion(center, volume)
		local endTime = tick()
		
		queryDuration = queryDuration + endTime - startTime
		queryCount = queryCount + 1
		
		return result
	else
		return {}
	end
end

function SenseManager.querySphere(center, radius)
	if enabled then
		local startTime = tick()
		local diameter = radius * 2
		local result = {}
		
		for _, event in ipairs(octree:queryRegion(center, Vector3.new(diameter, diameter, diameter))) do
			if (event.position - center).Magnitude < radius then
				table.insert(result, event)
			end
		end
		local endTime = tick()
		
		queryDuration = queryDuration + endTime - startTime
		queryCount = queryCount + 1
	
		return result
	else
		return {}
	end
end

function SenseManager.setEnabled(state)
	if state ~= enabled then
		if state then
			octree = Octree.new()
			agentQueue = CircularQueue.new()
			agentIdToRootPart = {}
		else
			octree:destroy()
			agentQueue = nil
			agentIdToRootPart = nil
		end
		
		enabled = state
	end
end

RunService.Heartbeat:Connect(function()
	local frameBudgetFull = false
	
	local startAgentId = agentQueue:next()
	local currAgentId = startAgentId
	if currAgentId then
		budgetRunner:tear()
		repeat
			local rootPart = agentIdToRootPart[currAgentId]
			if rootPart then
				frameBudgetFull = not budgetRunner:run(function()
					Blackboards.getAgentBlackboard(currAgentId).senseEvents = SenseManager.querySphere(rootPart.Position, SENSE_RADIUS)
				end)
			end
			currAgentId = agentQueue:next()
		until(frameBudgetFull or currAgentId == startAgentId)
	end
	
	local currTime = tick()
	if currTime >= lastMetricReportTime + METRIC_REPORT_RATE then
		SenseManagerStatEvent:FireAllClients(currTime - lastMetricReportTime, queryCount, queryDuration)
		queryDuration = 0
		queryCount = 0
		lastMetricReportTime = currTime
	end
end)

return SenseManager
-- [[ SCRIPT ENUMS ]]
local BubbleColor = {	WHITE = "dub",
					BLUE = "blu",
					GREEN = "gre",
					RED = "red" }
-- Optimized CFrame interpolator module ~ by Stravant
-- Based off of code by Treyreynolds posted on the Roblox Developer Forum

local fromAxisAngle = CFrame.fromAxisAngle
local components = CFrame.new().components
local inverse = CFrame.new().inverse
local v3 = Vector3.new
local acos = math.acos
local sqrt = math.sqrt
local invroot2 = 1/math.sqrt(2)

return function(c0, c1, t) -- (CFrame from, CFrame to) -> (float theta, (float fraction -> CFrame between))
	-- The expanded matrix
	local _, _, _, xx, yx, zx, 
	               xy, yy, zy, 
	               xz, yz, zz = components(inverse(c0)*c1)
	
	-- The cos-theta of the axisAngles from 
	local cosTheta = (xx + yy + zz - 1)/2
	
	-- Rotation axis
	local rotationAxis = v3(yz-zy, zx-xz, xy-yx)
	
	-- The position to tween through
	local positionDelta = (c1.p - c0.p)
		
	-- Theta
	local theta;			
		
	-- Catch degenerate cases
	if cosTheta >= 0.999 then
			return c0 + positionDelta*t
	elseif cosTheta <= -0.999 then
		-- Case exactly opposite rotations, disambiguate
		theta = math.pi
		xx = (xx + 1) / 2
		yy = (yy + 1) / 2
		zz = (zz + 1) / 2
		if xx > yy and xx > zz then
			if xx < 0.001 then
				rotationAxis = v3(0, invroot2, invroot2)
			else
				local x = sqrt(xx)
				xy = (xy + yx) / 4
				xz = (xz + zx) / 4
				rotationAxis = v3(x, xy/x, xz/x)
			end
		elseif yy > zz then
			if yy < 0.001 then
				rotationAxis = v3(invroot2, 0, invroot2)
			else
				local y = sqrt(yy)
				xy = (xy + yx) / 4
				yz = (yz + zy) / 4
				rotationAxis = v3(xy/y, y, yz/y)
			end	
		else
			if zz < 0.001 then
				rotationAxis = v3(invroot2, invroot2, 0)
			else
				local z = sqrt(zz)
				xz = (xz + zx) / 4
				yz = (yz + zy) / 4
				rotationAxis = v3(xz/z, yz/z, z)
			end
		end
	else
		-- Normal case, get theta from cosTheta
		theta = acos(cosTheta)
	end
	
	return c0*fromAxisAngle(rotationAxis, theta*t) + positionDelta*t
end
-- Bind function to fire event
fireEvent.OnServerEvent:connect(function(player, target)
	if tool.Parent == player.Character then
		-- If tool has enough shots then fires. Otherwise reloads.
		if currentAmmo <= 0 then
			return reload()
		end
		if canFire then
			canFire = false
			currentAmmo = currentAmmo - 1
			fireSound:Play()
			createBullet(target)
			delay(attackCooldown, function()
				canFire = true
			end)
		end
	end
end)
--- Returns the last argument that has a value.
-- Useful for getting the autocomplete for the argument the user is working on.
function Command:GetLastArgument()
	for i = #self.Arguments, 1, -1 do
		if self.Arguments[i].RawValue then
			return self.Arguments[i]
		end
	end
end
-----------------------------------------------| Save Stats |------------------------------------------------------------


local DataStoreService = game:GetService("DataStoreService")
local myDataStore = DataStoreService:GetDataStore("myDataStore")


game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local Time = Instance.new("IntValue")
	Time.Name = "Speed"
	Time.Parent = leaderstats

	local playerUserId = "Player"..player.UserId

	local data 

	local success, errormessage = pcall(function()
		data = myDataStore:GetAsync(playerUserId) 
	end)


	if success then
		Time.Value = data  
	end

	while wait(1) do
		player.leaderstats.Speed.Value = player.leaderstats.Speed.Value + 1 --Don't change it or it will make it go up twice
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	local playerUserId = "Player"..player.UserId

	local data = player.leaderstats.Speed.Value

	myDataStore:SetAsync(playerUserId, data)   

end)
-- connect events
Humanoid.Died:connect(onDied)
Humanoid.Running:connect(onRunning)
Humanoid.Jumping:connect(onJumping)
Humanoid.Climbing:connect(onClimbing)
Humanoid.GettingUp:connect(onGettingUp)
Humanoid.FreeFalling:connect(onFreeFall)
Humanoid.FallingDown:connect(onFallingDown)
Humanoid.Seated:connect(onSeated)
Humanoid.PlatformStanding:connect(onPlatformStanding)
Humanoid.Swimming:connect(onSwimming)
----------------------------------------------------------------------------------------------------
-----------------=[ RECOIL & PRECISAO ]=------------------------------------------------------------
----------------------------------------------------------------------------------------------------
	,VRecoil = {12,16}				--- Vertical Recoil
	,HRecoil = {5,7}				--- Horizontal Recoil
	,AimRecover = .7				---- Between 0 & 1
	
	,RecoilPunch = .15
	,VPunchBase = 2.5				--- Vertical Punch
	,HPunchBase = 1.7				--- Horizontal Punch
	,DPunchBase = 1 				--- Tilt Punch | useless
	
	,AimRecoilReduction = 5 		--- Recoil Reduction Factor While Aiming (Do not set to 0)
	,PunchRecover = 0.1
	,MinRecoilPower = .5
	,MaxRecoilPower = 3.5
	,RecoilPowerStepAmount = .25
	
	,MinSpread = 0.56				--- Min bullet spread value | Studs
	,MaxSpread = 35					--- Max bullet spread value | Studs
	,AimInaccuracyStepAmount = 0.5
	,WalkMultiplier = 0				--- Bullet spread based on player speed

	,SwayBase = 0.25				--- Weapon Base Sway | Studs
	,MaxSway =	1.5					--- Max sway value based on player stamina | Studs
-- If in-game, enable ctrl hotkeys for prism selection
if Mode == 'Tool' then
	AssignHotkey({ 'LeftControl', 'K' }, Targeting.PrismSelect);
	AssignHotkey({ 'RightControl', 'K' }, Targeting.PrismSelect);
end;
-- ButtonClick
ExitButton.Activated:Connect(hide)
InteractionButton.Activated:Connect(show)
ToGameButton.Activated:Connect(EnterGame)
-- Make a base cosmetic bullet object. This will be cloned every time we fire off a ray.
local CosmeticBullet = Instance.new("Part")
CosmeticBullet.Material = Enum.Material.Neon
CosmeticBullet.Color = Color3.fromRGB(0, 196, 255)
CosmeticBullet.CanCollide = false
CosmeticBullet.Anchored = true
CosmeticBullet.Size = Vector3.new(0.2, 0.2, 2.4)
--Redirects velocity
function MathUtils:GroundAccelerate(wishDir, wishSpeed, accel, velocity, dt)
    --Cap velocity
    local speed = velocity.Magnitude
    if speed > wishSpeed then
        velocity = velocity.unit * wishSpeed
    end

    local wishVel = wishDir * wishSpeed
    local pushDir = wishVel - velocity

    local pushLen = pushDir.magnitude

    local canPush = accel * dt * wishSpeed

    if canPush > pushLen then
        canPush = pushLen
    end
    if canPush < 0.00001 then
        return velocity
    end
    return velocity + (canPush * pushDir.Unit)
end

function MathUtils:Accelerate(wishDir, wishSpeed, accel, velocity, dt)
    local speed = velocity.magnitude

    local currentSpeed = velocity:Dot(wishDir)
    local addSpeed = wishSpeed - currentSpeed

    if addSpeed <= 0 then
        return velocity
    end

    local accelSpeed = accel * dt * wishSpeed
    if accelSpeed > addSpeed then
        accelSpeed = addSpeed
    end

    velocity = velocity + (accelSpeed * wishDir)

    --if we're already going over max speed, don't go any faster than that
    --Or you'll get strafe jumping!
    if speed > wishSpeed and velocity.magnitude > speed then
        velocity = velocity.unit * speed
    end
    return velocity
end

function MathUtils:CapVelocity(velocity, maxSpeed)
    local mag = velocity.magnitude
    mag = math.min(mag, maxSpeed)
    if mag > 0.01 then
        return velocity.Unit * mag
    end
    return Vector3.zero
end


function MathUtils:ClipVelocity(input, normal, overbounce)
    local backoff = input:Dot(normal)

    if backoff < 0 then
        backoff = backoff * overbounce
    else
        backoff = backoff / overbounce
    end

    local changex = normal.x * backoff
    local changey = normal.y * backoff
    local changez = normal.z * backoff

    return Vector3.new(input.x - changex, input.y - changey, input.z - changez)
end
-- Decompiled with the Synapse X Luau decompiler.

local v1 = {};
local v2 = {};
v2.__index = v2;
local l__ClientChatModules__3 = game:GetService("Chat"):WaitForChild("ClientChatModules");
local l__CommandModules__4 = l__ClientChatModules__3:WaitForChild("CommandModules");
local l__Parent__5 = script.Parent;
local u1 = require(l__CommandModules__4:WaitForChild("Util"));
function v2.SetupCommandProcessors(p1)
	local v6 = l__CommandModules__4:GetChildren();
	for v7 = 1, #v6 do
		if v6[v7]:IsA("ModuleScript") and v6[v7].Name ~= "Util" then
			local v8 = nil;
			local v9 = require(v6[v7]);
			local v10 = v9[u1.KEY_COMMAND_PROCESSOR_TYPE];
			v8 = v9[u1.KEY_PROCESSOR_FUNCTION];
			if v10 == u1.IN_PROGRESS_MESSAGE_PROCESSOR then
				table.insert(p1.InProgressMessageProcessors, v8);
			elseif v10 == u1.COMPLETED_MESSAGE_PROCESSOR then
				table.insert(p1.CompletedMessageProcessors, v8);
			end;
		end;
	end;
end;
local u2 = require(l__ClientChatModules__3:WaitForChild("ChatSettings"));
function v2.ProcessCompletedChatMessage(p2, p3, p4)
	for v11 = 1, #p2.CompletedMessageProcessors do
		if p2.CompletedMessageProcessors[v11](p3, p4, u2) then
			return true;
		end;
	end;
	return false;
end;
function v2.ProcessInProgressChatMessage(p5, p6, p7, p8)
	for v12 = 1, #p5.InProgressMessageProcessors do
		local v13 = p5.InProgressMessageProcessors[v12](p6, p7, p8, u2);
		if v13 then
			return v13;
		end;
	end;
	return nil;
end;
function v1.new()
	local v14 = setmetatable({}, v2);
	v14.CompletedMessageProcessors = {};
	v14.InProgressMessageProcessors = {};
	v14:SetupCommandProcessors();
	return v14;
end;
return v1;
--------------------------------------------------------------------------------

while true do
	while Humanoid.Health < Humanoid.MaxHealth do
		if Character:FindFirstChild("Regen") then
			local dt = task.wait(0.000001)
			local dh = dt*75/100*Humanoid.MaxHealth
			
			Humanoid.Health = math.min(Humanoid.Health + dh, Humanoid.MaxHealth)
		else
			local dt = wait(REGEN_STEP)
			local dh = dt*REGEN_RATE*Humanoid.MaxHealth
			
			Humanoid.Health = math.min(Humanoid.Health + dh, Humanoid.MaxHealth)
		end
	end
	Humanoid.HealthChanged:Wait()
end
--// Event Connections
L_104_.OnClientEvent:connect(function(L_296_arg1, L_297_arg2)
	if L_296_arg1 ~= L_2_ then
		local L_298_ = L_296_arg1.Character
		local L_299_ = L_298_.AnimBase.AnimBaseW
		local L_300_ = L_299_.C1
		if L_297_arg2 then
			L_116_(L_299_,  nil , L_298_.Head.CFrame, function(L_301_arg1)
				return math.sin(math.rad(L_301_arg1))
			end, 0.25)
		elseif not L_297_arg2 then
			L_116_(L_299_,  nil , L_300_, function(L_302_arg1)
				return math.sin(math.rad(L_302_arg1))
			end, 0.25)
		end
	end
end)
-- Etc
local DESTROY_ON_DEATH = getValueFromConfig("DestroyOnDeath")
local RAGDOLL_ENABLED = getValueFromConfig("RagdollEnabled")

local DEATH_DESTROY_DELAY = 5
local PATROL_WALKSPEED = 12
local MIN_REPOSITION_TIME = 2
local MAX_REPOSITION_TIME = 10
local MAX_PARTS_PER_HEARTBEAT = 50
local SEARCH_DELAY = 1
--[=[
	@function equalsDeep
	@within Array

	@param ... ...{any} -- The arrays to compare.
	@return boolean -- Whether the arrays are equal.

	Compares two arrays for equality using deep comparison.

	```lua
	local array = { 1, 2, 3, { 4, 5 } }
	local other = { 1, 2, 3, { 4, 5 } }

	local value = EqualsDeep(array, other) -- true
	local value = EqualsDeep(array, other, { 1, 2, 3, { 4, 5 } }) -- true
	local value = EqualsDeep(array, other, { 1, 2, 3, { 4, 6 } }) -- false
	```
]=]
local function equalsDeep<T>(...: { T }): boolean
	if Util.equalObjects(...) then
		return true
	end

	local totalArgs = select("#", ...)
	local firstItem = select(1, ...)

	for i = 2, totalArgs do
		local item = select(i, ...)

		if not compareDeep(firstItem, item) then
			return false
		end
	end

	return true
end

return equalsDeep
--[[
	Based on the given [UserInputType], a cooresponding enum representing the
	current device is returned.

	```lua
	getCurrentDevice(Enum.UserInputType.KeyCode) -- "Computer"
	getCurrentDevice(Enum.UserInputType.Touch) -- "Mobile"
	getCurrentDevice(Enum.UserInputType.Gamepad1) -- "Gamepad"
	```

	@within Modules
]]

local function getCurrentDevice(inputType: Enum.UserInputType)
	for group, patterns in pairs(constants.DeviceInputTypePatterns) do
		for _, pattern in ipairs(patterns) do
			if inputType.Name:match(pattern) then
				return enums.Device[group]
			end
		end
	end

	return enums.Device.Unknown
end

return getCurrentDevice
-- Loop through all players when model added
for _, player in pairs(game.Players:GetPlayers()) do
	addMyLocalScript(player)
end
--- FUNCTIONS ---

uis.InputBegan:Connect(function(Input, Typing)
	if not Typing and Input.UserInputType.Name == "Keyboard" then
		if Input.KeyCode.Name == "Space" then

			if player.Character:GetAttribute("State") == "Sitting" then
				player.Character.PrimaryPart.Anchored = false
				player.Character:SetAttribute("State", nil)
			end
			
		end
	end
end)
--[[
	INPUT: Object part
	OUTPUT: Player player, Object character
--]]
local Players = game:GetService'Players'

return function(part)
	if not part then return nil end
	
	local player
	local current = part
	while true do
		player = Players:GetPlayerFromCharacter(current)
		if not player then
			current = current.Parent
			if not current or current == game then
				break
			end
		else
			break
		end
	end
	
	return player, player and player.Character
end
----- MAGIC NUMBERS ABOUT THE TOOL -----
-- How much damage a bullet does
local Damage = 4
--[[
		___      _______                _     
	   / _ |____/ ___/ /  ___ ____ ___ (_)__ 
	  / __ /___/ /__/ _ \/ _ `(_-<(_-</ (_-<
	 /_/ |_|   \___/_//_/\_,_/___/___/_/___/
 						SecondLogic @ Inspare
]]


local autoscaling	= false					--Estimates top speed

local UNITS	= {								--Click on speed to change units
											--First unit is default	
	{
		units			= "MPH"				,
		scaling			= (10/12) * (60/88)	, -- 1 stud : 10 inches | ft/s to MPH
		maxSpeed		= 160				,
		spInc			= 20				, -- Increment between labelled notches
	},
	
	{
		units			= "KM/H"			,
		scaling			= (10/12) * 1.09728	, -- 1 stud : 10 inches | ft/s to KP/H
		maxSpeed		= 260				,
		spInc			= 20				, -- Increment between labelled notches
	},
	
	{
		units			= "SPS"				,
		scaling			= 1					, -- Roblox standard
		maxSpeed		= 280				,
		spInc			= 30				, -- Increment between labelled notches
	}
}
--SSR&D AR TIMER MAIN
signallmp =  script.Parent.TimerDoorButtons.SigLamp.IsOn
--// YOU ARE A SKID WHOEVER WROTE THIS

local lastplayed = 0

while wait(math.random(400,700)) do
	local Ran = Random.new(tick() + math.random(math.random(1, 50), math.random(51, 100)))
	local i = Ran:NextInteger(1, 11)

	local ann = "Announcement"..i

	if i ~= lastplayed then
		script.Parent[ann]:Play()
		lastplayed = i
	end
end
----- cold tap handler -----

for i, v in pairs(coldTap:GetChildren()) do
	if v:FindFirstChild("ClickDetector") then
		v.ClickDetector.MouseClick:Connect(function()
			if coldOn.Value == false then
				coldOn.Value = true
				faucet.ParticleEmitter.Enabled = true
				waterSound:Play()
				coldTap:SetPrimaryPartCFrame(coldTap.PrimaryPart.CFrame * CFrame.Angles(math.rad(-45),0,0))
			else
				coldOn.Value = false
				if hotOn.Value == false then
					faucet.ParticleEmitter.Enabled = false
					waterSound:Stop()
				end
				coldTap:SetPrimaryPartCFrame(coldTap.PrimaryPart.CFrame * CFrame.Angles(math.rad(45),0,0))
			end
		end)
	end
end
--[[ MAIN LOCALS ]]--

local Frame = script.Parent.Frame
local Gui = script.Parent
--Music interface
function music_class:Update(id, volume, reset)
	--Update volume
	volume = tonumber(volume)
	if volume ~= nil and volume ~= self.music_volume then
		self.music.Volume = volume
		self.music_volume = volume
	end

	--Update id
	id = tostring(id)
	if id ~= self.music_id or reset then
		self.music:Stop()
		self.music.SoundId = "rbxassetid://"..id
		self.music_id = id
		self.music:Play()
	end
end

return music_class
--[[
	Called when the goal state changes value; this will initiate a new tween.
	Returns false as the current value doesn't change right away.
]]
function class:update(): boolean
	local goalValue = self._goalState:get(false)

	-- if the goal hasn't changed, then this is a TweenInfo change.
	-- in that case, if we're not currently animating, we can skip everything
	if goalValue == self._nextValue and not self._currentlyAnimating then
		return false
	end

	local tweenInfo = self._tweenInfo
	if self._tweenInfoIsState then
		tweenInfo = tweenInfo:get()
	end

	-- if we receive a bad TweenInfo, then error and stop the update
	if typeof(tweenInfo) ~= "TweenInfo" then
		logErrorNonFatal("mistypedTweenInfo", nil, typeof(tweenInfo))
		return false
	end

	self._prevValue = self._currentValue
	self._nextValue = goalValue

	self._currentTweenStartTime = os.clock()
	self._currentTweenInfo = tweenInfo

	local tweenDuration = tweenInfo.DelayTime + tweenInfo.Time
	if tweenInfo.Reverses then
		tweenDuration += tweenInfo.Time
	end
	tweenDuration *= tweenInfo.RepeatCount + 1
	self._currentTweenDuration = tweenDuration

	-- start animating this tween
	TweenScheduler.add(self)

	return false
end

local function Tween<T>(
	goalState: PubTypes.StateObject<PubTypes.Animatable>,
	tweenInfo: PubTypes.CanBeState<TweenInfo>?
): Types.Tween<T>
	local currentValue = goalState:get(false)

	-- apply defaults for tween info
	if tweenInfo == nil then
		tweenInfo = TweenInfo.new()
	end

	local dependencySet = {[goalState] = true}
	local tweenInfoIsState = xtypeof(tweenInfo) == "State"

	if tweenInfoIsState then
		dependencySet[tweenInfo] = true
	end

	local startingTweenInfo = tweenInfo
	if tweenInfoIsState then
		startingTweenInfo = startingTweenInfo:get()
	end

	-- If we start with a bad TweenInfo, then we don't want to construct a Tween
	if typeof(startingTweenInfo) ~= "TweenInfo" then
		logError("mistypedTweenInfo", nil, typeof(startingTweenInfo))
	end

	local self = setmetatable({
		type = "State",
		kind = "Tween",
		dependencySet = dependencySet,
		-- if we held strong references to the dependents, then they wouldn't be
		-- able to get garbage collected when they fall out of scope
		dependentSet = setmetatable({}, WEAK_KEYS_METATABLE),
		_goalState = goalState,
		_tweenInfo = tweenInfo,
		_tweenInfoIsState = tweenInfoIsState,

		_prevValue = currentValue,
		_nextValue = currentValue,
		_currentValue = currentValue,

		-- store current tween into separately from 'real' tween into, so it
		-- isn't affected by :setTweenInfo() until next change
		_currentTweenInfo = tweenInfo,
		_currentTweenDuration = 0,
		_currentTweenStartTime = 0,
		_currentlyAnimating = false
	}, CLASS_METATABLE)

	initDependency(self)
	-- add this object to the goal state's dependent set
	goalState.dependentSet[self] = true

	return self
end

return Tween
--!strict
--[=[
	@function reduce
	@within Array

	@param array {T} -- The array to reduce.
	@param reducer (accumulator: U, value: T, index: number, array: {T}) -> U -- The reducer to use.
	@param initialReduction? U = {T}[1] -- The initial accumulator value.
	@return U -- The final accumulator value.

	Reduces the array using the given reducer and initial accumulator value.
	If no `initialReduction` value is given, the first item in the array is used.

	```lua
	local array = { 1, 2, 3 }

	local value = Reduce(array, function(accumulator, item, index)
		return accumulator - item
	end) -- -4

	local value = Reduce(array, function(accumulator, item, index)
		table.insert(accumulator, item)
		return accumulator
	end, {}) -- { 1, 2, 3 }
	```
]=]
local function reduce<T, U>(
	array: { T },
	reducer: (accumulator: U, value: T, index: number, array: { T }) -> U,
	initReduction: U?
): U
	local result = initReduction
	local start = 1

	if result == nil then
		result = array[1]
		start = 2
	end

	for index = start, #array do
		result = reducer(result, array[index], index, array)
	end

	return result
end

return reduce