local a=newproxy(true)SupportLibrary.Blank=a;(getmetatable(a)).__tostring=function()return"\083\121\109\098\111\108\040\066\108\097\110\107\041"end function SupportLibrary.MergeWithBlanks(u,...)local O={...}for O,C in ipairs(O)do for O,C in pairs(C)do if C==a then u[O]=nil else u[O]=C end end end return u end function SupportLibrary.GetAllDescendants(a)local u={}for a,O in pairs(a:GetChildren())do table.insert(u,O)for a,O in pairs(SupportLibrary.GetAllDescendants(O))do table.insert(u,O)end end return u end function SupportLibrary.GetDescendantsWhichAreA(a,u)local O={}for a,C in pairs(a:GetDescendants())do if C:IsA(u)then O[#O+1]=C end end return O end function SupportLibrary.FilterArray(a,u)local O={}for a,C in ipairs(a)do if u(C,a)then table.insert(O,C)end end return O end function SupportLibrary.FilterMap(a,u)local O={}for a,C in ipairs(a)do if u(C,a)then O[a]=C end end return O end function SupportLibrary.GetDescendantCount(a)local u=0 for a,O in pairs(a:GetChildren())do u=u+1 u=u+SupportLibrary.GetDescendantCount(O)end return u end function SupportLibrary.CloneParts(a)local u={}for a,O in pairs(a)do u[a]=O:Clone()end return u end function SupportLibrary.SplitString(a,u)local O={}local C=("\040\091\094\037\115\093\043\041"):format(u)a:gsub(C,function(a)table.insert(O,a)end)return O end function SupportLibrary.GetChildOfClass(a,u,O)if not O then for a,O in pairs(a:GetChildren())do if O.ClassName==u then return O end end else for a,O in pairs(a:GetChildren())do if O:IsA(u)then return O end end end return nil end function SupportLibrary.GetChildrenOfClass(a,u,O)local C={}if not O then for a,O in pairs(a:GetChildren())do if O.ClassName==u then table.insert(C,O)end end else for a,O in pairs(a:GetChildren())do if O:IsA(u)then table.insert(C,O)end end end return C end function SupportLibrary.HSVToRGB(a,u,O)if u==0 then return O end local C=math.floor(a/60)local p=a/60-C local d=O*(1-u)local b=O*(1-u*p)local k=O*(1-u*(1-p))if C==0 then return O,k,d elseif C==1 then return b,O,d elseif C==2 then return d,O,k elseif C==3 then return d,b,O elseif C==4 then return k,d,O elseif C==5 then return O,d,b end end function SupportLibrary.RGBToHSV(a,u,O)local C,p,d local b=math.min(a,u,O)local k=math.max(a,u,O)d=k local M=k-b if k~=0 then p=M/k else p=0 C=-1 return C,p,d end if a==k then C=(u-O)/M elseif u==k then C=2+(O-a)/M else C=4+(a-u)/M end C=C*60 if C<0 then C=C+360 end return C,p,d end function SupportLibrary.IdentifyCommonItem(a)local u=nil for a,O in pairs(a)do if a==1 then u=O else if O~=u then return nil end end end return u end function SupportLibrary.IdentifyCommonProperty(a,u)local O={}for a,C in pairs(a)do table.insert(O,C[u])end return SupportLibrary.IdentifyCommonItem(O)end function SupportLibrary.GetPartCorners(a)local u=table.insert local O=(CFrame.new()).toWorldSpace local C=CFrame.new local p=a.CFrame local d,b,k=a.Size.x/2,a.Size.y/2,a.Size.z/2 local M={}u(M,O(p,C(d,b,k)))u(M,O(p,C(-d,b,k)))u(M,O(p,C(d,-b,k)))u(M,O(p,C(d,b,-k)))u(M,O(p,C(-d,b,-k)))u(M,O(p,C(-d,-b,k)))u(M,O(p,C(d,-b,-k)))u(M,O(p,C(-d,-b,-k)))return M end function SupportLibrary.ImportServices()local a=getfenv(2)a.Workspace=Game:GetService("\087\111\114\107\115\112\097\099\101")a.Players=Game:GetService("\080\108\097\121\101\114\115")a.MarketplaceService=Game:GetService("\077\097\114\107\101\116\112\108\097\099\101\083\101\114\118\105\099\101")a.ContentProvider=Game:GetService("\067\111\110\116\101\110\116\080\114\111\118\105\100\101\114")a.SoundService=Game:GetService("\083\111\117\110\100\083\101\114\118\105\099\101")a.UserInputService=Game:GetService("\085\115\101\114\073\110\112\117\116\083\101\114\118\105\099\101")a.SelectionService=Game:GetService("\083\101\108\101\099\116\105\111\110")a.CoreGui=Game:GetService("\067\111\114\101\071\117\105")a.HttpService=Game:GetService("\072\116\116\112\083\101\114\118\105\099\101")a.ChangeHistoryService=Game:GetService("\067\104\097\110\103\101\072\105\115\116\111\114\121\083\101\114\118\105\099\101")a.ReplicatedStorage=Game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")a.GroupService=Game:GetService("\071\114\111\117\112\083\101\114\118\105\099\101")a.ServerScriptService=Game:GetService("\083\101\114\118\101\114\083\099\114\105\112\116\083\101\114\118\105\099\101")a.ServerStorage=Game:GetService("\083\101\114\118\101\114\083\116\111\114\097\103\101")a.StarterGui=Game:GetService("\083\116\097\114\116\101\114\071\117\105")a.RunService=Game:GetService("\082\117\110\083\101\114\118\105\099\101")end function SupportLibrary.GetListMembers(a,u)local O={}for a,C in ipairs(a)do O[a]=C[u]end return O end function SupportLibrary.GetMemberMap(a,u)local O={}for a,C in ipairs(a)do O[C]=C[u]end return O end function SupportLibrary.AddUserInputListener(a,u,O,C)local p={}if type(u)=="\115\116\114\105\110\103"then p[u]=true elseif type(u)=="\116\097\098\108\101"then p=SupportLibrary.FlipTable(u)end return(Game:GetService("\085\115\101\114\073\110\112\117\116\083\101\114\118\105\099\101"))["\073\110\112\117\116"..a]:Connect(function(a,u)if u and not O then return end if not p[a.UserInputType.Name]then return end if InputType==Enum.UserInputType.Keyboard and(Game:GetService("\085\115\101\114\073\110\112\117\116\083\101\114\118\105\099\101")):GetFocusedTextBox()then return end C(a)end)end function SupportLibrary.AddGuiInputListener(a,u,O,C,p)local d={}if type(O)=="\115\116\114\105\110\103"then d[O]=true elseif type(O)=="\116\097\098\108\101"then d=SupportLibrary.FlipTable(O)end return a["\073\110\112\117\116"..u]:Connect(function(a,u)if u and not C then return end if not d[a.UserInputType.Name]then return end p(a)end)end function SupportLibrary.AreKeysPressed(...)local a=0 local u=SupportLibrary.GetListMembers((Game:GetService("\085\115\101\114\073\110\112\117\116\083\101\114\118\105\099\101")):GetKeysPressed(),"\075\101\121\067\111\100\101")for O,C in pairs({...})do if SupportLibrary.IsInTable(u,C)then a=a+1 end end return a==#{...}end function SupportLibrary.ConcatTable(a,...)local u={...}for u,O in ipairs(u)do for u,O in ipairs(O)do table.insert(a,O)end end return a end function SupportLibrary.ClearTable(a)for u in pairs(a)do a[u]=nil end return a end function SupportLibrary.Values(a)local u={}for a,O in pairs(a)do table.insert(u,O)end return u end function SupportLibrary.Keys(a)local u={}for a in pairs(a)do table.insert(u,a)end return u end function SupportLibrary.Call(a,...)local u={...}return function(...)return a(unpack(SupportLibrary.ConcatTable({},u,{...})))end end function SupportLibrary.Trim(a)return a:gsub("\094\037\115\042\040\046-\041\037\115\042\036","\037\049")end function SupportLibrary.ChainCall(...)local a={...}return function(...)local u={...}for a,O in ipairs(a)do u={O(unpack(u))}end return unpack(u)end end function SupportLibrary.CountKeys(a)local u=0 for a in pairs(a)do u=u+1 end return u end function SupportLibrary.Slice(a,u,O)local C={}for u=u,O,1 do table.insert(C,a[u])end return C end function SupportLibrary.FlipTable(a)local u={}for a,O in pairs(a)do u[O]=a end return u end function SupportLibrary.ScheduleRecurringTask(a,u)local O={Running=true,Stop=function(a)a.Running=false end,TaskFunction=a;Interval=u};(coroutine.wrap(function(a)while wait(a.Interval)and a.Running do a.TaskFunction()end end))(O)return O end function SupportLibrary.Loop(a,u,...)local O={...}local C=true local p=function()C=nil end;(coroutine.wrap(function()while wait(a)and C do u(unpack(O))end end))()return p end function SupportLibrary.Clamp(a,u,O)if u and a<u then a=u elseif O and a>O then a=O end return a end function SupportLibrary.ReverseTable(a)local u={}for O,C in ipairs(a)do u[(#a-O)+1]=C end return u end function SupportLibrary.CreateConsecutiveCallDeferrer(a)local u local function O()local O=tick()u=O wait(a)return u==O end return O end return SupportLibrary

local Blank = newproxy(true)
SupportLibrary.Blank = Blank
getmetatable(Blank).__tostring = function ()
	return 'Symbol(Blank)'
end

function SupportLibrary.MergeWithBlanks(Target, ...)
	-- Copies members of the given tables into the specified target table, including blank values

	local Tables = { ... }

	-- Copy members from each table into target
	for TableOrder, Table in ipairs(Tables) do
		for Key, Value in pairs(Table) do
			if Value == Blank then
				Target[Key] = nil
			else
				Target[Key] = Value
			end
		end
	end

	-- Return target
	return Target
end

function SupportLibrary.GetAllDescendants(Parent)
	-- Recursively gets all the descendants of `Parent` and returns them

	local Descendants = {};

	for _, Child in pairs(Parent:GetChildren()) do

		-- Add the direct descendants of `Parent`
		table.insert(Descendants, Child);

		-- Add the descendants of each child
		for _, Subchild in pairs(SupportLibrary.GetAllDescendants(Child)) do
			table.insert(Descendants, Subchild);
		end;

	end;

	return Descendants;
end;

function SupportLibrary.GetDescendantsWhichAreA(Object, Class)
	-- Returns descendants of `Object` which match `Class`

	local Matches = {}

	-- Check each descendant
	for _, Descendant in pairs(Object:GetDescendants()) do
		if Descendant:IsA(Class) then
			Matches[#Matches + 1] = Descendant
		end
	end

	-- Return matches
	return Matches

end

function SupportLibrary.FilterArray(Array, Callback)
	-- Returns a filtered copy of `Array` based on the filter `Callback`

	local FilteredArray = {}

	-- Add items from `Array` that `Callback` returns `true` on
	for Key, Value in ipairs(Array) do
		if Callback(Value, Key) then
			table.insert(FilteredArray, Value)
		end
	end

	return FilteredArray
end

function SupportLibrary.FilterMap(Map, Callback)
	-- Returns a filtered copy of `Map` based on the filter `Callback`

	local FilteredMap = {}

	-- Add items from `Map` that `Callback` returns `true` on
	for Key, Value in ipairs(Map) do
		if Callback(Value, Key) then
			FilteredMap[Key] = Value
		end
	end

	return FilteredMap
end

function SupportLibrary.GetDescendantCount(Parent)
	-- Recursively gets a count of all the descendants of `Parent` and returns them

	local Count = 0;

	for _, Child in pairs(Parent:GetChildren()) do

		-- Count the direct descendants of `Parent`
		Count = Count + 1;

		-- Count and add the descendants of each child
		Count = Count + SupportLibrary.GetDescendantCount(Child);

	end;

	return Count;
end;

function SupportLibrary.CloneParts(Parts)
	-- Returns a table of cloned `Parts`

	local Clones = {};

	-- Copy the parts into `Clones`
	for Index, Part in pairs(Parts) do
		Clones[Index] = Part:Clone();
	end;

	return Clones;
end;

function SupportLibrary.SplitString(String, Delimiter)
	-- Returns a table of string `String` split by pattern `Delimiter`

	local StringParts = {};
	local Pattern = ('([^%s]+)'):format(Delimiter);

	-- Capture each separated part
	String:gsub(Pattern, function (Part)
		table.insert(StringParts, Part);
	end);

	return StringParts;
end;

function SupportLibrary.GetChildOfClass(Parent, ClassName, Inherit)
	-- Returns the first child of `Parent` that is of class `ClassName`
	-- or nil if it couldn't find any

	-- Look for a child of `Parent` of class `ClassName` and return it
	if not Inherit then
		for _, Child in pairs(Parent:GetChildren()) do
			if Child.ClassName == ClassName then
				return Child;
			end;
		end;
	else
		for _, Child in pairs(Parent:GetChildren()) do
			if Child:IsA(ClassName) then
				return Child;
			end;
		end;
	end;

	return nil;
end;

function SupportLibrary.GetChildrenOfClass(Parent, ClassName, Inherit)
	-- Returns a table containing the children of `Parent` that are
	-- of class `ClassName`

	local Matches = {};

	if not Inherit then
		for _, Child in pairs(Parent:GetChildren()) do
			if Child.ClassName == ClassName then
				table.insert(Matches, Child);
			end;
		end;
	else
		for _, Child in pairs(Parent:GetChildren()) do
			if Child:IsA(ClassName) then
				table.insert(Matches, Child);
			end;
		end;
	end;

	return Matches;
end;

function SupportLibrary.HSVToRGB(Hue, Saturation, Value)
	-- Returns the RGB equivalent of the given HSV-defined color
	-- (adapted from some code found around the web)

	-- If it's achromatic, just return the value
	if Saturation == 0 then
		return Value;
	end;

	-- Get the hue sector
	local HueSector = math.floor(Hue / 60);
	local HueSectorOffset = (Hue / 60) - HueSector;

	local P = Value * (1 - Saturation);
	local Q = Value * (1 - Saturation * HueSectorOffset);
	local T = Value * (1 - Saturation * (1 - HueSectorOffset));

	if HueSector == 0 then
		return Value, T, P;
	elseif HueSector == 1 then
		return Q, Value, P;
	elseif HueSector == 2 then
		return P, Value, T;
	elseif HueSector == 3 then
		return P, Q, Value;
	elseif HueSector == 4 then
		return T, P, Value;
	elseif HueSector == 5 then
		return Value, P, Q;
	end;
end;

function SupportLibrary.RGBToHSV(Red, Green, Blue)
	-- Returns the HSV equivalent of the given RGB-defined color
	-- (adapted from some code found around the web)

	local Hue, Saturation, Value;

	local MinValue = math.min(Red, Green, Blue);
	local MaxValue = math.max(Red, Green, Blue);

	Value = MaxValue;

	local ValueDelta = MaxValue - MinValue;

	-- If the color is not black
	if MaxValue ~= 0 then
		Saturation = ValueDelta / MaxValue;

	-- If the color is purely black
	else
		Saturation = 0;
		Hue = -1;
		return Hue, Saturation, Value;
	end;

	if Red == MaxValue then
		Hue = (Green - Blue) / ValueDelta;
	elseif Green == MaxValue then
		Hue = 2 + (Blue - Red) / ValueDelta;
	else
		Hue = 4 + (Red - Green) / ValueDelta;
	end;

	Hue = Hue * 60;
	if Hue < 0 then
		Hue = Hue + 360;
	end;

	return Hue, Saturation, Value;
end;

function SupportLibrary.IdentifyCommonItem(Items)
	-- Returns the common item in table `Items`, or `nil` if
	-- they vary

	local CommonItem = nil;

	for ItemIndex, Item in pairs(Items) do

		-- Set the initial item to compare against
		if ItemIndex == 1 then
			CommonItem = Item;

		-- Check if this item is the same as the rest
		else
			-- If it isn't the same, there is no common item, so just stop right here
			if Item ~= CommonItem then
				return nil;
			end;
		end;

	end;

	-- Return the common item
	return CommonItem;
end;

function SupportLibrary.IdentifyCommonProperty(Items, Property)
	-- Returns the common `Property` value in the instances given in `Items`

	local PropertyVariations = {};

	-- Capture all the variations of the property value
	for _, Item in pairs(Items) do
		table.insert(PropertyVariations, Item[Property]);
	end;

	-- Return the common property value
	return SupportLibrary.IdentifyCommonItem(PropertyVariations);

end;

function SupportLibrary.GetPartCorners(Part)
	-- Returns a table of the given part's corners' CFrames

	-- Make references to functions called a lot for efficiency
	local Insert = table.insert;
	local ToWorldSpace = CFrame.new().toWorldSpace;
	local NewCFrame = CFrame.new;

	-- Get info about the part
	local PartCFrame = Part.CFrame;
	local SizeX, SizeY, SizeZ = Part.Size.x / 2, Part.Size.y / 2, Part.Size.z / 2;

	-- Get each corner
	local Corners = {};
	Insert(Corners, ToWorldSpace(PartCFrame, NewCFrame(SizeX, SizeY, SizeZ)));
	Insert(Corners, ToWorldSpace(PartCFrame, NewCFrame(-SizeX, SizeY, SizeZ)));
	Insert(Corners, ToWorldSpace(PartCFrame, NewCFrame(SizeX, -SizeY, SizeZ)));
	Insert(Corners, ToWorldSpace(PartCFrame, NewCFrame(SizeX, SizeY, -SizeZ)));
	Insert(Corners, ToWorldSpace(PartCFrame, NewCFrame(-SizeX, SizeY, -SizeZ)));
	Insert(Corners, ToWorldSpace(PartCFrame, NewCFrame(-SizeX, -SizeY, SizeZ)));
	Insert(Corners, ToWorldSpace(PartCFrame, NewCFrame(SizeX, -SizeY, -SizeZ)));
	Insert(Corners, ToWorldSpace(PartCFrame, NewCFrame(-SizeX, -SizeY, -SizeZ)));

	return Corners;
end;

function SupportLibrary.ImportServices()
	-- Adds references to common services into the calling environment

	-- Get the calling environment
	local CallingEnvironment = getfenv(2);

	-- Add the services
	CallingEnvironment.Workspace = Game:GetService 'Workspace';
	CallingEnvironment.Players = Game:GetService 'Players';
	CallingEnvironment.MarketplaceService = Game:GetService 'MarketplaceService';
	CallingEnvironment.ContentProvider = Game:GetService 'ContentProvider';
	CallingEnvironment.SoundService = Game:GetService 'SoundService';
	CallingEnvironment.UserInputService = Game:GetService 'UserInputService';
	CallingEnvironment.SelectionService = Game:GetService 'Selection';
	CallingEnvironment.CoreGui = Game:GetService 'CoreGui';
	CallingEnvironment.HttpService = Game:GetService 'HttpService';
	CallingEnvironment.ChangeHistoryService = Game:GetService 'ChangeHistoryService';
	CallingEnvironment.ReplicatedStorage = Game:GetService 'ReplicatedStorage';
	CallingEnvironment.GroupService = Game:GetService 'GroupService';
	CallingEnvironment.ServerScriptService = Game:GetService 'ServerScriptService';
	CallingEnvironment.ServerStorage = Game:GetService 'ServerStorage';
	CallingEnvironment.StarterGui = Game:GetService 'StarterGui';
	CallingEnvironment.RunService = Game:GetService 'RunService';
end;

function SupportLibrary.GetListMembers(List, MemberName)
	-- Gets the given member for each object in the given list table

	local Members = {}

	-- Collect the member values for each item in the list
	for Key, Item in ipairs(List) do
		Members[Key] = Item[MemberName]
	end

	-- Return the members
	return Members

end

function SupportLibrary.GetMemberMap(List, MemberName)
	-- Maps the given items' specified members to each item

	local Map = {}

	-- Collect member values
	for Key, Item in ipairs(List) do
		Map[Item] = Item[MemberName]
	end

	-- Return map
	return Map

end

function SupportLibrary.AddUserInputListener(InputState, InputTypeFilter, CatchAll, Callback)
	-- Connects to the given user input event and takes care of standard boilerplate code

	-- Create input type whitelist
	local InputTypes = {}
	if type(InputTypeFilter) == 'string' then
		InputTypes[InputTypeFilter] = true
	elseif type(InputTypeFilter) == 'table' then
		InputTypes = SupportLibrary.FlipTable(InputTypeFilter)
	end

	-- Create a UserInputService listener based on the given `InputState`
	return Game:GetService('UserInputService')['Input' .. InputState]:Connect(function (Input, GameProcessedEvent)

		-- Make sure this input was not captured by the client (unless `CatchAll` is enabled)
		if GameProcessedEvent and not CatchAll then
			return;
		end;

		-- Make sure this is the right input type
		if not InputTypes[Input.UserInputType.Name] then
			return;
		end;

		-- Make sure any key input did not occur while typing into a UI
		if InputType == Enum.UserInputType.Keyboard and Game:GetService('UserInputService'):GetFocusedTextBox() then
			return;
		end;

		-- Call back upon passing all conditions
		Callback(Input);

	end);

end;

function SupportLibrary.AddGuiInputListener(Gui, InputState, InputTypeFilter, CatchAll, Callback)
	-- Connects to the given GUI user input event and takes care of standard boilerplate code

	-- Create input type whitelist
	local InputTypes = {}
	if type(InputTypeFilter) == 'string' then
		InputTypes[InputTypeFilter] = true
	elseif type(InputTypeFilter) == 'table' then
		InputTypes = SupportLibrary.FlipTable(InputTypeFilter)
	end

	-- Create a UserInputService listener based on the given `InputState`
	return Gui['Input' .. InputState]:Connect(function (Input, GameProcessedEvent)

		-- Make sure this input was not captured by the client (unless `CatchAll` is enabled)
		if GameProcessedEvent and not CatchAll then
			return;
		end;

		-- Make sure this is the right input type
		if not InputTypes[Input.UserInputType.Name] then
			return;
		end;

		-- Call back upon passing all conditions
		Callback(Input);

	end);

end;

function SupportLibrary.AreKeysPressed(...)
	-- Returns whether the given keys are pressed

	local RequestedKeysPressed = 0;

	-- Get currently pressed keys
	local PressedKeys = SupportLibrary.GetListMembers(Game:GetService('UserInputService'):GetKeysPressed(), 'KeyCode');

	-- Go through each requested key
	for _, Key in pairs({ ... }) do

		-- Count requested keys that are pressed
		if SupportLibrary.IsInTable(PressedKeys, Key) then
			RequestedKeysPressed = RequestedKeysPressed + 1;
		end;

	end;

	-- Return whether all the requested keys are pressed or not
	return RequestedKeysPressed == #{...};

end;

function SupportLibrary.ConcatTable(TargetTable, ...)
	-- Inserts all values from given source tables into target

	local SourceTables = { ... }

	-- Insert values from each source table into target
	for TableOrder, SourceTable in ipairs(SourceTables) do
		for Key, Value in ipairs(SourceTable) do
			table.insert(TargetTable, Value)
		end
	end

	-- Return the destination table
	return TargetTable
end

function SupportLibrary.ClearTable(Table)
	-- Clears out every value in `Table`

	-- Clear each index
	for Index in pairs(Table) do
		Table[Index] = nil;
	end;

	-- Return the given table
	return Table;
end;

function SupportLibrary.Values(Table)
	-- Returns all the values in the given table

	local Values = {};

	-- Go through each key and get each value
	for _, Value in pairs(Table) do
		table.insert(Values, Value);
	end;

	-- Return the values
	return Values;
end;

function SupportLibrary.Keys(Table)
	-- Returns all the keys in the given table

	local Keys = {};

	-- Go through each key and get each value
	for Key in pairs(Table) do
		table.insert(Keys, Key);
	end;

	-- Return the values
	return Keys;
end;

function SupportLibrary.Call(Function, ...)
	-- Returns a callback to `Function` with the given arguments
	local Args = { ... }
	return function (...)
		return Function(unpack(
			SupportLibrary.ConcatTable({}, Args, { ... })
		))
	end
end

function SupportLibrary.Trim(String)
	-- Returns a trimmed version of `String` (adapted from code from lua-users)
	return (String:gsub("^%s*(.-)%s*$", "%1"));
end

function SupportLibrary.ChainCall(...)
	-- Returns function that passes arguments through given functions and returns the final result

	-- Get the given chain of functions
	local Chain = { ... };

	-- Return the chaining function
	return function (...)

		-- Get arguments
		local Arguments = { ... };

		-- Go through each function and store the returned data to reuse in the next function's arguments 
		for _, Function in ipairs(Chain) do
			Arguments = { Function(unpack(Arguments)) };
		end;

		-- Return the final returned data
		return unpack(Arguments);

	end;

end;

function SupportLibrary.CountKeys(Table)
	-- Returns the number of keys in `Table`

	local Count = 0;

	-- Count each key
	for _ in pairs(Table) do
		Count = Count + 1;
	end;

	-- Return the count
	return Count;

end;

function SupportLibrary.Slice(Table, Start, End)
	-- Returns values from `Start` to `End` in `Table`

	local Slice = {};

	-- Go through the given indices
	for Index = Start, End do
		table.insert(Slice, Table[Index]);
	end;

	-- Return the slice
	return Slice;

end;

function SupportLibrary.FlipTable(Table)
	-- Returns a table with keys and values in `Table` swapped

	local FlippedTable = {};

	-- Flip each key and value
	for Key, Value in pairs(Table) do
		FlippedTable[Value] = Key;
	end;

	-- Return the flipped table
	return FlippedTable;

end;

function SupportLibrary.ScheduleRecurringTask(TaskFunction, Interval)
	-- Repeats `Task` every `Interval` seconds until stopped

	-- Create a task object
	local Task = {

		-- A switch determining if it's running or not
		Running = true;

		-- A function to stop this task
		Stop = function (Task)
			Task.Running = false;
		end;

		-- References to the task function and set interval
		TaskFunction = TaskFunction;
		Interval = Interval;

	};

	coroutine.wrap(function (Task)

		-- Repeat the task
		while wait(Task.Interval) and Task.Running do
			Task.TaskFunction();
		end;

	end)(Task);

	-- Return the task object
	return Task;

end;

function SupportLibrary.Loop(Interval, Function, ...)
	-- Calls the given function repeatedly at the specified interval until stopped

	local Args = { ... }

	-- Create state
	local Running = true
	local Stop = function ()
		Running = nil
	end

	-- Start loop
	coroutine.wrap(function ()
		while wait(Interval) and Running do
			Function(unpack(Args))
		end
	end)()

	-- Return stopping callback
	return Stop
end

function SupportLibrary.Clamp(Number, Minimum, Maximum)
	-- Returns the given number, clamped according to the provided min/max

	-- Clamp the number
	if Minimum and Number < Minimum then
		Number = Minimum;
	elseif Maximum and Number > Maximum then
		Number = Maximum;
	end;

	-- Return the clamped number
	return Number;

end;

function SupportLibrary.ReverseTable(Table)
	-- Returns a new table with values in the opposite order

	local ReversedTable = {};

	-- Copy each value at the opposite key
	for Index, Value in ipairs(Table) do
		ReversedTable[#Table - Index + 1] = Value;
	end;

	-- Return the reversed table
	return ReversedTable;

end;

function SupportLibrary.CreateConsecutiveCallDeferrer(MaxInterval)
	-- Returns a callback for determining whether to execute consecutive calls

	local LastCallTime
	local function ShouldExecuteCall()

		-- Mark latest call time
		local CallTime = tick()
		LastCallTime = CallTime

		-- Indicate whether call still latest
		wait(MaxInterval)
		return LastCallTime == CallTime

	end

	-- Return callback
	return ShouldExecuteCall

end

return SupportLibrary;
