if Mode=="\084\111\111\108"then AssignHotkey({"\076\101\102\116\067\111\110\116\114\111\108","\090"},History.Undo)AssignHotkey({"\082\105\103\104\116\067\111\110\116\114\111\108","\090"},History.Undo)AssignHotkey({"\076\101\102\116\067\111\110\116\114\111\108","\089"},History.Redo)AssignHotkey({"\082\105\103\104\116\067\111\110\116\114\111\108","\089"},History.Redo)end local function f(f,S)local v=0 while f~=S do v=v+1 f=f.Parent end return v end local function S(S)local v,h for S,l in ipairs(S)do local u=f(l,game)if not h or u<h then v=l h=u end end return v and v.Parent or nil end function CloneSelection()if#Selection.Items==0 then return end local f=SyncAPI:Invoke("\067\108\111\110\101",Selection.Items,S(Selection.Items))local v={Clones=f,Unapply=function(f)Selection.Remove(f.Clones,false)SyncAPI:Invoke("\082\101\109\111\118\101",f.Clones)end,Apply=function(f)SyncAPI:Invoke("\085\110\100\111\082\101\109\111\118\101",f.Clones)end}History.Add(v)Selection.Replace(f);(coroutine.wrap(Selection.FlashOutlines))()end function DeleteSelection()local f={Parts=Support.CloneTable(Selection.Items),Unapply=function(f)SyncAPI:Invoke("\085\110\100\111\082\101\109\111\118\101",f.Parts)Selection.Replace(f.Parts)end;Apply=function(f)Selection.Remove(f.Parts,false)SyncAPI:Invoke("\082\101\109\111\118\101",f.Parts)end}Selection.Remove(f.Parts,false)SyncAPI:Invoke("\082\101\109\111\118\101",f.Parts)History.Add(f)end

if Mode == 'Tool' then
	AssignHotkey({ 'LeftControl', 'Z' }, History.Undo);
	AssignHotkey({ 'RightControl', 'Z' }, History.Undo);
	AssignHotkey({ 'LeftControl', 'Y' }, History.Redo);
	AssignHotkey({ 'RightControl', 'Y' }, History.Redo);
end;

local function GetDepthFromAncestor(Item, Ancestor)
	-- Returns the depth of `Item` from `Ancestor`

	local Depth = 0

	-- Go through ancestry until reaching `Ancestor`
	while Item ~= Ancestor do
		Depth = Depth + 1
		Item = Item.Parent
	end

	-- Return depth
	return Depth
end

local function GetHighestParent(Items)
	local HighestItem, HighestItemDepth

	-- Calculate depth of each item & keep highest
	for _, Item in ipairs(Items) do
		local Depth = GetDepthFromAncestor(Item, game)
		if (not HighestItemDepth) or (Depth < HighestItemDepth) then
			HighestItem = Item
			HighestItemDepth = Depth
		end
	end

	-- Return parent of highest item
	return HighestItem and HighestItem.Parent or nil
end

function CloneSelection()
	-- Clones selected parts

	-- Make sure that there are items in the selection
	if #Selection.Items == 0 then
		return;
	end;

	-- Send the cloning request to the server
	local Clones = SyncAPI:Invoke('Clone', Selection.Items, GetHighestParent(Selection.Items))

	-- Put together the history record
	local HistoryRecord = {
		Clones = Clones;

		Unapply = function (HistoryRecord)
			-- Reverts this change

			-- Deselect the clones
			Selection.Remove(HistoryRecord.Clones, false);

			-- Remove the clones
			SyncAPI:Invoke('Remove', HistoryRecord.Clones);

		end;

		Apply = function (HistoryRecord)
			-- Reapplies this change

			-- Restore the clones
			SyncAPI:Invoke('UndoRemove', HistoryRecord.Clones);

		end;

	};

	-- Register the history record
	History.Add(HistoryRecord);

	-- Select the clones
	Selection.Replace(Clones);

	-- Flash the outlines of the new parts
	coroutine.wrap(Selection.FlashOutlines)();

end;

function DeleteSelection()
	-- Deletes selected items

	-- Put together the history record
	local HistoryRecord = {
		Parts = Support.CloneTable(Selection.Items);

		Unapply = function (HistoryRecord)
			-- Reverts this change

			-- Restore the parts
			SyncAPI:Invoke('UndoRemove', HistoryRecord.Parts);

			-- Select the restored parts
			Selection.Replace(HistoryRecord.Parts);

		end;

		Apply = function (HistoryRecord)
			-- Applies this change

			-- Deselect the parts
			Selection.Remove(HistoryRecord.Parts, false);

			-- Remove the parts
			SyncAPI:Invoke('Remove', HistoryRecord.Parts);

		end;

	};

	-- Deselect parts before deleting
	Selection.Remove(HistoryRecord.Parts, false);

	-- Perform the removal
	SyncAPI:Invoke('Remove', HistoryRecord.Parts);

	-- Register the history record
	History.Add(HistoryRecord);

end;
