Actions={RecolorHandle=function(C)Tool.Handle.BrickColor=C end;Clone=function(C)if not ArePartsSelectable(C)then return end local K=Security.GetPermissions(Security.GetSelectionAreas(C),Player)if Security.ArePartsViolatingAreas(C,Player,false,K)then return end local V={}for C,K in pairs(C)do local U=K:Clone()U.Parent=Options.DefaultPartParent table.insert(V,U)CreatedInstances[K]=K end return V end;CreatePart=function(C,K)local V=Support.CreatePart(C)V.TopSurface=Enum.SurfaceType.Smooth V.BottomSurface=Enum.SurfaceType.Smooth V.CFrame=K local U=Security.GetPermissions(Security.GetSelectionAreas({V}),Player)if Security.ArePartsViolatingAreas({V},Player,false,U)then return end V.Parent=Options.DefaultPartParent CreatedInstances[V]=V return V end;Remove=function(C)local K={}for C,V in pairs(C)do if V then if V:IsA("\066\097\115\101\080\097\114\116")then table.insert(K,V)elseif V:IsA("\083\109\111\107\101")or V:IsA("\070\105\114\101")or V:IsA("\083\112\097\114\107\108\101\115")or V:IsA("\068\097\116\097\077\111\100\101\108\077\101\115\104")or V:IsA("\068\101\099\097\108")or V:IsA("\084\101\120\116\117\114\101")or V:IsA("\076\105\103\104\116")then table.insert(K,V.Parent)end end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end for C,K in pairs(C)do LastParents[K]=K.Parent CreatedInstances[K]=K K.Parent=nil end end,UndoRemove=function(C)local K={}for C,V in pairs(C)do if V and LastParents[V]then if V:IsA("\066\097\115\101\080\097\114\116")then table.insert(K,V)elseif V:IsA("\083\109\111\107\101")or V:IsA("\070\105\114\101")or V:IsA("\083\112\097\114\107\108\101\115")or V:IsA("\068\097\116\097\077\111\100\101\108\077\101\115\104")or V:IsA("\068\101\099\097\108")or V:IsA("\084\101\120\116\117\114\101")or V:IsA("\076\105\103\104\116")then table.insert(K,V.Parent)end end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,false,V)then return end for C,K in pairs(C)do local V=LastParents[K]LastParents[K]=K.Parent CreatedInstances[K]=K K.Parent=V end end,SyncMove=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then K.InitialState={Anchored=K.Part.Anchored;CFrame=K.Part.CFrame}U[K.Part]=K end end for C,K in pairs(U)do K.Joints=PreserveJoints(C,U)end for C,K in pairs(U)do C.Anchored=true C:BreakJoints()C.Velocity=Vector3.new()C.RotVelocity=Vector3.new()C.CFrame=K.CFrame end if Security.ArePartsViolatingAreas(K,Player,false,V)then for C,K in pairs(U)do C.CFrame=K.InitialState.CFrame end end for C,K in pairs(U)do C:MakeJoints()RestoreJoints(K.Joints)C.Anchored=K.InitialState.Anchored end end,SyncResize=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then K.InitialState={Anchored=K.Part.Anchored,Size=K.Part.Size;CFrame=K.Part.CFrame}U[K.Part]=K end end for C,K in pairs(U)do C.Anchored=true C:BreakJoints()C.Velocity=Vector3.new()C.RotVelocity=Vector3.new()C.Size=K.Size C.CFrame=K.CFrame end if Security.ArePartsViolatingAreas(K,Player,false,V)then for C,K in pairs(U)do C.Size=K.InitialState.Size C.CFrame=K.InitialState.CFrame end end for C,K in pairs(U)do C:MakeJoints()C.Anchored=K.InitialState.Anchored end end;SyncRotate=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then K.InitialState={Anchored=K.Part.Anchored;CFrame=K.Part.CFrame}U[K.Part]=K end end for C,K in pairs(U)do K.Joints=PreserveJoints(C,U)end for C,K in pairs(U)do C.Anchored=true C:BreakJoints()C.Velocity=Vector3.new()C.RotVelocity=Vector3.new()C.CFrame=K.CFrame end if Security.ArePartsViolatingAreas(K,Player,false,V)then for C,K in pairs(U)do C.CFrame=K.InitialState.CFrame end end for C,K in pairs(U)do C:MakeJoints()RestoreJoints(K.Joints)C.Anchored=K.InitialState.Anchored end end;SyncColor=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then U[K.Part]=K end end for C,K in pairs(U)do C.Color=K.Color if C.ClassName=="\085\110\105\111\110\079\112\101\114\097\116\105\111\110"then C.UsePartColor=K.UnionColoring end end end,SyncSurface=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then U[K.Part]=K end end for C,K in pairs(U)do for K,V in pairs(K.Surfaces)do C[K.."\083\117\114\102\097\099\101"]=V end end end,CreateLights=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then U[K.Part]=K end end local M={PointLight=true;SurfaceLight=true,SpotLight=true}local h={}for C,K in pairs(U)do if M[K.LightType]then local V=Instance.new(K.LightType,C)table.insert(h,V)CreatedInstances[V]=V end end return h end,SyncLighting=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then U[K.Part]=K end end local M={PointLight=true,SurfaceLight=true;SpotLight=true}for C,K in pairs(U)do if M[K.LightType]then local V=Support.GetChildOfClass(C,K.LightType)if V then if K.Range~=nil then V.Range=K.Range end if K.Brightness~=nil then V.Brightness=K.Brightness end if K.Color~=nil then V.Color=K.Color end if K.Shadows~=nil then V.Shadows=K.Shadows end if K.Face~=nil then V.Face=K.Face end if K.Angle~=nil then V.Angle=K.Angle end end end end end,CreateDecorations=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then U[K.Part]=K end end local M={Smoke=true;Fire=true;Sparkles=true}local h={}for C,K in pairs(U)do if M[K.DecorationType]then local V=Instance.new(K.DecorationType,C)table.insert(h,V)CreatedInstances[V]=V end end return h end,SyncDecorate=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then U[K.Part]=K end end local M={Smoke=true;Fire=true,Sparkles=true}for C,K in pairs(U)do if M[K.DecorationType]then local V=Support.GetChildOfClass(C,K.DecorationType)if V then if K.Color~=nil then V.Color=K.Color end if K.Opacity~=nil then V.Opacity=K.Opacity end if K.RiseVelocity~=nil then V.RiseVelocity=K.RiseVelocity end if K.Size~=nil then V.Size=K.Size end if K.Heat~=nil then V.Heat=K.Heat end if K.SecondaryColor~=nil then V.SecondaryColor=K.SecondaryColor end if K.SparkleColor~=nil then V.SparkleColor=K.SparkleColor end end end end end;CreateMeshes=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then U[K.Part]=K end end local M={}for C,K in pairs(U)do local V=Instance.new("\083\112\101\099\105\097\108\077\101\115\104",C)table.insert(M,V)CreatedInstances[V]=V end return M end,SyncMesh=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then U[K.Part]=K end end for C,K in pairs(U)do local V=Support.GetChildOfClass(C,"\083\112\101\099\105\097\108\077\101\115\104")if V then if K.VertexColor~=nil then V.VertexColor=K.VertexColor end if K.MeshType~=nil then V.MeshType=K.MeshType end if K.Scale~=nil then V.Scale=K.Scale end if K.Offset~=nil then V.Offset=K.Offset end if K.MeshId~=nil then V.MeshId=K.MeshId end if K.TextureId~=nil then V.TextureId=K.TextureId end end end end;CreateTextures=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then U[K.Part]=K end end local M={Texture=true;Decal=true}local h={}for C,K in pairs(U)do if M[K.TextureType]then local V=Instance.new(K.TextureType,C)V.Face=K.Face table.insert(h,V)CreatedInstances[V]=V end end return h end,SyncTexture=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then U[K.Part]=K end end local M={Texture=true,Decal=true}for C,K in pairs(U)do if M[K.TextureType]then for C,V in pairs(C:GetChildren())do if V.ClassName==K.TextureType and V.Face==K.Face then if K.Texture~=nil then V.Texture=K.Texture end if K.Transparency~=nil then V.Transparency=K.Transparency end if K.StudsPerTileU~=nil then V.StudsPerTileU=K.StudsPerTileU end if K.StudsPerTileV~=nil then V.StudsPerTileV=K.StudsPerTileV end end end end end end;SyncAnchor=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then U[K.Part]=K end end for C,K in pairs(U)do C.Anchored=K.Anchored end end,SyncCollision=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then U[K.Part]=K end end for C,K in pairs(U)do C.CanCollide=K.CanCollide end end;SyncMaterial=function(C)local K={}for C,V in pairs(C)do if V.Part then table.insert(K,V.Part)end end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)if Security.ArePartsViolatingAreas(K,Player,true,V)then return end local U={}for C,K in pairs(C)do if K.Part then U[K.Part]=K end end for C,K in pairs(U)do if K.Material~=nil then C.Material=K.Material end if K.Transparency~=nil then C.Transparency=K.Transparency end if K.Reflectance~=nil then C.Reflectance=K.Reflectance end end end,CreateWelds=function(C,K)if not ArePartsSelectable(C)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(C),Player)if Security.ArePartsViolatingAreas(C,Player,true,V)then return end local U={}for C,V in pairs(C)do if V~=K then local C=V.CFrame:toObjectSpace(K.CFrame)local M=Instance.new("\087\101\108\100")M.Name="\066\084\087\101\108\100"M.Part0=K M.Part1=V M.C1=C M.Archivable=true M.Parent=K CreatedInstances[M]=M table.insert(U,M)end end return U end,RemoveWelds=function(C)local K={}for C,V in pairs(C)do if V.ClassName~="\087\101\108\100"then return end table.insert(K,V.Part0)table.insert(K,V.Part1)end if not ArePartsSelectable(K)then return end local V=0 local U=Security.GetPermissions(Security.GetSelectionAreas(K),Player)for C,K in pairs(C)do local M=Security.ArePartsViolatingAreas({K.Part0},Player,true,U)local h=Security.ArePartsViolatingAreas({K.Part1},Player,true,U)if not M or not h then CreatedInstances[K]=K LastParents[K]=K.Parent V=V+1 K.Parent=nil end end return V end,UndoRemovedWelds=function(C)local K={}for C,V in pairs(C)do if V.ClassName~="\087\101\108\100"then return end if not LastParents[V]then return end table.insert(K,V.Part0)table.insert(K,V.Part1)end if not ArePartsSelectable(K)then return end local V=Security.GetPermissions(Security.GetSelectionAreas(K),Player)for C,K in pairs(C)do local U=Security.ArePartsViolatingAreas({K.Part0},Player,false,V)local M=Security.ArePartsViolatingAreas({K.Part0},Player,false,V)if not U or not M then local C=LastParents[K]LastParents[K]=K.Parent CreatedInstances[K]=K K.Parent=C end end end,Export=function(C)if RunService:IsClient()and not RunService:IsStudio()then return SyncAPI.ServerEndpoint:InvokeServer("\069\120\112\111\114\116",C)end assert(type(C)=="\116\097\098\108\101","\073\110\118\097\108\105\100 \105\116\101\109 \116\097\098\108\101")if#C==0 then return end if not ArePartsSelectable(C)then return end local K=Security.GetPermissions(Security.GetSelectionAreas(C),Player)if Security.ArePartsViolatingAreas(C,Player,true,K)then return end local V=Support.CloneTable(C)for C,K in pairs(C)do Support.ConcatTable(V,Support.GetAllDescendants(K))end local U=Serialization.SerializeModel(V)local M=HttpService:JSONDecode(HttpService:PostAsync("\104\116\116\112\058\047\047\102\051\120\116\101\097\109\046\099\111\109\047\098\116\047\101\120\112\111\114\116",HttpService:JSONEncode({data=U,version=3;userId=Player and Player.UserId}),Enum.HttpContentType.ApplicationJson,true))if M.success then return M.id else error("\069\120\112\111\114\116 \102\097\105\108\101\100 \100\117\101 \116\111 \115\101\114\118\101\114-\115\105\100\101 \101\114\114\111\114",2)end end;IsHttpServiceEnabled=function()if RunService:IsClient()and not RunService:IsStudio()then return SyncAPI.ServerEndpoint:InvokeServer("\073\115\072\116\116\112\083\101\114\118\105\099\101\069\110\097\098\108\101\100")end if ToolMode=="\084\111\111\108"and IsHttpServiceEnabled~=nil then return IsHttpServiceEnabled end local C,K=pcall(function()return HttpService:GetAsync("\104\116\116\112\058\047\047\103\111\111\103\108\101\046\099\111\109")end)if not C and K:match("\072\116\116\112 \114\101\113\117\101\115\116\115 \097\114\101 \110\111\116 \101\110\097\098\108\101\100")then IsHttpServiceEnabled=false elseif C then IsHttpServiceEnabled=true end return IsHttpServiceEnabled end,ExtractMeshFromAsset=function(C)if RunService:IsClient()and not RunService:IsStudio()then return SyncAPI.ServerEndpoint:InvokeServer("\069\120\116\114\097\099\116\077\101\115\104\070\114\111\109\065\115\115\101\116",C)end assert(type(C)=="\110\117\109\098\101\114","\073\110\118\097\108\105\100 \097\115\115\101\116 \073\068")return HttpService:JSONDecode(HttpService:GetAsync("\104\116\116\112\058\047\047\102\051\120\116\101\097\109\046\099\111\109\047\098\116\047\103\101\116\070\105\114\115\116\077\101\115\104\068\097\116\097\047"..C))end,ExtractImageFromDecal=function(C)if RunService:IsClient()and not RunService:IsStudio()then return SyncAPI.ServerEndpoint:InvokeServer("\069\120\116\114\097\099\116\073\109\097\103\101\070\114\111\109\068\101\099\097\108",C)end return HttpService:GetAsync("\104\116\116\112\058\047\047\102\051\120\116\101\097\109\046\099\111\109\047\098\116\047\103\101\116\068\101\099\097\108\073\109\097\103\101\073\068\047"..C)end,SetMouseLockEnabled=function(C)if RunService:IsClient()and not RunService:IsStudio()then return SyncAPI.ServerEndpoint:InvokeServer("\083\101\116\077\111\117\115\101\076\111\099\107\069\110\097\098\108\101\100",C)end Player.DevEnableMouseLock=C end}function ArePartsSelectable(C)for C,K in pairs(C)do if not K:IsA("\066\097\115\101\080\097\114\116")or K.Locked then return false end end return true end

Actions = {

	['RecolorHandle'] = function (NewColor)
		-- Recolors the tool handle
		Tool.Handle.BrickColor = NewColor;
	end;

	['Clone'] = function (Parts)
		-- Clones the given parts

		-- Make sure the given items are all parts
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, false, AreaPermissions) then
			return;
		end;

		local Clones = {};

		-- Clone the parts
		for _, Part in pairs(Parts) do

			-- Create the clone
			local Clone = Part:Clone();
			Clone.Parent = Options.DefaultPartParent;

			-- Register the clone
			table.insert(Clones, Clone);
			CreatedInstances[Part] = Part;

		end;

		-- Return the clones
		return Clones;
	end;

	['CreatePart'] = function (PartType, Position)
		-- Creates a new part based on `PartType`

		-- Create the part
		local NewPart = Support.CreatePart(PartType);
		NewPart.TopSurface = Enum.SurfaceType.Smooth;
		NewPart.BottomSurface = Enum.SurfaceType.Smooth;

		-- Position the part
		NewPart.CFrame = Position;

		-- Cache up permissions for all private areas
		local AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas({ NewPart }), Player);

		-- Make sure the player is allowed to create parts in the area
		if Security.ArePartsViolatingAreas({ NewPart }, Player, false, AreaPermissions) then
			return;
		end;

		-- Parent the part
		NewPart.Parent = Options.DefaultPartParent;

		-- Register the part
		CreatedInstances[NewPart] = NewPart;

		-- Return the part
		return NewPart;
	end;

	['Remove'] = function (Objects)
		-- Removes the given objects

		-- Get the relevant parts for each object, for permission checking
		local Parts = {};

		-- Go through the selection
		for _, Object in pairs(Objects) do

			-- Make sure the object still exists
			if Object then

				if Object:IsA 'BasePart' then
					table.insert(Parts, Object);

				elseif Object:IsA 'Smoke' or Object:IsA 'Fire' or Object:IsA 'Sparkles' or Object:IsA 'DataModelMesh' or Object:IsA 'Decal' or Object:IsA 'Texture' or Object:IsA 'Light' then
					table.insert(Parts, Object.Parent);
				end;

			end;

		end;

		-- Ensure relevant parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- After confirming permissions, perform each removal
		for _, Object in pairs(Objects) do

			-- Store the part's current parent
			LastParents[Object] = Object.Parent;

			-- Register the object
			CreatedInstances[Object] = Object;

			-- Set the object's current parent to `nil`
			Object.Parent = nil;

		end;

	end;

	['UndoRemove'] = function (Objects)
		-- Restores the given removed objects to their last parents

		-- Get the relevant parts for each object, for permission checking
		local Parts = {};

		-- Go through the selection
		for _, Object in pairs(Objects) do

			-- Make sure the object still exists, and that its last parent is registered
			if Object and LastParents[Object] then

				if Object:IsA 'BasePart' then
					table.insert(Parts, Object);

				elseif Object:IsA 'Smoke' or Object:IsA 'Fire' or Object:IsA 'Sparkles' or Object:IsA 'DataModelMesh' or Object:IsA 'Decal' or Object:IsA 'Texture' or Object:IsA 'Light' then
					table.insert(Parts, Object.Parent);
				end;

			end;

		end;

		-- Ensure relevant parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, false, AreaPermissions) then
			return;
		end;

		-- After confirming permissions, perform each removal
		for _, Object in pairs(Objects) do

			-- Store the part's current parent
			local LastParent = LastParents[Object];
			LastParents[Object] = Object.Parent;

			-- Register the object
			CreatedInstances[Object] = Object;

			-- Set the object's parent to the last parent
			Object.Parent = LastParent;

		end;

	end;

	['SyncMove'] = function (Changes)
		-- Updates parts server-side given their new CFrames

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				Change.InitialState = { Anchored = Change.Part.Anchored, CFrame = Change.Part.CFrame };
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Preserve joints
		for Part, Change in pairs(ChangeSet) do
			Change.Joints = PreserveJoints(Part, ChangeSet);
		end;

		-- Perform each change
		for Part, Change in pairs(ChangeSet) do

			-- Stabilize the parts and maintain the original anchor state
			Part.Anchored = true;
			Part:BreakJoints();
			Part.Velocity = Vector3.new();
			Part.RotVelocity = Vector3.new();

			-- Set the part's CFrame
			Part.CFrame = Change.CFrame;

		end;

		-- Make sure the player is authorized to move parts into this area
		if Security.ArePartsViolatingAreas(Parts, Player, false, AreaPermissions) then

			-- Revert changes if unauthorized destination
			for Part, Change in pairs(ChangeSet) do
				Part.CFrame = Change.InitialState.CFrame;
			end;

		end;

		-- Restore the parts' original states
		for Part, Change in pairs(ChangeSet) do
			Part:MakeJoints();
			RestoreJoints(Change.Joints);
			Part.Anchored = Change.InitialState.Anchored;
		end;

	end;

	['SyncResize'] = function (Changes)
		-- Updates parts server-side given their new sizes and CFrames

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				Change.InitialState = { Anchored = Change.Part.Anchored, Size = Change.Part.Size, CFrame = Change.Part.CFrame };
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Perform each change
		for Part, Change in pairs(ChangeSet) do

			-- Stabilize the parts and maintain the original anchor state
			Part.Anchored = true;
			Part:BreakJoints();
			Part.Velocity = Vector3.new();
			Part.RotVelocity = Vector3.new();

			-- Set the part's size and CFrame
			Part.Size = Change.Size;
			Part.CFrame = Change.CFrame;

		end;

		-- Make sure the player is authorized to move parts into this area
		if Security.ArePartsViolatingAreas(Parts, Player, false, AreaPermissions) then

			-- Revert changes if unauthorized destination
			for Part, Change in pairs(ChangeSet) do
				Part.Size = Change.InitialState.Size;
				Part.CFrame = Change.InitialState.CFrame;
			end;

		end;

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

	end;

	['SyncRotate'] = function (Changes)
		-- Updates parts server-side given their new CFrames

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				Change.InitialState = { Anchored = Change.Part.Anchored, CFrame = Change.Part.CFrame };
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Preserve joints
		for Part, Change in pairs(ChangeSet) do
			Change.Joints = PreserveJoints(Part, ChangeSet);
		end;

		-- Perform each change
		for Part, Change in pairs(ChangeSet) do

			-- Stabilize the parts and maintain the original anchor state
			Part.Anchored = true;
			Part:BreakJoints();
			Part.Velocity = Vector3.new();
			Part.RotVelocity = Vector3.new();

			-- Set the part's CFrame
			Part.CFrame = Change.CFrame;

		end;

		-- Make sure the player is authorized to move parts into this area
		if Security.ArePartsViolatingAreas(Parts, Player, false, AreaPermissions) then

			-- Revert changes if unauthorized destination
			for Part, Change in pairs(ChangeSet) do
				Part.CFrame = Change.InitialState.CFrame;
			end;

		end;

		-- Restore the parts' original states
		for Part, Change in pairs(ChangeSet) do
			Part:MakeJoints();
			RestoreJoints(Change.Joints);
			Part.Anchored = Change.InitialState.Anchored;
		end;

	end;

	['SyncColor'] = function (Changes)
		-- Updates parts server-side given their new colors

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Perform each change
		for Part, Change in pairs(ChangeSet) do

			-- Set the part's color
			Part.Color = Change.Color;

			-- If this part is a union, set its UsePartColor state
			if Part.ClassName == 'UnionOperation' then
				Part.UsePartColor = Change.UnionColoring;
			end;

		end;

	end;

	['SyncSurface'] = function (Changes)
		-- Updates parts server-side given their new surfaces

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Perform each change
		for Part, Change in pairs(ChangeSet) do

			-- Apply each surface change
			for Surface, SurfaceType in pairs(Change.Surfaces) do
				Part[Surface .. 'Surface'] = SurfaceType;
			end;

		end;

	end;

	['CreateLights'] = function (Changes)
		-- Creates lights in the given parts

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Make a list of allowed light type requests
		local AllowedLightTypes = { PointLight = true, SurfaceLight = true, SpotLight = true };

		-- Keep track of the newly created lights
		local Lights = {};

		-- Create each light
		for Part, Change in pairs(ChangeSet) do

			-- Make sure the requested light type is valid
			if AllowedLightTypes[Change.LightType] then

				-- Create the light
				local Light = Instance.new(Change.LightType, Part);
				table.insert(Lights, Light);

				-- Register the light
				CreatedInstances[Light] = Light;

			end;

		end;

		-- Return the new lights
		return Lights;

	end;

	['SyncLighting'] = function (Changes)
		-- Updates aspects of the given selection's lights

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Make a list of allowed light type requests
		local AllowedLightTypes = { PointLight = true, SurfaceLight = true, SpotLight = true };

		-- Update each part's lights
		for Part, Change in pairs(ChangeSet) do

			-- Make sure that the light type requested is valid
			if AllowedLightTypes[Change.LightType] then

				-- Grab the part's light
				local Light = Support.GetChildOfClass(Part, Change.LightType);

				-- Make sure the light exists
				if Light then

					-- Make the requested changes
					if Change.Range ~= nil then
						Light.Range = Change.Range;
					end;
					if Change.Brightness ~= nil then
						Light.Brightness = Change.Brightness;
					end;
					if Change.Color ~= nil then
						Light.Color = Change.Color;
					end;
					if Change.Shadows ~= nil then
						Light.Shadows = Change.Shadows;
					end;
					if Change.Face ~= nil then
						Light.Face = Change.Face;
					end;
					if Change.Angle ~= nil then
						Light.Angle = Change.Angle;
					end;

				end;

			end;

		end;

	end;

	['CreateDecorations'] = function (Changes)
		-- Creates decorations in the given parts

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Make a list of allowed decoration type requests
		local AllowedDecorationTypes = { Smoke = true, Fire = true, Sparkles = true };

		-- Keep track of the newly created decorations
		local Decorations = {};

		-- Create each decoration
		for Part, Change in pairs(ChangeSet) do

			-- Make sure the requested decoration type is valid
			if AllowedDecorationTypes[Change.DecorationType] then

				-- Create the decoration
				local Decoration = Instance.new(Change.DecorationType, Part);
				table.insert(Decorations, Decoration);

				-- Register the decoration
				CreatedInstances[Decoration] = Decoration;

			end;

		end;

		-- Return the new decorations
		return Decorations;

	end;

	['SyncDecorate'] = function (Changes)
		-- Updates aspects of the given selection's decorations

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Make a list of allowed decoration type requests
		local AllowedDecorationTypes = { Smoke = true, Fire = true, Sparkles = true };

		-- Update each part's decorations
		for Part, Change in pairs(ChangeSet) do

			-- Make sure that the decoration type requested is valid
			if AllowedDecorationTypes[Change.DecorationType] then

				-- Grab the part's decoration
				local Decoration = Support.GetChildOfClass(Part, Change.DecorationType);

				-- Make sure the decoration exists
				if Decoration then

					-- Make the requested changes
					if Change.Color ~= nil then
						Decoration.Color = Change.Color;
					end;
					if Change.Opacity ~= nil then
						Decoration.Opacity = Change.Opacity;
					end;
					if Change.RiseVelocity ~= nil then
						Decoration.RiseVelocity = Change.RiseVelocity;
					end;
					if Change.Size ~= nil then
						Decoration.Size = Change.Size;
					end;
					if Change.Heat ~= nil then
						Decoration.Heat = Change.Heat;
					end;
					if Change.SecondaryColor ~= nil then
						Decoration.SecondaryColor = Change.SecondaryColor;
					end;
					if Change.SparkleColor ~= nil then
						Decoration.SparkleColor = Change.SparkleColor;
					end;

				end;

			end;

		end;

	end;

	['CreateMeshes'] = function (Changes)
		-- Creates meshes in the given parts

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Keep track of the newly created meshes
		local Meshes = {};

		-- Create each mesh
		for Part, Change in pairs(ChangeSet) do

			-- Create the mesh
			local Mesh = Instance.new('SpecialMesh', Part);
			table.insert(Meshes, Mesh);

			-- Register the mesh
			CreatedInstances[Mesh] = Mesh;

		end;

		-- Return the new meshes
		return Meshes;

	end;

	['SyncMesh'] = function (Changes)
		-- Updates aspects of the given selection's meshes

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Update each part's meshes
		for Part, Change in pairs(ChangeSet) do

			-- Grab the part's mesh
			local Mesh = Support.GetChildOfClass(Part, 'SpecialMesh');

			-- Make sure the mesh exists
			if Mesh then

				-- Make the requested changes
				if Change.VertexColor ~= nil then
					Mesh.VertexColor = Change.VertexColor;
				end;
				if Change.MeshType ~= nil then
					Mesh.MeshType = Change.MeshType;
				end;
				if Change.Scale ~= nil then
					Mesh.Scale = Change.Scale;
				end;
				if Change.Offset ~= nil then
					Mesh.Offset = Change.Offset;
				end;
				if Change.MeshId ~= nil then
					Mesh.MeshId = Change.MeshId;
				end;
				if Change.TextureId ~= nil then
					Mesh.TextureId = Change.TextureId;
				end;

			end;

		end;

	end;

	['CreateTextures'] = function (Changes)
		-- Creates textures in the given parts

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Make a list of allowed texture type requests
		local AllowedTextureTypes = { Texture = true, Decal = true };

		-- Keep track of the newly created textures
		local Textures = {};

		-- Create each texture
		for Part, Change in pairs(ChangeSet) do

			-- Make sure the requested light type is valid
			if AllowedTextureTypes[Change.TextureType] then

				-- Create the texture
				local Texture = Instance.new(Change.TextureType, Part);
				Texture.Face = Change.Face;
				table.insert(Textures, Texture);

				-- Register the texture
				CreatedInstances[Texture] = Texture;

			end;

		end;

		-- Return the new textures
		return Textures;

	end;

	['SyncTexture'] = function (Changes)
		-- Updates aspects of the given selection's textures

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Make a list of allowed texture type requests
		local AllowedTextureTypes = { Texture = true, Decal = true };

		-- Update each part's textures
		for Part, Change in pairs(ChangeSet) do

			-- Make sure that the texture type requested is valid
			if AllowedTextureTypes[Change.TextureType] then

				-- Get the right textures within the part
				for _, Texture in pairs(Part:GetChildren()) do
					if Texture.ClassName == Change.TextureType and Texture.Face == Change.Face then

						-- Perform the changes
						if Change.Texture ~= nil then
							Texture.Texture = Change.Texture;
						end;
						if Change.Transparency ~= nil then
							Texture.Transparency = Change.Transparency;
						end;
						if Change.StudsPerTileU ~= nil then
							Texture.StudsPerTileU = Change.StudsPerTileU;
						end;
						if Change.StudsPerTileV ~= nil then
							Texture.StudsPerTileV = Change.StudsPerTileV;
						end;

					end;
				end;

			end;

		end;

	end;

	['SyncAnchor'] = function (Changes)
		-- Updates parts server-side given their new anchor status

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Perform each change
		for Part, Change in pairs(ChangeSet) do
			Part.Anchored = Change.Anchored;
		end;

	end;

	['SyncCollision'] = function (Changes)
		-- Updates parts server-side given their new collision status

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Perform each change
		for Part, Change in pairs(ChangeSet) do
			Part.CanCollide = Change.CanCollide;
		end;

	end;

	['SyncMaterial'] = function (Changes)
		-- Updates parts server-side given their new material

		-- Grab a list of every part we're attempting to modify
		local Parts = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				table.insert(Parts, Change.Part);
			end;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Reorganize the changes
		local ChangeSet = {};
		for _, Change in pairs(Changes) do
			if Change.Part then
				ChangeSet[Change.Part] = Change;
			end;
		end;

		-- Perform each change
		for Part, Change in pairs(ChangeSet) do
			if Change.Material ~= nil then
				Part.Material = Change.Material;
			end;
			if Change.Transparency ~= nil then
				Part.Transparency = Change.Transparency;
			end;
			if Change.Reflectance ~= nil then
				Part.Reflectance = Change.Reflectance;
			end;
		end;

	end;

	['CreateWelds'] = function (Parts, TargetPart)
		-- Creates welds for the given parts to the target part

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to perform changes to these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		local Welds = {};

		-- Create the welds
		for _, Part in pairs(Parts) do

			-- Make sure we're not welding this part to itself
			if Part ~= TargetPart then

				-- Calculate the offset of the part from the target part
				local Offset = Part.CFrame:toObjectSpace(TargetPart.CFrame);

				-- Create the weld
				local Weld = Instance.new('Weld');
				Weld.Name = 'BTWeld';
				Weld.Part0 = TargetPart;
				Weld.Part1 = Part;
				Weld.C1 = Offset;
				Weld.Archivable = true;
				Weld.Parent = TargetPart;

				-- Register the weld
				CreatedInstances[Weld] = Weld;
				table.insert(Welds, Weld);

			end;

		end;

		-- Return the welds created
		return Welds;
	end;

	['RemoveWelds'] = function (Welds)
		-- Removes the given welds

		local Parts = {};

		-- Go through each weld
		for _, Weld in pairs(Welds) do

			-- Make sure each given weld is valid
			if Weld.ClassName ~= 'Weld' then
				return;
			end;

			-- Collect the relevant parts for this weld
			table.insert(Parts, Weld.Part0);
			table.insert(Parts, Weld.Part1);

		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

		local WeldsRemoved = 0;

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

		-- Go through each weld
		for _, Weld in pairs(Welds) do

			-- Check the permissions on each weld-related part
			local Part0Unauthorized = Security.ArePartsViolatingAreas({ Weld.Part0 }, Player, true, AreaPermissions);
			local Part1Unauthorized = Security.ArePartsViolatingAreas({ Weld.Part1 }, Player, true, AreaPermissions);

			-- If at least one of the involved parts is authorized, remove the weld
			if not Part0Unauthorized or not Part1Unauthorized then

				-- Register the weld
				CreatedInstances[Weld] = Weld;
				LastParents[Weld] = Weld.Parent;
				WeldsRemoved = WeldsRemoved + 1;

				-- Remove the weld
				Weld.Parent = nil;

			end;

		end;

		-- Return the number of welds removed
		return WeldsRemoved;
	end;

	['UndoRemovedWelds'] = function (Welds)
		-- Restores the given removed welds

		local Parts = {};

		-- Go through each weld
		for _, Weld in pairs(Welds) do

			-- Make sure each given weld is valid
			if Weld.ClassName ~= 'Weld' then
				return;
			end;

			-- Make sure each weld has its old parent registered
			if not LastParents[Weld] then
				return;
			end;

			-- Collect the relevant parts for this weld
			table.insert(Parts, Weld.Part0);
			table.insert(Parts, Weld.Part1);

		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Go through each weld
		for _, Weld in pairs(Welds) do

			-- Check the permissions on each weld-related part
			local Part0Unauthorized = Security.ArePartsViolatingAreas({ Weld.Part0 }, Player, false, AreaPermissions);
			local Part1Unauthorized = Security.ArePartsViolatingAreas({ Weld.Part0 }, Player, false, AreaPermissions);

			-- If at least one of the involved parts is authorized, restore the weld
			if not Part0Unauthorized or not Part1Unauthorized then

				-- Store the part's current parent
				local LastParent = LastParents[Weld];
				LastParents[Weld] = Weld.Parent;

				-- Register the weld
				CreatedInstances[Weld] = Weld;

				-- Set the weld's parent to the last parent
				Weld.Parent = LastParent;

			end;

		end;

	end;

	['Export'] = function (Parts)
		-- Serializes, exports, and returns ID for importing given parts

		-- Offload action to server-side if API is running locally
		if RunService:IsClient() and not RunService:IsStudio() then
			return SyncAPI.ServerEndpoint:InvokeServer('Export', Parts);
		end;

		-- Ensure valid selection
		assert(type(Parts) == 'table', 'Invalid item table');

		-- Ensure there are items to export
		if #Parts == 0 then
			return;
		end;

		-- Ensure parts are selectable
		if not ArePartsSelectable(Parts) then
			return;
		end;

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

		-- Make sure the player is allowed to access these parts
		if Security.ArePartsViolatingAreas(Parts, Player, true, AreaPermissions) then
			return;
		end;

		-- Get all descendants of the parts
		local Items = Support.CloneTable(Parts);
		for _, Part in pairs(Parts) do
			Support.ConcatTable(Items, Support.GetAllDescendants(Part));
		end;

		-- After confirming permissions, serialize parts
		local SerializedBuildData = Serialization.SerializeModel(Items);

		-- Push serialized data to server
		local Response = HttpService:JSONDecode(
			HttpService:PostAsync(
				'http://f3xteam.com/bt/export',
				HttpService:JSONEncode { data = SerializedBuildData, version = 3, userId = (Player and Player.UserId) },
				Enum.HttpContentType.ApplicationJson,
				true
			)
		);

		-- Return creation ID on success
		if Response.success then
			return Response.id;
		else
			error('Export failed due to server-side error', 2);
		end;

	end;

	['IsHttpServiceEnabled'] = function ()
		-- Returns whether HttpService is enabled

		-- Offload action to server-side if API is running locally
		if RunService:IsClient() and not RunService:IsStudio() then
			return SyncAPI.ServerEndpoint:InvokeServer('IsHttpServiceEnabled');
		end;

		-- For in-game tool, return cached status if available
		if ToolMode == 'Tool' and (IsHttpServiceEnabled ~= nil) then
			return IsHttpServiceEnabled;
		end;

		-- Perform test HTTP request
		local Success, Error = pcall(function ()
			return HttpService:GetAsync('http://google.com');
		end);

		-- Determine whether HttpService is enabled
		if not Success and Error:match 'Http requests are not enabled' then
			IsHttpServiceEnabled = false;
		elseif Success then
			IsHttpServiceEnabled = true;
		end;

		-- Return HttpService status
		return IsHttpServiceEnabled;

	end;

	['ExtractMeshFromAsset'] = function (AssetId)
		-- Returns the first found mesh in the given asset

		-- Offload action to server-side if API is running locally
		if RunService:IsClient() and not RunService:IsStudio() then
			return SyncAPI.ServerEndpoint:InvokeServer('ExtractMeshFromAsset', AssetId);
		end;

		-- Ensure valid asset ID is given
		assert(type(AssetId) == 'number', 'Invalid asset ID');

		-- Return parsed response from API
		return HttpService:JSONDecode(
			HttpService:GetAsync('http://f3xteam.com/bt/getFirstMeshData/' .. AssetId)
		);

	end;

	['ExtractImageFromDecal'] = function (DecalAssetId)
		-- Returns the first image found in the given decal asset

		-- Offload action to server-side if API is running locally
		if RunService:IsClient() and not RunService:IsStudio() then
			return SyncAPI.ServerEndpoint:InvokeServer('ExtractImageFromDecal', DecalAssetId);
		end;

		-- Return direct response from the API
		return HttpService:GetAsync('http://f3xteam.com/bt/getDecalImageID/' .. DecalAssetId);

	end;

	['SetMouseLockEnabled'] = function (Enabled)
		-- Sets whether mouse lock is enabled for the current player

		-- Offload action to server-side if API is running locally
		if RunService:IsClient() and not RunService:IsStudio() then
			return SyncAPI.ServerEndpoint:InvokeServer('SetMouseLockEnabled', Enabled);
		end;

		-- Set whether mouse lock is enabled
		Player.DevEnableMouseLock = Enabled;

	end;

};

function ArePartsSelectable(Parts)
	-- Returns whether the parts are selectable

	-- Check whether each part is selectable
	for _, Part in pairs(Parts) do
		if not Part:IsA 'BasePart' or Part.Locked then
			return false;
		end;
	end;

	-- Return true if all parts are selectable
	return true;

end;
