local a={[Enum.NormalId.Top]="\089";[Enum.NormalId.Bottom]="\089",[Enum.NormalId.Front]="\090",[Enum.NormalId.Back]="\090",[Enum.NormalId.Left]="\088";[Enum.NormalId.Right]="\088"}function ShowHandles()if not Connections.AutofocusHandle then Connections.AutofocusHandle=Selection.FocusChanged:Connect(ShowHandles)end if ResizeTool.Handles then ResizeTool.Handles:SetAdornee(Selection.Focus)return end local a local function D()Core.Targeting.CancelSelecting()HandleResizing=true InitialState=PreparePartsForResizing()TrackChange()if Core.Mode=="\084\111\111\108"then a=Security.GetPermissions(Security.GetSelectionAreas(Selection.Parts),Core.Player)end end local function r(D,r)if not HandleResizing then return end r=GetIncrementMultiple(r,ResizeTool.Increment)local s,Y=ResizePartsByFace(D,r,ResizeTool.Directions,InitialState)if not s then ResizePartsByFace(D,Y,ResizeTool.Directions,InitialState)end if ResizeTool.UI then ResizeTool.UI.Changes.Text.Text="\114\101\115\105\122\101\100 "..(Support.Round(math.abs(Y or r),3).." \115\116\117\100\115")end if Core.Mode=="\084\111\111\108"and Security.ArePartsViolatingAreas(Selection.Parts,Core.Player,false,a)then for a,D in pairs(InitialState)do a.Size=D.Size a.CFrame=D.CFrame end end end local function s()if not HandleResizing then return end HandleResizing=false Core.Targeting.CancelSelecting()for a,D in pairs(InitialState)do a:MakeJoints()a.CanCollide=D.CanCollide a.Anchored=D.Anchored end RegisterChange()end local Y=require(Libraries:WaitForChild("\072\097\110\100\108\101\115"))ResizeTool.Handles=Y.new({Color=ResizeTool.Color.Color,Parent=Core.UIContainer;Adornee=Selection.Focus,OnDragStart=D,OnDrag=r,OnDragEnd=s})end function HideHandles()if not ResizeTool.Handles then return end ResizeTool.Handles=ResizeTool.Handles:Destroy()ClearConnection("\065\117\116\111\102\111\099\117\115\072\097\110\100\108\101")end function ResizePartsByFace(D,r,s,Y)if s=="\066\111\116\104"then r=r*2 end local N=AxisSizeMultipliers[D]local o=r*N local P=a[D]local T,V,S,O for a,D in pairs(Y)do local s=D.Size[P]+r if s<.049999 and(not T or T and s<T)then T,V=s,a elseif s>2048 and(not S or S and s>S)then S,O=s,a end end if T then local a=Y[V].Size[P]local D=a-ResizeTool.Increment*tonumber((tostring((a-.05)/ResizeTool.Increment)):gsub("\037\046\046\043",""))return false,(r+D)-T end if S then local a=ResizeTool.Increment*tonumber((tostring(2048/ResizeTool.Increment)):gsub("\037\046\046\043",""))return false,(r+a)-S end for a,Y in pairs(Y)do if a:IsA("\080\097\114\116")then if a.Shape==Enum.PartType.Ball then a.Size=Y.Size+Vector3.new(r,r,r)elseif a.Shape==Enum.PartType.Cylinder and P~="\088"then a.Size=Y.Size+Vector3.new(0,r,r)else a.Size=Y.Size+o end else a.Size=Y.Size+o end if s=="\078\111\114\109\097\108"then a.CFrame=Y.CFrame*CFrame.new((AxisPositioningMultipliers[D]*r)/2)elseif s=="\066\111\116\104"then a.CFrame=Y.CFrame end end return true end function BindShortcutKeys()table.insert(Connections,UserInputService.InputBegan:Connect(function(a,D)if D then return end if a.UserInputType~=Enum.UserInputType.Keyboard then return end if UserInputService:GetFocusedTextBox()then return end if a.KeyCode==Enum.KeyCode.Return or a.KeyCode==Enum.KeyCode.KeypadEnter then if ResizeTool.Directions=="\078\111\114\109\097\108"then SetDirections("\066\111\116\104")elseif ResizeTool.Directions=="\066\111\116\104"then SetDirections("\078\111\114\109\097\108")end elseif a.KeyCode==Enum.KeyCode.Minus or a.KeyCode==Enum.KeyCode.KeypadMinus then if ResizeTool.UI then ResizeTool.UI.IncrementOption.Increment.TextBox:CaptureFocus()end elseif a.KeyCode==Enum.KeyCode.KeypadEight then NudgeSelectionByFace(Enum.NormalId.Top)elseif a.KeyCode==Enum.KeyCode.KeypadTwo then NudgeSelectionByFace(Enum.NormalId.Bottom)elseif a.KeyCode==Enum.KeyCode.KeypadNine then NudgeSelectionByFace(Enum.NormalId.Front)elseif a.KeyCode==Enum.KeyCode.KeypadOne then NudgeSelectionByFace(Enum.NormalId.Back)elseif a.KeyCode==Enum.KeyCode.KeypadFour then NudgeSelectionByFace(Enum.NormalId.Left)elseif a.KeyCode==Enum.KeyCode.KeypadSix then NudgeSelectionByFace(Enum.NormalId.Right)elseif a.KeyCode==Enum.KeyCode.R and not Selection.Multiselecting then StartSnapping()end end))table.insert(Connections,UserInputService.InputEnded:Connect(function(a,D)if D then return end if a.UserInputType~=Enum.UserInputType.Keyboard then return end if UserInputService:GetFocusedTextBox()then return end if a.KeyCode==Enum.KeyCode.R and not Selection.Multiselecting then FinishSnapping()end end))end function SetAxisSize(a,D)TrackChange()local r=PreparePartsForResizing()for r,s in pairs(r)do r.Size=Vector3.new(a=="\088"and D or r.Size.X,a=="\089"and D or r.Size.Y,a=="\090"and D or r.Size.Z)r.CFrame=s.CFrame end local s=Security.GetPermissions(Security.GetSelectionAreas(Selection.Parts),Core.Player)if Core.Mode=="\084\111\111\108"and Security.ArePartsViolatingAreas(Selection.Parts,Core.Player,false,s)then for a,D in pairs(r)do a.Size=D.Size a.CFrame=D.CFrame end end for a,D in pairs(r)do a:MakeJoints()a.CanCollide=D.CanCollide a.Anchored=D.Anchored end RegisterChange()end function NudgeSelectionByFace(a)local D=ResizeTool.Increment local r=Support.FlipTable(Support.GetListMembers(UserInputService:GetKeysPressed(),"\075\101\121\067\111\100\101"))if r[Enum.KeyCode.LeftShift]or r[Enum.KeyCode.RightShift]then D=-D end TrackChange()local s=PreparePartsForResizing()local Y,N=ResizePartsByFace(a,D,ResizeTool.Directions,s)if not Y then ResizePartsByFace(a,N,ResizeTool.Directions,s)end if ResizeTool.UI then ResizeTool.UI.Changes.Text.Text="\114\101\115\105\122\101\100 "..(Support.Round(N or D,3).." \115\116\117\100\115")end local o=Security.GetPermissions(Security.GetSelectionAreas(Selection.Parts),Core.Player)if Core.Mode=="\084\111\111\108"and Security.ArePartsViolatingAreas(Selection.Parts,Core.Player,false,o)then for a,D in pairs(s)do a.Size=D.Size a.CFrame=D.CFrame end end for a,D in pairs(s)do a:MakeJoints()a.CanCollide=D.CanCollide a.Anchored=D.Anchored end RegisterChange()end function TrackChange()HistoryRecord={Parts=Support.CloneTable(Selection.Parts),BeforeSize={},AfterSize={},BeforeCFrame={};AfterCFrame={},Selection=Selection.Items;Unapply=function(a)Selection.Replace(a.Selection)local D={}for r,s in pairs(a.Parts)do table.insert(D,{Part=s;Size=a.BeforeSize[s],CFrame=a.BeforeCFrame[s]})end Core.SyncAPI:Invoke("\083\121\110\099\082\101\115\105\122\101",D)end,Apply=function(a)Selection.Replace(a.Selection)local D={}for r,s in pairs(a.Parts)do table.insert(D,{Part=s,Size=a.AfterSize[s],CFrame=a.AfterCFrame[s]})end Core.SyncAPI:Invoke("\083\121\110\099\082\101\115\105\122\101",D)end}for a,D in pairs(HistoryRecord.Parts)do HistoryRecord.BeforeSize[D]=D.Size HistoryRecord.BeforeCFrame[D]=D.CFrame end end function RegisterChange()if not HistoryRecord then return end local a={}for D,r in pairs(HistoryRecord.Parts)do HistoryRecord.AfterSize[r]=r.Size HistoryRecord.AfterCFrame[r]=r.CFrame table.insert(a,{Part=r,Size=r.Size,CFrame=r.CFrame})end Core.SyncAPI:Invoke("\083\121\110\099\082\101\115\105\122\101",a)Core.History.Add(HistoryRecord)HistoryRecord=nil end function PreparePartsForResizing()local a={}for D,r in pairs(Selection.Parts)do a[r]={Anchored=r.Anchored,CanCollide=r.CanCollide;Size=r.Size;CFrame=r.CFrame}r.Anchored=true r.CanCollide=false r:BreakJoints()r.Velocity=Vector3.new()r.RotVelocity=Vector3.new()end return a end function GetIncrementMultiple(a,D)local r=a%D local s=a-r local Y=(a-r)+D local N=math.abs(a-s)local o=math.abs(a-Y)if N<=o then a=s else a=Y end return a end

local FaceAxisNames = {
	[Enum.NormalId.Top] = 'Y';
	[Enum.NormalId.Bottom] = 'Y';
	[Enum.NormalId.Front] = 'Z';
	[Enum.NormalId.Back] = 'Z';
	[Enum.NormalId.Left] = 'X';
	[Enum.NormalId.Right] = 'X';
};

function ShowHandles()
	-- Creates and automatically attaches handles to the currently focused part

	-- Autofocus handles on latest focused part
	if not Connections.AutofocusHandle then
		Connections.AutofocusHandle = Selection.FocusChanged:Connect(ShowHandles);
	end;

	-- If handles already exist, only show them
	if ResizeTool.Handles then
		ResizeTool.Handles:SetAdornee(Selection.Focus)
		return
	end

	local AreaPermissions
	local function OnHandleDragStart()
		-- Prepare for resizing parts when the handle is clicked

		-- Prevent selection
		Core.Targeting.CancelSelecting();

		-- Indicate resizing via handles
		HandleResizing = true;

		-- Stop parts from moving, and capture the initial state of the parts
		InitialState = PreparePartsForResizing();

		-- Track the change
		TrackChange();

		-- Cache area permissions information
		if Core.Mode == 'Tool' then
			AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Selection.Parts), Core.Player);
		end;

	end

	local function OnHandleDrag(Face, Distance)
		-- Update parts when the handles are moved

		-- Only resize if handle is enabled
		if not HandleResizing then
			return;
		end;

		-- Calculate the increment-aligned drag distance
		Distance = GetIncrementMultiple(Distance, ResizeTool.Increment);

		-- Resize the parts on the selected faces by the calculated distance
		local Success, Adjustment = ResizePartsByFace(Face, Distance, ResizeTool.Directions, InitialState);

		-- If the resizing did not succeed, resize according to the suggested adjustment
		if not Success then
			ResizePartsByFace(Face, Adjustment, ResizeTool.Directions, InitialState);
		end;

		-- Update the "studs resized" indicator
		if ResizeTool.UI then
			ResizeTool.UI.Changes.Text.Text = 'resized ' .. Support.Round(math.abs(Adjustment or Distance), 3) .. ' studs';
		end;

		-- Make sure we're not entering any unauthorized private areas
		if Core.Mode == 'Tool' and Security.ArePartsViolatingAreas(Selection.Parts, Core.Player, false, AreaPermissions) then
			for Part, State in pairs(InitialState) do
				Part.Size = State.Size;
				Part.CFrame = State.CFrame;
			end;
		end;

	end

	local function OnHandleDragEnd()
		if not HandleResizing then
			return
		end

		-- Disable resizing
		HandleResizing = false;

		-- Prevent selection
		Core.Targeting.CancelSelecting();

		-- Make joints, restore original anchor and collision states
		for Part, State in pairs(InitialState) do
			Part:MakeJoints();
			Part.CanCollide = State.CanCollide;
			Part.Anchored = State.Anchored;
		end;

		-- Register the change
		RegisterChange();
	end

	-- Create the handles
	local Handles = require(Libraries:WaitForChild 'Handles')
	ResizeTool.Handles = Handles.new({
		Color = ResizeTool.Color.Color,
		Parent = Core.UIContainer,
		Adornee = Selection.Focus,
		OnDragStart = OnHandleDragStart,
		OnDrag = OnHandleDrag,
		OnDragEnd = OnHandleDragEnd
	})

end;

function HideHandles()
	-- Hides the resizing handles

	-- Make sure handles exist and are visible
	if not ResizeTool.Handles then
		return;
	end;

	-- Hide the handles
	ResizeTool.Handles = ResizeTool.Handles:Destroy()

	-- Clear unnecessary resources
	ClearConnection 'AutofocusHandle';

end;

function ResizePartsByFace(Face, Distance, Directions, InitialStates)
	-- Resizes the selection on face `Face` by `Distance` studs, in the given `Directions`

	-- Adjust the size increment to the resizing direction mode
	if Directions == 'Both' then
		Distance = Distance * 2;
	end;

	-- Calculate the increment vector for this resizing
	local AxisSizeMultiplier = AxisSizeMultipliers[Face];
	local IncrementVector = Distance * AxisSizeMultiplier;

	-- Get name of axis the resize will occur on
	local AxisName = FaceAxisNames[Face];

	-- Check for any potential undersizing or oversizing
	local ShortestSize, ShortestPart, LongestSize, LongestPart;
	for Part, InitialState in pairs(InitialStates) do

		-- Calculate target size for this resize
		local TargetSize = InitialState.Size[AxisName] + Distance;

		-- If target size is under 0.05, note if it's the shortest size
		if TargetSize < 0.049999 and (not ShortestSize or (ShortestSize and TargetSize < ShortestSize)) then
			ShortestSize, ShortestPart = TargetSize, Part;

		-- If target size is over 2048, note if it's the longest size
		elseif TargetSize > 2048 and (not LongestSize or (LongestSize and TargetSize > LongestSize)) then
			LongestSize, LongestPart = TargetSize, Part;
		end;

	end;

	-- Return adjustment for undersized parts (snap to lowest possible valid increment multiple)
	if ShortestSize then
		local InitialSize = InitialStates[ShortestPart].Size[AxisName];
		local TargetSize = InitialSize - ResizeTool.Increment * tonumber((tostring((InitialSize - 0.05) / ResizeTool.Increment):gsub('%..+', '')));
		return false, Distance + TargetSize - ShortestSize;
	end;

	-- Return adjustment for oversized parts (snap to highest possible valid increment multiple)
	if LongestSize then
		local TargetSize = ResizeTool.Increment * tonumber((tostring(2048 / ResizeTool.Increment):gsub('%..+', '')));
		return false, Distance + TargetSize - LongestSize;
	end;

	-- Resize each part
	for Part, InitialState in pairs(InitialStates) do

		-- Perform the size change depending on shape
		if Part:IsA 'Part' then

			-- Resize spheres on all axes
			if Part.Shape == Enum.PartType.Ball then
				Part.Size = InitialState.Size + Vector3.new(Distance, Distance, Distance);

			-- Resize cylinders on both Y & Z axes for circle sides
			elseif Part.Shape == Enum.PartType.Cylinder and AxisName ~= 'X' then
				Part.Size = InitialState.Size + Vector3.new(0, Distance, Distance);

			-- Resize block parts and cylinder lengths normally
			else
				Part.Size = InitialState.Size + IncrementVector;
			end;

		-- Perform the size change normally on all other parts
		else
			Part.Size = InitialState.Size + IncrementVector;
		end;

		-- Offset the part when resizing in the normal, one direction
		if Directions == 'Normal' then
			Part.CFrame = InitialState.CFrame * CFrame.new(AxisPositioningMultipliers[Face] * Distance / 2);

		-- Keep the part centered when resizing in both directions
		elseif Directions == 'Both' then
			Part.CFrame = InitialState.CFrame;

		end;

	end;

	-- Indicate that the resizing happened successfully
	return true;
end;

function BindShortcutKeys()
	-- Enables useful shortcut keys for this tool

	-- Track user input while this tool is equipped
	table.insert(Connections, UserInputService.InputBegan:Connect(function (InputInfo, GameProcessedEvent)

		-- Make sure this is an intentional event
		if GameProcessedEvent then
			return;
		end;

		-- Make sure this input is a key press
		if InputInfo.UserInputType ~= Enum.UserInputType.Keyboard then
			return;
		end;

		-- Make sure it wasn't pressed while typing
		if UserInputService:GetFocusedTextBox() then
			return;
		end;

		-- Check if the enter key was pressed
		if InputInfo.KeyCode == Enum.KeyCode.Return or InputInfo.KeyCode == Enum.KeyCode.KeypadEnter then

			-- Toggle the current directions mode
			if ResizeTool.Directions == 'Normal' then
				SetDirections('Both');

			elseif ResizeTool.Directions == 'Both' then
				SetDirections('Normal');
			end;

		-- Check if the - key was pressed
		elseif InputInfo.KeyCode == Enum.KeyCode.Minus or InputInfo.KeyCode == Enum.KeyCode.KeypadMinus then

			-- Focus on the increment input
			if ResizeTool.UI then
				ResizeTool.UI.IncrementOption.Increment.TextBox:CaptureFocus();
			end;

		-- Nudge up if the 8 button on the keypad is pressed
		elseif InputInfo.KeyCode == Enum.KeyCode.KeypadEight then
			NudgeSelectionByFace(Enum.NormalId.Top);

		-- Nudge down if the 2 button on the keypad is pressed
		elseif InputInfo.KeyCode == Enum.KeyCode.KeypadTwo then
			NudgeSelectionByFace(Enum.NormalId.Bottom);

		-- Nudge forward if the 9 button on the keypad is pressed
		elseif InputInfo.KeyCode == Enum.KeyCode.KeypadNine then
			NudgeSelectionByFace(Enum.NormalId.Front);

		-- Nudge backward if the 1 button on the keypad is pressed
		elseif InputInfo.KeyCode == Enum.KeyCode.KeypadOne then
			NudgeSelectionByFace(Enum.NormalId.Back);

		-- Nudge left if the 4 button on the keypad is pressed
		elseif InputInfo.KeyCode == Enum.KeyCode.KeypadFour then
			NudgeSelectionByFace(Enum.NormalId.Left);

		-- Nudge right if the 6 button on the keypad is pressed
		elseif InputInfo.KeyCode == Enum.KeyCode.KeypadSix then
			NudgeSelectionByFace(Enum.NormalId.Right);

		-- Start snapping when the R key is pressed down, and it's not the selection clearing hotkey
		elseif InputInfo.KeyCode == Enum.KeyCode.R and not Selection.Multiselecting then
			StartSnapping();

		end;

	end));

	-- Track ending user input while this tool is equipped
	table.insert(Connections, UserInputService.InputEnded:Connect(function (InputInfo, GameProcessedEvent)

		-- Make sure this is an intentional event
		if GameProcessedEvent then
			return;
		end;

		-- Make sure this is input from the keyboard
		if InputInfo.UserInputType ~= Enum.UserInputType.Keyboard then
			return;
		end;

		-- Make sure it wasn't pressed while typing
		if UserInputService:GetFocusedTextBox() then
			return;
		end;

		-- Finish snapping when the R key is released, and it's not the selection clearing hotkey
		if InputInfo.KeyCode == Enum.KeyCode.R and not Selection.Multiselecting then
			FinishSnapping();

		end;

	end));

end;

function SetAxisSize(Axis, Size)
	-- Sets the selection's size on axis `Axis` to `Size`

	-- Track this change
	TrackChange();

	-- Prepare parts to be resized
	local InitialStates = PreparePartsForResizing();

	-- Update each part
	for Part, InitialState in pairs(InitialStates) do

		-- Set the part's new size
		Part.Size = Vector3.new(
			Axis == 'X' and Size or Part.Size.X,
			Axis == 'Y' and Size or Part.Size.Y,
			Axis == 'Z' and Size or Part.Size.Z
		);

		-- Keep the part in place
		Part.CFrame = InitialState.CFrame;

	end;

	-- Cache up permissions for all private areas
	local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Selection.Parts), Core.Player);

	-- Revert changes if player is not authorized to resize parts towards the end destination
	if Core.Mode == 'Tool' and Security.ArePartsViolatingAreas(Selection.Parts, Core.Player, false, AreaPermissions) then
		for Part, State in pairs(InitialStates) do
			Part.Size = State.Size;
			Part.CFrame = State.CFrame;
		end;
	end;

	-- Restore the parts' original states
	for Part, State in pairs(InitialStates) do
		Part:MakeJoints();
		Part.CanCollide = State.CanCollide;
		Part.Anchored = State.Anchored;
	end;

	-- Register the change
	RegisterChange();

end;

function NudgeSelectionByFace(Face)
	-- Nudges the size of the selection in the direction of the given face

	-- Get amount to nudge by
	local NudgeAmount = ResizeTool.Increment;

	-- Reverse nudge amount if shift key is held while nudging
	local PressedKeys = Support.FlipTable(Support.GetListMembers(UserInputService:GetKeysPressed(), 'KeyCode'));
	if PressedKeys[Enum.KeyCode.LeftShift] or PressedKeys[Enum.KeyCode.RightShift] then
		NudgeAmount = -NudgeAmount;
	end;

	-- Track this change
	TrackChange();

	-- Prepare parts to be resized
	local InitialState = PreparePartsForResizing();

	-- Perform the resizing
	local Success, Adjustment = ResizePartsByFace(Face, NudgeAmount, ResizeTool.Directions, InitialState);

	-- If the resizing did not succeed, resize according to the suggested adjustment
	if not Success then
		ResizePartsByFace(Face, Adjustment, ResizeTool.Directions, InitialState);
	end;

	-- Update "studs resized" indicator
	if ResizeTool.UI then
		ResizeTool.UI.Changes.Text.Text = 'resized ' .. Support.Round(Adjustment or NudgeAmount, 3) .. ' studs';
	end;

	-- Cache up permissions for all private areas
	local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Selection.Parts), Core.Player);

	-- Revert changes if player is not authorized to resize parts towards the end destination
	if Core.Mode == 'Tool' and Security.ArePartsViolatingAreas(Selection.Parts, Core.Player, false, AreaPermissions) then
		for Part, State in pairs(InitialState) do
			Part.Size = State.Size;
			Part.CFrame = State.CFrame;
		end;
	end;

	-- Restore the parts' original states
	for Part, State in pairs(InitialState) do
		Part:MakeJoints();
		Part.CanCollide = State.CanCollide;
		Part.Anchored = State.Anchored;
	end;

	-- Register the change
	RegisterChange();

end;

function TrackChange()

	-- Start the record
	HistoryRecord = {
		Parts = Support.CloneTable(Selection.Parts);
		BeforeSize = {};
		AfterSize = {};
		BeforeCFrame = {};
		AfterCFrame = {};
		Selection = Selection.Items;

		Unapply = function (Record)
			-- Reverts this change

			-- Select the changed parts
			Selection.Replace(Record.Selection)

			-- Put together the change request
			local Changes = {};
			for _, Part in pairs(Record.Parts) do
				table.insert(Changes, { Part = Part, Size = Record.BeforeSize[Part], CFrame = Record.BeforeCFrame[Part] });
			end;

			-- Send the change request
			Core.SyncAPI:Invoke('SyncResize', Changes);

		end;

		Apply = function (Record)
			-- Applies this change

			-- Select the changed parts
			Selection.Replace(Record.Selection)

			-- Put together the change request
			local Changes = {};
			for _, Part in pairs(Record.Parts) do
				table.insert(Changes, { Part = Part, Size = Record.AfterSize[Part], CFrame = Record.AfterCFrame[Part] });
			end;

			-- Send the change request
			Core.SyncAPI:Invoke('SyncResize', Changes);

		end;

	};

	-- Collect the selection's initial state
	for _, Part in pairs(HistoryRecord.Parts) do
		HistoryRecord.BeforeSize[Part] = Part.Size;
		HistoryRecord.BeforeCFrame[Part] = Part.CFrame;
	end;

end;

function RegisterChange()
	-- Finishes creating the history record and registers it

	-- Make sure there's an in-progress history record
	if not HistoryRecord then
		return;
	end;

	-- Collect the selection's final state
	local Changes = {};
	for _, Part in pairs(HistoryRecord.Parts) do
		HistoryRecord.AfterSize[Part] = Part.Size;
		HistoryRecord.AfterCFrame[Part] = Part.CFrame;
		table.insert(Changes, { Part = Part, Size = Part.Size, CFrame = Part.CFrame });
	end;

	-- Send the change to the server
	Core.SyncAPI:Invoke('SyncResize', Changes);

	-- Register the record and clear the staging
	Core.History.Add(HistoryRecord);
	HistoryRecord = nil;

end;

function PreparePartsForResizing()
	-- Prepares parts for resizing and returns the initial state of the parts

	local InitialState = {};

	-- Stop parts from moving, and capture the initial state of the parts
	for _, Part in pairs(Selection.Parts) do
		InitialState[Part] = { Anchored = Part.Anchored, CanCollide = Part.CanCollide, Size = Part.Size, CFrame = Part.CFrame };
		Part.Anchored = true;
		Part.CanCollide = false;
		Part:BreakJoints();
		Part.Velocity = Vector3.new();
		Part.RotVelocity = Vector3.new();
	end;

	return InitialState;
end;

function GetIncrementMultiple(Number, Increment)

	-- Get how far the actual distance is from a multiple of our increment
	local MultipleDifference = Number % Increment;

	-- Identify the closest lower and upper multiples of the increment
	local LowerMultiple = Number - MultipleDifference;
	local UpperMultiple = Number - MultipleDifference + Increment;

	-- Calculate to which of the two multiples we're closer
	local LowerMultipleProximity = math.abs(Number - LowerMultiple);
	local UpperMultipleProximity = math.abs(Number - UpperMultiple);

	-- Use the closest multiple of our increment as the distance moved
	if LowerMultipleProximity <= UpperMultipleProximity then
		Number = LowerMultiple;
	else
		Number = UpperMultiple;
	end;

	return Number;
end;
