<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
	<External>null</External>
	<External>nil</External>
	<Item class="Model" referent="RBX51D25DC47D7342E8AF5CB4979E7A7A24">
		<Properties>
			<CoordinateFrame name="ModelInPrimary">
				<X>0</X>
				<Y>0</Y>
				<Z>0</Z>
				<R00>1</R00>
				<R01>0</R01>
				<R02>0</R02>
				<R10>0</R10>
				<R11>1</R11>
				<R12>0</R12>
				<R20>0</R20>
				<R21>0</R21>
				<R22>1</R22>
			</CoordinateFrame>
			<string name="Name">UIEditor</string>
			<Ref name="PrimaryPart">null</Ref>
			<BinaryString name="Tags"></BinaryString>
		</Properties>
		<Item class="Script" referent="RBX1FB432CD8E694E69AE99819783377BD2">
			<Properties>
				<bool name="Disabled">false</bool>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">main</string>
				<string name="ScriptGuid">{34A19B7D-1583-4262-A391-F01E3CD7D973}</string>
				<ProtectedString name="Source"><![CDATA[local plugin, settings = plugin, settings

local versionString = "v1.1"

-- Module scripts
local ActionMediator		= require(script.Parent.ActionMediator)
local CoreGuiManager		= require(script.Parent.CoreGuiManager)
local DoubleClickDetector	= require(script.Parent.DoubleClickDetector)
local FFlag					= require(script.Parent.FFlag)
local RotationBox			= require(script.Parent.RotationBox)
local Rubberband			= require(script.Parent.Rubberband)
local SizeBox				= require(script.Parent.SizeBox)
local DistanceLinesManager	= require(script.Parent.DistanceLinesManager)
local TextEditor			= require(script.Parent.TextEditor)
local Utility				= require(script.Parent.Utility)
local GlobalValues 			= require(script.Parent.GlobalValues)
local InstanceInfo			= require(script.Parent.InstanceInfo)

local Select				= require(script.Parent.Select)
local Resize				= require(script.Parent.Resize)
local Rotate				= require(script.Parent.Rotate)
local Move					= require(script.Parent.Move)
local MouseIconManager		= require(script.Parent.MouseIconManager)

local SelectionManager		= require(script.Parent.SelectionManager)

local SnappingPointManager	= require(script.Parent.SnappingPointManager)

local Analytics				= require(script.Parent.Analytics)

-- Services
local ChangeHistoryService	= game:GetService("ChangeHistoryService")
local UserInputService		= game:GetService("UserInputService")
local SelectionService		= game:GetService("Selection")

-- Flags
local FFlagStudioUIEditorV2Alpha = FFlag:isEnabled("StudioUIEditorV2Alpha")

-- Variables
local inputBeganEvent = nil
local inputChangedEvent = nil
local inputEndedEvent = nil
local selectionChangedEvent = nil
local deactivationEvent = nil
local dragEnterEvent = nil

local undoEvent = nil
local redoEvent = nil

local selectedInstancesPropertyChangedEvent = nil
local m_totalInputs = 0

local m_mouseDown = false

local m_previousSelection = {}

-- Constants
local BUFFER_SIZE_MINIMUM = 5


-- Functions

-- Injects all the modules that the ActionMediator needs.
local function configureActionMediator()
	Move:setActionMediator(ActionMediator)
	Resize:setActionMediator(ActionMediator)
	Rotate:setActionMediator(ActionMediator)
	Rubberband:setActionMediator(ActionMediator)
	TextEditor:setActionMediator(ActionMediator)
	
	ActionMediator:setMove(Move)
	ActionMediator:setResize(Resize)
	ActionMediator:setRotate(Rotate)
	ActionMediator:setRubberband(Rubberband)
	ActionMediator:setTextEditor(TextEditor)
	
	ActionMediator:setDistanceLinesManager(DistanceLinesManager)
	ActionMediator:setRotationBox(RotationBox)
	ActionMediator:setSizeBox(SizeBox)
end

-- Events

local function onDoubleClick(inputObject)
	local location = Vector2.new(inputObject.Position.x, inputObject.Position.y)
	local objectsAtPoint = Select:getGuiObjectsAtPoint(location)
	
	if (#objectsAtPoint > 0) and 
		(objectsAtPoint[1]:IsA("TextLabel") or
		objectsAtPoint[1]:IsA("TextButton") or
		objectsAtPoint[1]:IsA("TextBox")) then
	
		TextEditor:startEditingInstance(objectsAtPoint[1])
		Resize:hide()
		
		return true
	end
	
	return false
end

local function onInstanceChanged(instance, property)
	Resize:updatePosition()
	
	if FFlagStudioUIEditorV2Alpha then
		DistanceLinesManager:update()
		DistanceLinesManager:setVisible(true)
		Rotate:update()
		SizeBox:update()
	end
end

local function onInputBegan(inputObject)

	if (TextEditor:isCurrentlyEditing()) then
		return
	end
	
	if (inputObject.UserInputType == Enum.UserInputType.MouseButton1) then
				
		if (UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or 
			UserInputService:IsKeyDown(Enum.KeyCode.RightShift)) then
				m_previousSelection = SelectionManager:getRawSelection()
		end
		
		
		selectedInstancesPropertyChangedEvent = SelectionManager:disconnectSelectionInstancesChanged(selectedInstancesPropertyChangedEvent)
		
		m_mouseDown = true
		local location = Vector2.new(inputObject.Position.X, inputObject.Position.Y)
		
		if FFlagStudioUIEditorV2Alpha then
			if Resize:isOverAHandle() then
				Resize:startDrag(location)
				return
			elseif Rotate:isOverAHandle() then
				Rotate:onMouseDown(location)
				return
			end
		else
			if (Resize:DEPRECATED_isOverHandle(location)) then
				Resize:startDrag(location)
				return
			end
		end
		
		local item = Select:selectTopLevelItemAtPoint(location)
		
		Move:startDrag(location)
		
		if not FFlagStudioUIEditorV2Alpha then
			--Double click to activate text editor
			if (DoubleClickDetector:isDoubleClick() and not (UserInputService:IsKeyDown(Enum.KeyCode.LeftAlt) or UserInputService:IsKeyDown(Enum.KeyCode.RightAlt))) then
				if (onDoubleClick(inputObject)) then
					return
				end
			end
		end
		
		if (not item) then
			Rubberband:startRubberbandDrag(location)
		else
			InstanceInfo:isVisible(item, true)
		end
--		
	elseif (inputObject.UserInputType == Enum.UserInputType.Keyboard) then
		
		--[[
		if (inputObject.KeyCode == Enum.KeyCode.Left) then
			Move:bump(Move.LEFT)
		elseif (inputObject.KeyCode == Enum.KeyCode.Right) then
			Move:bump(Move.RIGHT)
		elseif (inputObject.KeyCode == Enum.KeyCode.Up) then
			Move:bump(Move.UP)
		elseif (inputObject.KeyCode == Enum.KeyCode.Down) then
			Move:bump(Move.DOWN)
		else--]]
		if (inputObject.KeyCode == Enum.KeyCode.U and 
			(UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or
			UserInputService:IsKeyDown(Enum.KeyCode.RightShift))) then
			
			GlobalValues:toggleGridType()
		elseif (inputObject.KeyCode == Enum.KeyCode.A and UserInputService:IsKeyDown(Enum.KeyCode.LeftControl)) then
			--We will eventually want an action overriding system
			--Select all action has already been fired
			SelectionManager:setSelection(Select:getGuiObjects())
		end
	end
end

local function onInputEnded(inputObject)
	if (inputObject.UserInputType == Enum.UserInputType.MouseButton1) then
		m_mouseDown = false
		
		local location = Vector2.new(inputObject.Position.X, inputObject.Position.Y)
		
		if (Resize:isDragInProgress()) then
			Resize:finishDrag()
		end
		
		if (Rubberband:isDragInProgress()) then
			if (UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or 
				UserInputService:IsKeyDown(Enum.KeyCode.RightShift)) then
				Select:toggleSelectionOfAllObjectsInBounds(m_previousSelection, Rubberband:getBounds())
			else
				Select:selectAllObjectsInBounds(Rubberband:getBounds())
			end
						
			if (#SelectionManager:getRawSelection() > 0) then
				Analytics:reportEvent("DragSelect")
			end
			
			Rubberband:finishRubberbandDrag()
			m_previousSelection = {}
		end
		
		if Move:isDragInProgress() then
			Move:finishDrag(location)
		end

		if not FFlagStudioUIEditorV2Alpha then
			if (not TextEditor:isCurrentlyEditing()) then
				Resize:show()
				Resize:updatePosition()
			end
		end
		
		if FFlagStudioUIEditorV2Alpha then
			-- Double click to activate text editor. This check should happen onInputEnded instead
			-- of onInputBegan because otherwise the move will end after text editing has begun. Ending
			-- a move will show the resize handles (and size box and distance lines if there's one object). 
			if (DoubleClickDetector:isDoubleClick() and not (UserInputService:IsKeyDown(Enum.KeyCode.LeftAlt) or UserInputService:IsKeyDown(Enum.KeyCode.RightAlt))) then
				if (onDoubleClick(inputObject)) then
					return
				end
			end
		end
		
		if not selectedInstancesPropertyChangedEvent then
			selectedInstancesPropertyChangedEvent = SelectionManager:connectSelectionInstancesChanged(onInstanceChanged)
		end
		
		if FFlagStudioUIEditorV2Alpha then
			Rotate:onMouseUp(location)
			
			if Resize:isOverAHandle() then
				Resize:updateMouseIcon()
			elseif Rotate:isOverAHandle() then
				Rotate:updateMouseIcon()
			else
				MouseIconManager:setToDefaultIcon()
			end
			
			Resize:updateHandleHighlight()
		end
	end
	
	
end

local function onInputChanged(inputObject)
	if (TextEditor:isCurrentlyEditing()) then return end
	
	if (inputObject.UserInputType == Enum.UserInputType.MouseMovement) then

		local location = Vector2.new(inputObject.Position.x, inputObject.Position.y)
		
		local actionPerformed = false
		
		if (Resize:isDragInProgress()) then
			Resize:updateDrag(location)
			return
		end
		
		if (Rubberband:isDragInProgress()) then
			Rubberband:updateRubberband(location)
			
			if (UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or 
				UserInputService:IsKeyDown(Enum.KeyCode.RightShift)) then
				Select:toggleSelectionOfAllObjectsInBounds(m_previousSelection, Rubberband:getBounds())
			else
				Select:selectAllObjectsInBounds(Rubberband:getBounds())
			end
			
			if not FFlagStudioUIEditorV2Alpha then
				Resize:hide()
			end
			return
		end
		
		if (Move:isDragInProgress()) then
			Move:updateDrag(location)
			return
		end
		
		if FFlagStudioUIEditorV2Alpha then
			Rotate:onMouseMove(location)
		
			-- Handle mouse icon updates. Resize takes precedence over rotate.
			if Resize:isOverAHandle() and not Rotate:isRotating() then
				Resize:updateMouseIcon()
			elseif Rotate:isOverAHandle() then
				Rotate:updateMouseIcon()
			elseif not Rotate:isRotating() then
				MouseIconManager:setToDefaultIcon()
			end
			
			Resize:updateHandleHighlight(Rotate:isRotating())
		else
			Resize:DEPRECATED_highlightHandles(location)
		end
	end
end

local function onSelectionChanged()
	SelectionManager:onSelectionChanged()
	if not FFlagStudioUIEditorV2Alpha then
		Resize:onSelectionChanged()
		Resize:updatePosition()
	end	
	
	if FFlagStudioUIEditorV2Alpha then
		if not Rubberband:isDragInProgress() then
			Resize:onSelectionChanged()
			SizeBox:onSelectionChanged()
			DistanceLinesManager:onSelectionChanged()
			Rotate:onSelectionChanged()
		end
	end
	
	SnappingPointManager:generateSnappingLines()
end

function onDragEnter(instances)	
	m_mouseDown = true	
	local location = Vector2.new(plugin:GetMouse().X, plugin:GetMouse().Y)
	SelectionManager:setSelection(instances)
	SelectionManager:onSelectionChanged()
	Move:startDrag(location)
end

local function onUndo(waypoint)
	Resize:updatePosition()
end

local function onRedo(waypoint)
	Resize:updatePosition()
end

-----------------------------------
---------PLUGIN BOILERPLATE--------
-----------------------------------

local loaded = false
local on = false

local toolbar = plugin and plugin:CreateToolbar("RobloxUIEditor")
local toolbarButton = toolbar and toolbar:CreateButton("RobloxUIEditor", "RobloxUIEditor", "")

function Off()
	if not on then return end
	on = false
	
	Analytics:reportEvent("Disabled")
	
	inputBeganEvent:disconnect()
	inputChangedEvent:disconnect()
	inputEndedEvent:disconnect()
	selectionChangedEvent:disconnect()
	deactivationEvent:disconnect()
	dragEnterEvent:disconnect()
	
	selectedInstancesPropertyChangedEvent = SelectionManager:disconnectSelectionInstancesChanged(selectedInstancesPropertyChangedEvent)
	
	if not FFlagStudioUIEditorV2Alpha then
		Resize:DEPRECATED_clearAdornments()
	end
	
	if FFlagStudioUIEditorV2Alpha then
		SizeBox:Off()
		DistanceLinesManager:Off()
		MouseIconManager:Off()
		Resize:Off()
		Rotate:Off()
		RotationBox:Off()
	end
	
	toolbarButton:SetActive(false)
end

function On()
	if on then return end
	
	Analytics:reportEvent("Enabled")
	
	plugin:Activate(true)
	toolbarButton:SetActive(true)
	
	inputBeganEvent = UserInputService.InputBegan:connect(onInputBegan)	
	inputChangedEvent = UserInputService.InputChanged:connect(onInputChanged)
	inputEndedEvent = UserInputService.InputEnded:connect(onInputEnded)
	selectionChangedEvent = SelectionService.SelectionChanged:connect(onSelectionChanged)
	dragEnterEvent = plugin:GetMouse().DragEnter:connect(onDragEnter)
	
	deactivationEvent = plugin.Deactivation:connect(Off)
	
	selectedInstancesPropertyChangedEvent = SelectionManager:connectSelectionInstancesChanged(onInstanceChanged)
	undoEvent = ChangeHistoryService.OnUndo:connect(onUndo)
	redoEvent = ChangeHistoryService.OnRedo:connect(onRedo)
	
	SnappingPointManager:setThreshold(5)
	
	if not FFlagStudioUIEditorV2Alpha then
		Resize:DEPRECATED_showResizeAdorns()
	end
	
	if FFlagStudioUIEditorV2Alpha then
		SizeBox:On()
		DistanceLinesManager:On()
		MouseIconManager:On(plugin:GetMouse())
		Resize:On()
		Rotate:On()
		RotationBox:On()
		
		-- Must do onSelectionChanged, otherwise you can select an object before
		-- the UI Editor is turned on and it won't be registered.	
		onSelectionChanged()
		
		configureActionMediator()
	end
	
	on = true
end

if toolbarButton then
	toolbarButton.Click:connect(function()
		if on then
			Off()
		else
			On()
		end
	end)
end

loaded = true]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX7F2D1FB543A542A68F73F347E654B0CF">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">Rubberband</string>
				<string name="ScriptGuid">{E5C0F730-A606-4984-B9E0-5BD9342AC9BA}</string>
				<ProtectedString name="Source"><![CDATA[--[[
	The Rubberband is displayed when the user clicks outside a GUI object and
	drags the mouse. GUI object inside the rubberband are selected.
--]]

-- Module scripts
local FFlag	= require(script.Parent.FFlag)

-- Services
local CoreGuiManager = require(script.Parent.CoreGuiManager)

-- Flags
local FFlagStudioUIEditorV2Alpha = FFlag:isEnabled("StudioUIEditorV2Alpha")

local m_actionMediator = nil

local m_rubberbandDragInProgress = false
local m_selectionBoxStart = nil
local m_selectionBoxEnd = nil

local m_selectionScreenGui = nil
local m_rubberbandFrames = {}

--constant
local RUBBERBAND_BORDER_SIZE = 1
local RUBBERBAND_COLOR = Color3.new(0.7019, 0.7019, 0.7019)

local function createFrame(parent, border, color)
	local frame = Instance.new("Frame", parent)
	frame.BorderSizePixel = border
	frame.BackgroundColor3 = color
	return frame
end

local function createRubberband()
	m_selectionScreenGui = Instance.new("ScreenGui", CoreGuiManager:findOrCreateFolder("Rubberband"))
	
	for i = 1, 4 do
		m_rubberbandFrames[i] = createFrame(m_selectionScreenGui, 0, RUBBERBAND_COLOR)
	end
end

local Rubberband = {}

function Rubberband:startRubberbandDrag(location)
	m_rubberbandDragInProgress = true
	m_selectionBoxStart = location
	m_selectionBoxEnd = location
	
	if (not m_selectionScreenGui) then
		createRubberband()
	end
	
	if FFlagStudioUIEditorV2Alpha then
		m_actionMediator:onRubberbandBegan(location)
	end
end

function Rubberband:updateRubberband(location)
	if (not m_rubberbandDragInProgress) then return end
	
	m_selectionBoxEnd = location	
	local size = m_selectionBoxEnd - m_selectionBoxStart
	
	m_rubberbandFrames[1].Size = UDim2.new(0, RUBBERBAND_BORDER_SIZE, 0, size.Y + RUBBERBAND_BORDER_SIZE)
	m_rubberbandFrames[2].Size = UDim2.new(0, RUBBERBAND_BORDER_SIZE, 0, size.Y + RUBBERBAND_BORDER_SIZE)
	m_rubberbandFrames[3].Size = UDim2.new(0, size.X + RUBBERBAND_BORDER_SIZE, 0, RUBBERBAND_BORDER_SIZE)
	m_rubberbandFrames[4].Size = UDim2.new(0, size.X + RUBBERBAND_BORDER_SIZE, 0, RUBBERBAND_BORDER_SIZE)
	
	m_rubberbandFrames[1].Position = UDim2.new(0, m_selectionBoxStart.X, 0, m_selectionBoxStart.Y)
	m_rubberbandFrames[2].Position = UDim2.new(0, m_selectionBoxStart.X + size.X, 0, m_selectionBoxStart.Y)
	m_rubberbandFrames[3].Position = UDim2.new(0, m_selectionBoxStart.X, 0, m_selectionBoxStart.Y)
	m_rubberbandFrames[4].Position = UDim2.new(0, m_selectionBoxStart.X, 0, m_selectionBoxStart.Y + size.Y)
end

function Rubberband:finishRubberbandDrag()
	if (not m_rubberbandDragInProgress) then return end
	
	m_rubberbandDragInProgress = false
	m_selectionBoxStart = nil
	
	if (m_selectionScreenGui) then
		m_selectionScreenGui:Destroy()
		m_selectionScreenGui = nil
		m_rubberbandFrames = {}
	end
	
	if FFlagStudioUIEditorV2Alpha then
		m_actionMediator:onRubberbandEnded()
	end
end

function Rubberband:isDragInProgress()
	return m_rubberbandDragInProgress-- and m_selectionBoxStart ~= m_selectionBoxEnd
end

function Rubberband:getBounds()
	return m_selectionBoxStart, m_selectionBoxEnd
end

function Rubberband:setActionMediator(actionMediator)
	m_actionMediator = actionMediator
end

return Rubberband
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX7C4DDFA5C1DA4D73BCD139322D2D8E4F">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">CoreGuiManager</string>
				<string name="ScriptGuid">{AE0B6978-A31E-4841-8C29-B9D825E9FF12}</string>
				<ProtectedString name="Source"><![CDATA[-----------------------------------
-----------CoreGuiManager----------
-----------------------------------
--[[
	This is a simple module script which creates or returns existing folders
	underneath the main plugin folder under the coreGuiService
--]]

local m_mainFolder = nil

local CoreGui = game:GetService("CoreGui")

local function createFolder(name, parent)
	local folder = Instance.new("Folder")
	folder.Name = name
	folder.Parent = parent
	return folder
end

local function createScreenGui(name, parent)
	local sg = Instance.new("ScreenGui")
	sg.Name = name
	sg.Parent = parent
	return sg
end

local function getMainFolder()
	if (not m_mainFolder) then
		m_mainFolder = createFolder("RobloxGUIEditor", CoreGui)
	end
	return m_mainFolder
end

local CoreGuiManager = {}

function CoreGuiManager:findOrCreateFolder(name)
	local folder = getMainFolder():FindFirstChild(name)
	if (not folder) then
		folder = createFolder(name, getMainFolder())
	end
	return folder
end

function CoreGuiManager:findOrCreateScreenGui(name)
	local sg = getMainFolder():FindFirstChild(name)
	if (not sg) then
		sg = createScreenGui(name, getMainFolder())
	end
	return sg
end

return CoreGuiManager
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX86112528C5C8404AB7BBE3CD22E65813">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">Utility</string>
				<string name="ScriptGuid">{B09747B4-F704-498A-B54F-A300C0E8CD2A}</string>
				<ProtectedString name="Source"><![CDATA[local Error = require(script.Parent.Error)

local Utility = {}

-- bool Utility:tablesAreEquivalent(table t1, table t2)
function Utility:tablesAreEquivalent(t1, t2)
	if #t1 ~= #t2 then return false end
	
	for i = 1, #t1 do
		if t1[i] ~= t2[i] then return false end
	end
	return true	
end

-- int Utility:findItemInTable(? item, table t)
function Utility:findItemInTable(item, t)
	if not item then return 0 end
	for i = 1, #t do
		if (t[i] == item) then
			return i
		end
	end
	return 0
end

-- void Utility:removeItemFromTable(? item, table t)
function Utility:removeItemFromTable(item, t)
	local index = Utility:findItemInTable(item, t)
	if (index > 0) then
		table.remove(t, index)
		return true
	end
	return false
end

-- int Utility:mathattanDistance(Vector2 v)
function Utility:manhattanDistance(v)
	return math.abs(v.X) + math.abs(v.Y)
end

-- Returns the cross product between two vectors.
--
-- double Utility:crossVector2(Vector2 v1, Vector2 v2)
function Utility:crossVector2(v1, v2)
	return v1.X*v2.Y - v1.Y*v2.X
end

-- Returns the angle in radians between two vectors. 
--
-- double Utility:angleVector2(Vector2 v1, Vector2 v2)
function Utility:angleVector2(v1, v2)
	-- We use this for when rotating the selected object. This method
	-- works better than the method we use in the transform dragger tool.
	-- See https://stackoverflow.com/questions/21483999/using-atan2-to-find-angle-between-two-vectors
	return math.atan2(Utility:crossVector2(v1, v2), v1:Dot(v2))
end

-- Vector2 Utility:floorVector2(Vector2 v)
function Utility:floorVector2(v)
	return Vector2.new(math.floor(v.X), math.floor(v.Y))
end

-- Vector2 Utility:minVector2(Vector2 v1, Vector2 v2)
function Utility:minVector2(v1, v2)
	return Vector2.new(math.min(v1.X, v2.X), math.min(v1.Y, v2.Y))
end

-- Vector2 Utility:maxVector2(Vector2 v1, Vector2 v2)
function Utility:maxVector2(v1, v2)
	return Vector2.new(math.max(v1.X, v2.X), math.max(v1.Y, v2.Y))
end

-- UDim2 Utility:vector2ToUDim2Offset(Vector2 v)
function Utility:vector2ToUDim2Offset(v1)
	return UDim2.new(0, v1.X, 0, v1.Y)
end

-- num or nil Utility:minOrNil(num v1, num v2)
function Utility:minOrNil(v1, v2)
	if not v1 then return v2 end
	if not v2 then return v1 end
	
	return math.min(v1, v2)
end

-- num or nil Utility:maxOrNil(num v1, num v2)
function Utility:maxOrNil(v1, v2)
	if not v1 then return v2 end
	if not v2 then return v1 end
	
	return math.max(v1, v2)
end

-- bool Utility:isOnlyScaleUDim2(UDim2 value)
function Utility:isOnlyScaleUDim2(value)
	return (value.X.Offset == 0 and value.Y.Offset == 0) and
			(value.X.Scale ~=0 or value.Y.Scale ~= 0)
end

-- bool Utility:isOnlyOffsetUDim2(UDim2 value)
function Utility:isOnlyOffsetUDim2(value)
	return (value.X.Scale == 0 and value.Y.Scale == 0) and
			(value.X.Offset ~=0 or value.Y.Offset ~= 0)
end

-- num or Vector2 Utility:distance((num or Vector2) v1, (num or Vector2) v2)
function Utility:distance(v1, v2)
	local v1IsNumber = type(v1) == "number"
	local v2IsNumber = type(v2) == "number"
	if (v1IsNumber and v2IsNumber) then
		return math.abs(v2 - v1)
	elseif (v1IsNumber or v2IsNumber) then
		Error("passed in one number and one non number")
	else
		return (v2 - v1).magnitude
	end
end

-- table(mt ?) Utility:cloneTable(table(mt ?) t)
function Utility:cloneTable(t)
	local newTable = {}

	local mt = getmetatable(t)
	local newMt = nil
	
	for k, v in pairs(t) do
		if (type(v) == "table") then
			if v == mt then
				v = Utility:cloneTable(v)
				newMt = v
			else
				v = Utility:cloneTable(v)
			end
		end
		newTable[k] = v
	end
	
	if mt ~= nil and newMt == nil then
		newMt = Utility:cloneTable(mt)
	end	
	
	if newMt then
		setmetatable(newTable, newMt)
	end
	
	return newTable
end

--table Utility:joinTables(table t1, table t2)
function Utility:joinTables(t1, t2)
	local newTable = Utility:cloneTable(t1)
	
	for i = 1, #t2 do
		table.insert(newTable, t2[i])
	end
	
	return newTable
end

return Utility
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX16FB940FEB0147D5849F356DEA38159E">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">DoubleClickDetector</string>
				<string name="ScriptGuid">{D437651A-E23A-4FEC-9917-3B60B6DF46C6}</string>
				<ProtectedString name="Source"><![CDATA[
local m_lastClickTime = nil
local DOUBLE_CLICK_TIME_BUFFER = 0.3

local DoubleClickDetector = {}

function DoubleClickDetector:isDoubleClick()
	local currentTime = tick()
	if (m_lastClickTime and m_lastClickTime + DOUBLE_CLICK_TIME_BUFFER >= currentTime) then
		m_lastClickTime = nil
		return true
	end
	
	m_lastClickTime = currentTime
	return false
end

return DoubleClickDetector

]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX0CDD321579484011B6EDD81EE83FB611">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">TextEditor</string>
				<string name="ScriptGuid">{FAD895E4-EDA8-4C2A-A990-546FF1D94457}</string>
				<ProtectedString name="Source"><![CDATA[--[[
	The TextEditor is displayed when you double-click a TextLabel. It allows you
	to edit the text in the TextLabel.
--]]

-- Module scripts
local CoreGuiManager = require(script.Parent.CoreGuiManager)
local FFlag	= require(script.Parent.FFlag)

-- Services
local ChangeHistoryService = game:GetService("ChangeHistoryService")

-- Flags
local FFlagStudioUIEditorV2Alpha = FFlag:isEnabled("StudioUIEditorV2Alpha")

-- Variables
local m_actionMediator = nil

local m_currentInstance = nil

local m_screenGui = nil
local m_textBox = nil

local m_originalText = ""

local m_focusLostConnection = nil

local TextEditor = {}

function TextEditor:updateInstance(inputObject)
	if not m_currentInstance then return false end
	
	if (inputObject.UserInputType == Enum.UserInputType.MouseButton1 and
		inputObject.UserInputState == Enum.UserInputState.Begin) then
	
		--check if outside
		local location = Vector2.new(inputObject.Position.x, inputObject.Position.y)
	end
end

function TextEditor:finishEditingInstance()
	m_currentInstance = nil
	
	if m_screenGui then
		
		m_screenGui:Destroy()
		m_screenGui = nil
		
		m_textBox:Destroy()
		m_textBox = nil
		
		m_focusLostConnection:disconnect()
		m_focusLostConnection = nil
	end
	
	ChangeHistoryService:SetWaypoint("Text Changed")
	
	if FFlagStudioUIEditorV2Alpha then
		m_actionMediator:onTextEditorEnded()
	end
end

function TextEditor:isCurrentlyEditing()
	return m_currentInstance ~= nil
end

function TextEditor:getCurrentInstance()
	return m_currentInstance
end

local function onFocusLost(enterPressed, inputObject)
	
	if (m_currentInstance) then
		m_currentInstance.Text = m_textBox.Text
	end
	
	TextEditor:finishEditingInstance()
end

function TextEditor:startEditingInstance(instance)
	m_currentInstance = instance
	
	local pos = instance.AbsolutePosition
	local size = instance.AbsoluteSize
	
	m_originalText = instance.Text
	instance.Text = ""
	
	if not m_screenGui then
		m_screenGui = Instance.new("ScreenGui", CoreGuiManager:findOrCreateFolder("TextEditor"))
		m_textBox = Instance.new("TextBox")
		
		m_textBox.Position = UDim2.new(0, pos.X, 0, pos.Y)
		m_textBox.Size = UDim2.new(0, size.X, 0, size.Y)
		
		m_textBox.BackgroundTransparency = 1
		m_textBox.BorderSizePixel = 0
		
		m_textBox.Font = m_currentInstance.Font
		m_textBox.TextColor3 = m_currentInstance.TextColor3
		m_textBox.Text = m_originalText
		m_textBox.TextSize = m_currentInstance.TextSize
		
		m_textBox.TextScaled = m_currentInstance.TextScaled
		
		m_textBox.TextWrapped = m_currentInstance.TextWrapped
		m_textBox.TextXAlignment = m_currentInstance.TextXAlignment
		m_textBox.TextYAlignment = m_currentInstance.TextYAlignment
		
		m_textBox.Parent = m_screenGui
		
		m_focusLostConnection = m_textBox.FocusLost:connect(onFocusLost)
		
		m_textBox.ClearTextOnFocus = false
		m_textBox:CaptureFocus()
		
		
		
	end
	
	if FFlagStudioUIEditorV2Alpha then
		m_actionMediator:onTextEditorBegan()
	end
end

function TextEditor:setActionMediator(actionMediator)
	m_actionMediator = actionMediator
end

return TextEditor
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBXF55B971676134800984B2560E5832344">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">Resize</string>
				<string name="ScriptGuid">{E2185AB6-C336-4E0C-8F88-7F1625A0EE8A}</string>
				<ProtectedString name="Source"><![CDATA[
--[[
	The Resize module handles resizing objects. It displays a bounding box and resize
	handles when one or more GUI objects are selected.
--]]

-- Modules
local AdornmentModule		= require(script.Parent.AdornmentModule)
local Analytics				= require(script.Parent.Analytics)
local CoreGuiManager		= require(script.Parent.CoreGuiManager)
local Convert				= require(script.Parent.Convert)
local Direction				= require(script.Parent.Enum.Direction)
local Extents2D				= require(script.Parent.Extents2D)
local FFlag					= require(script.Parent.FFlag)
local GlobalValues			= require(script.Parent.GlobalValues)
local MouseIconManager		= require(script.Parent.MouseIconManager)
local SelectionManager		= require(script.Parent.SelectionManager)
local SnappingPointManager	= require(script.Parent.SnappingPointManager)
local Utility				= require(script.Parent.Utility)

local SnappingType			= require(script.Parent.Enum.SnappingType)

-- Services
local ChangeHistoryService = game:GetService("ChangeHistoryService")
local UserInputService = game:GetService("UserInputService")

-- Flags
local FFlagStudioUIEditorV2Alpha = FFlag:isEnabled("StudioUIEditorV2Alpha")

-- Constants
local MINIMUM_SIZE = 1
local HANDLE_POSITION_OFFSET = 3

local HOVER_COLOR = FFlagStudioUIEditorV2Alpha and Color3.fromRGB(255, 255, 255) or Color3.new(1,1,1)
local BASE_COLOR = FFlagStudioUIEditorV2Alpha and Color3.fromRGB(255, 255, 255) or Color3.new(0.8, 0.8, 0.8)
local HANDLE_BORDER_COLOR = Color3.fromRGB(136, 136, 136)
local BOUNDING_BOX_COLOR = Color3.new(0, 0, 0)
local HANDLE_OFFSET = Vector2.new(1, 1)
local HANDLE_SIZE = FFlagStudioUIEditorV2Alpha and 8 or 9

local BORDER_SIZE = 1 -- The border is 1 pixel wide by default
local BOUNDING_BOX_WIDTH = 3

local HANDLE_NOTSET = Direction.NOT_SET
local HANDLE_NW = FFlagStudioUIEditorV2Alpha and Direction.NW or 1
local HANDLE_N  = FFlagStudioUIEditorV2Alpha and Direction.N  or 2
local HANDLE_NE = FFlagStudioUIEditorV2Alpha and Direction.NE or 3
local HANDLE_W  = FFlagStudioUIEditorV2Alpha and Direction.W  or 4
local HANDLE_E  = FFlagStudioUIEditorV2Alpha and Direction.E  or 5
local HANDLE_SW = FFlagStudioUIEditorV2Alpha and Direction.SW or 6
local HANDLE_S  = FFlagStudioUIEditorV2Alpha and Direction.S  or 7
local HANDLE_SE = FFlagStudioUIEditorV2Alpha and Direction.SE or 8

local DATA_INSTANCE = 1
local DATA_ABSPOSITION = 2
local DATA_POSITION = 3
local DATA_ABSSIZE = 4
local DATA_SIZE = 5

-- Variables
local m_actionMediator = nil

local m_debugMode = false -- Shows m_handleParent so you can check its transformation
local m_selectionManagerEvent = nil

local m_screenGui = nil

local m_draggingHandle = nil

local m_handleParent = nil
local m_handles = {}
local m_boundingBox = {}

local m_filteredSelection = {}

local m_originalAspectRatio = nil

local m_originalMousePosition = nil
local m_originalExtents = nil
local m_originalSelectionData = {}

local m_currentlyDragging = false

local m_isHidden = FFlagStudioUIEditorV2Alpha and true or false

local m_mouseOverHandle = HANDLE_NOTSET

-- Functions

-- Callback for when the mouse enters a resize handle. 
--
-- void onHandleMouseEnter(Direction handleDirection)
local function onHandleMouseEnter(handleDirection)
	m_mouseOverHandle = handleDirection
end

-- Callback for when the mouse leaves a resize handle.
--
-- void onHandleMouseLeave(Direction handleDirection)
local function onHandleMouseLeave(handleDirection)
	--[[
		Check if left handle is the same as entered handle. Avoids the issue:
		enter Handle A, enter Handle B, leave Handle A -> m_mouseOverHandle = HANDLE_NOTSET
	--]]
	if handleDirection == m_mouseOverHandle then  
		m_mouseOverHandle = HANDLE_NOTSET
	end
end

-- Creates the m_handleParent. It is an invisible frame that is transformed like the
-- selected object. The resize handles and the the bounding box frames are parented
-- to it and are transformed with it. That way there is no need for manually transforming
-- the resize handle and bounding box frame.
--
-- void createHandleParent()
local function createHandleParent()
	m_handleParent = Instance.new("Frame")
	m_handleParent.Name = "UIEditorResizeHandleParent"
	
	-- Handle parent should only show in debug mode
	m_handleParent.AnchorPoint = Vector2.new(0, 0)
	m_handleParent.BackgroundTransparency = m_debugMode and 0.5 or 1	
	m_handleParent.BackgroundColor3 = Color3.new(0, 0, 255)
	m_handleParent.BorderSizePixel = 0
end

-- void createResizeHandles()
local function createResizeHandles()	
	--[[
		Then handles should appear at the corners and the middle of the sides. Using
		the anchors points simplifies this, as we can just use those positions directly. 
	--]]
	local anchorPoints = {
		[Direction.E]  = Vector2.new(0, 0.5),
		[Direction.SE] = Vector2.new(0, 0),
		[Direction.S]  = Vector2.new(0.5, 0),
		[Direction.SW] = Vector2.new(1, 0),
		[Direction.W]  = Vector2.new(1, 0.5),
		[Direction.NW] = Vector2.new(1, 1),
		[Direction.N]  = Vector2.new(0.5, 1),
		[Direction.NE] = Vector2.new(0, 1)
	}
	
	--[[
		The handles are positioned using Scale relative to the m_handleParent. That way
		their position will be updated automatically as the parent is resized.
	--]]
	local offset = 2
	local positions = {
		[Direction.E]  = UDim2.new(1, -offset, 0.5, 0),
		[Direction.SE] = UDim2.new(1, -offset, 1, -offset),
		[Direction.S]  = UDim2.new(0.5, 0, 1, -offset),
		[Direction.SW] = UDim2.new(0, offset, 1, -offset),
		[Direction.W]  = UDim2.new(0, offset, 0.5, 0),
		[Direction.NW] = UDim2.new(0, offset, 0, offset),
		[Direction.N]  = UDim2.new(0.5, 0, 0, offset),
		[Direction.NE] = UDim2.new(1, -offset, 0, offset)
	}
	
	-- Create each resize handle
	for i = Direction.FIRST, Direction.LAST do
		local handle = Instance.new("Frame")
		handle.Name = "ResizeHandle_" .. Direction:toShortName(i)
		handle.AnchorPoint = anchorPoints[i]
		handle.Size = UDim2.new(0, HANDLE_SIZE, 0, HANDLE_SIZE)
		handle.Position = positions[i]
		handle.BackgroundColor3 = BASE_COLOR
		handle.BorderColor3 = HANDLE_BORDER_COLOR
		handle.ZIndex = 3
		
		-- Create drop shadow
		local dropShadow = Instance.new("ImageLabel")
		dropShadow.Image = "rbxasset://textures/StudioUIEditor/resizeHandleDropShadow.png"
		dropShadow.Name = "ResizeHandleDropShadow_" .. Direction:toShortName(i)
		-- We want to show four pixels of drop shadow on each side of the resize handle, 
		-- which is why we add 8 to the size.
		dropShadow.Size = UDim2.new(0, HANDLE_SIZE + 8, 0, HANDLE_SIZE + 8)
		-- The image's first four pixels is the blured edge, so move it over by 4 pixels. We want
		-- more to show at the bottom than top, so move it by a little less in y.  
		dropShadow.Position = UDim2.new(0, -4, 0, -3)
		dropShadow.BackgroundTransparency = 1
		dropShadow.BorderSizePixel = 0
		dropShadow.ImageColor3 = Color3.fromRGB(0, 0, 0)
		dropShadow.ImageTransparency = 0.6
		dropShadow.ScaleType = Enum.ScaleType.Slice
		-- The image was created so four pixels around the border is the blurred edge. We
		-- want those edges and corners to not be stretched in the 9-patch.
		dropShadow.SliceCenter = Rect.new(4, 4, 12, 12)
		dropShadow.ZIndex = 2
		dropShadow.Parent = handle
		
		-- Callbacks for when the handle is hovered		
		handle.MouseEnter:connect(function(x, y)
			onHandleMouseEnter(i)
		end)
		handle.MouseLeave:connect(function(x, y)
			onHandleMouseLeave(i)
		end)
		
		-- Add resize handle
		handle.Parent = m_handleParent
		m_handles[i] = handle
	end
end

-- void createBoundingBox()
local function createBoundingBox()
	-- The winding order is East and clockwise.
	local anchors = {
		Vector2.new(0, 0.5),
		Vector2.new(0.5, 0),
		Vector2.new(1, 0.5),
		Vector2.new(0.5, 1)
	}	
	
	local positions = {
		UDim2.new(1, BORDER_SIZE, 0.5, 0),
		UDim2.new(0.5, 0, 1, BORDER_SIZE),
		UDim2.new(0, -BORDER_SIZE, 0.5, 0),
		UDim2.new(0.5, 0, 0, -BORDER_SIZE)
	}	
	
	
	--[[		
		The frames in the bounding box needs to larger than the selected
		objects because they're displayed on the outside. We need to add
		the bounding box width at both ends, hence the multiplication by
		two. We finally need to add 2 because there's at least a one
		pixel border on each side from the object itself.
	--]]
	local extraBoundingBoxSize = 2*BOUNDING_BOX_WIDTH + 2*BORDER_SIZE
	local sizes = {
		UDim2.new(0, BOUNDING_BOX_WIDTH, 1, extraBoundingBoxSize),
		UDim2.new(1, extraBoundingBoxSize, 0, BOUNDING_BOX_WIDTH), 		
		UDim2.new(0, BOUNDING_BOX_WIDTH, 1, extraBoundingBoxSize),				
		UDim2.new(1, extraBoundingBoxSize, 0, BOUNDING_BOX_WIDTH)	
	}	
	
	for i = 1, 4 do
		local frame = Instance.new("Frame")
		frame.AnchorPoint = anchors[i]
		frame.BackgroundColor3 = BOUNDING_BOX_COLOR
		frame.BorderSizePixel = 0
		frame.Position = positions[i]
		frame.Size = sizes[i]
		
		-- Add bounding box frame
		m_boundingBox[i] = frame
		m_boundingBox[i].Parent = m_handleParent
	end
end

-- TODO: Remove when removing FFlagStudioUIEditorV2Alpha
local function createResizeHandle()
	assert(not FFlagStudioUIEditorV2Alpha)
	local handle = Instance.new("Frame")
	handle.Size = UDim2.new(0, HANDLE_SIZE, 0, HANDLE_SIZE)
	handle.AnchorPoint = Vector2.new(0.5, 0.5)
	handle.BackgroundColor3 = BASE_COLOR
	handle.ZIndex = 2
	return handle
end

-- TODO: Remove when removing FFlagStudioUIEditorV2Alpha
local function createBoundingFrame()
	assert(not FFlagStudioUIEditorV2Alpha)
	local frame = Instance.new("Frame")
	frame.AnchorPoint = Vector2.new(0.5, 0.5)
	frame.BackgroundColor3 = BOUNDING_BOX_COLOR
	frame.BorderSizePixel = 0
	return frame
end

-- bool handleExist()
local function handlesExist()
	return #m_handles > 0
end

--Vector2 getPositionFromHandle(table(mt Extents2D), num handle)
local function getPositionFromHandle(extents, handle)
	if (handle == HANDLE_NW) then
		return extents.TopLeft
	elseif (handle == HANDLE_N) then
		return Vector2.new(extents.Center.X, extents.Top)
	elseif (handle == HANDLE_NE) then
		return extents.TopRight
	elseif (handle == HANDLE_W) then
		return Vector2.new(extents.Left, extents.Center.Y)
	elseif (handle == HANDLE_E) then
		return Vector2.new(extents.Right, extents.Center.Y)
	elseif (handle == HANDLE_SW) then
		return extents.BottomLeft
	elseif (handle == HANDLE_S) then
		return Vector2.new(extents.Center.X, extents.Bottom)
	elseif (handle == HANDLE_SE) then
		return extents.BottomRight
	end
	return extents.Center
end

-- num getSnappingTypeFromHandle(num handle)
local function getSnappingTypeFromHandle(handle)
	
	if (handle == HANDLE_NW) then
		return SnappingType.ResizeXnYn
	elseif (handle == HANDLE_N) then
		return SnappingType.ResizeYn
	elseif (handle == HANDLE_NE) then
		return SnappingType.ResizeXpYn
	elseif (handle == HANDLE_W) then
		return SnappingType.ResizeXn
	elseif (handle == HANDLE_E) then
		return SnappingType.ResizeXp
	elseif (handle == HANDLE_SW) then
		return SnappingType.ResizeXnYp
	elseif (handle == HANDLE_S) then
		return SnappingType.ResizeYp
	elseif (handle == HANDLE_SE) then
		return SnappingType.ResizeXpYp
	end
	
	--assert
	return nil
end

-- void updateHandlePositionFromExtents(table(mt Extents2D) extents)
local function updateHandlePositionFromExtents(extents)
	if FFlagStudioUIEditorV2Alpha then
		local size = extents.Size
		local position = extents.TopLeft

		--[[
			Update the m_handleParent so the resize handles and bounding box
			frames are transformed.
		--]] 
		m_handleParent.Position = UDim2.new(0, position.X, 0, position.Y)
		m_handleParent.Size = UDim2.new(0, size.X, 0, size.Y)
		if (#m_filteredSelection == 1) then
			-- Only one object is selected so we can rotate the bounding box and resize handles
			m_handleParent.Rotation = m_filteredSelection[1].AbsoluteRotation	
		else
			m_handleParent.Rotation = 0
		end
	else		
		local widenedExtents = Utility:cloneTable(extents)

		widenedExtents:translate(-Vector2.new(HANDLE_POSITION_OFFSET, HANDLE_POSITION_OFFSET))
		widenedExtents:resize((widenedExtents.Size + Vector2.new(HANDLE_POSITION_OFFSET, HANDLE_POSITION_OFFSET) * 2) - HANDLE_OFFSET)
	
		local size = widenedExtents.Size
		local center = widenedExtents.Center
		
		for i = 1, 8 do
			m_handles[i].Position = Utility:vector2ToUDim2Offset(getPositionFromHandle(widenedExtents, i))
		end
		 
		m_boundingBox[1].Position = UDim2.new(0, center.X, 0, widenedExtents.Top)
		m_boundingBox[1].Size = UDim2.new(0, size.X, 0, BOUNDING_BOX_WIDTH)
	
		m_boundingBox[2].Position = UDim2.new(0, center.X, 0, widenedExtents.Bottom)
		m_boundingBox[2].Size = UDim2.new(0, size.X, 0, BOUNDING_BOX_WIDTH)
	
		m_boundingBox[3].Position = UDim2.new(0, widenedExtents.Left, 0, center.Y)
		m_boundingBox[3].Size = UDim2.new(0, BOUNDING_BOX_WIDTH, 0, size.Y)
	
		m_boundingBox[4].Position = UDim2.new(0, widenedExtents.Right, 0, center.Y)
		m_boundingBox[4].Size = UDim2.new(0, BOUNDING_BOX_WIDTH, 0, size.Y)
	end
end

local function createResizeAdorns()
	if (handlesExist()) then return end
	
	local container = CoreGuiManager:findOrCreateFolder("m_handles")
	
	if not m_screenGui then
		m_screenGui = Instance.new("ScreenGui", container)
		if FFlagStudioUIEditorV2Alpha then
			-- I had forgotten to fast flag this in CLISTUDIO-14547
			m_screenGui.Enabled = false
		end
	end
	
	if FFlagStudioUIEditorV2Alpha then
		createHandleParent()
		m_handleParent.Parent = m_screenGui
		createResizeHandles()
		createBoundingBox()
	else
		for i = 1, 8 do
			table.insert(m_handles, createResizeHandle())
			m_handles[i].Parent = m_screenGui
		end
		
		for i = 1, 4 do
			table.insert(m_boundingBox, createBoundingFrame())
			m_boundingBox[i].Parent = m_screenGui
		end
	end	
end

local function deleteResizeAdorns()
	for i = 1, #m_handles do
		m_handles[i]:Destroy()
	end
	
	for i = 1, #m_boundingBox do
		m_boundingBox[i]:Destroy()
	end

	m_handles = {}
	m_boundingBox = {}
	
	if FFlagStudioUIEditorV2Alpha then
		m_mouseOverHandle = HANDLE_NOTSET
		
		if m_handleParent then
			m_handleParent:Destroy()
			m_handleParent = nil
		end
	
		if m_screenGui then
			m_screenGui:Destroy()
			m_screenGui = nil
		end		
	end
end

-- TODO: Remove when removing FFlagStudioUIEditorV2Alpha
local function DEPRECATED_isPointInBox(location, upperLeft, size)
	assert(not FFlagStudioUIEditorV2Alpha)
	return location.x >= upperLeft.x and
			location.y >= upperLeft.y and
			location.x <= upperLeft.x + size.x and
			location.y <= upperLeft.y + size.y
end

-- TODO: Remove when removing FFlagStudioUIEditorV2Alpha
local function DEPRECATED_getHandleOver(location)
	assert(not FFlagStudioUIEditorV2Alpha)
	for i = 1, #m_handles do
		if (DEPRECATED_isPointInBox(location, m_handles[i].AbsolutePosition, m_handles[i].AbsoluteSize)) then
			return m_handles[i]
		end
	end
	return nil
end

-- Returns true if one or more instances of the type GuiObject is selected.
--
-- bool hasSelection()
function hasSelection()
	return #m_filteredSelection > 0
end

-- Encapsulation
local Resize = {}

function Resize:onSelectionChanged()
	if FFlagStudioUIEditorV2Alpha then
		m_filteredSelection = SelectionManager:getFilteredSelection()
		if (not SelectionManager:hasFilteredSelection()) then
			Resize:hide()
		else
			Resize:updatePosition()
			Resize:show()
		end
	else
		if (not SelectionManager:hasSelection()) then
			deleteResizeAdorns()
		else
			createResizeAdorns()
			Resize:updatePosition()
		end
	end
end

-- TODO: Remove when removing FFlagStudioUIEditorV2Alpha
function Resize:DEPRECATED_clearAdornments()
	assert(not FFlagStudioUIEditorV2Alpha)
	deleteResizeAdorns()
end

-- TODO: Remove when removing FFlagStudioUIEditorV2Alpha
function Resize:DEPRECATED_showResizeAdorns()
	assert(not FFlagStudioUIEditorV2Alpha)
	if (SelectionManager:hasFilteredSelection()) then
		createResizeAdorns()
		Resize:updatePosition()
	end
end

-- void Resize:updatePosition()
function Resize:updatePosition()
	if FFlagStudioUIEditorV2Alpha then
		if #m_filteredSelection == 0 then
			return
		end
		
		updateHandlePositionFromExtents(Extents2D:getExtentsFromGuis(m_filteredSelection))
	else
		if (not handlesExist() or m_isHidden) then return end
		
		local selection = SelectionManager:getFilteredSelection()
		
		if (#selection == 0) then
			Resize:hide()
			return
		end
		
		updateHandlePositionFromExtents(Extents2D:getExtentsFromGuis(selection))
	end
end

-- Returns true if the mouse is currently over one of the resize handles.
--
-- bool Resize:isOverAHandle()
function Resize:isOverAHandle()
	if not hasSelection() then
		return false
	end

	return m_mouseOverHandle ~= HANDLE_NOTSET 
end

-- TODO: Remove when removing FFlagStudioUIEditorV2Alpha
function Resize:DEPRECATED_isOverHandle(location)
	assert(not FFlagStudioUIEditorV2Alpha)
	return DEPRECATED_getHandleOver(location) ~= nil
end

-- Updates the handle highlight. The previously hovered handles highlight will be
-- cleared.  If a handle is hovered, then it will be highlighted. The hovered
-- handle will not be highlighted if noHighlight is true. That's used when the 
-- mouse is over the handle, but it should not be highlighted, e.g when rotating.
--
-- Resize:updateHandleHighlight(bool noHighlight)
function Resize:updateHandleHighlight(noHighlight)
	if not hasSelection() then
		return
	end
	
	for i = Direction.FIRST, Direction.LAST do
		if not noHighlight and m_mouseOverHandle == i then
			m_handles[i].BackgroundColor3 = HOVER_COLOR		
		else
			m_handles[i].BackgroundColor3 = BASE_COLOR
		end
	end	
end

-- TODO: Remove when removing FFlagStudioUIEditorV2Alpha
function Resize:DEPRECATED_highlightHandles(location)
	assert(not FFlagStudioUIEditorV2Alpha)
	for i = 1, #m_handles do
		if (DEPRECATED_isPointInBox(location, m_handles[i].AbsolutePosition, m_handles[i].AbsoluteSize)) then
			m_handles[i].BackgroundColor3 = HOVER_COLOR
		else
			m_handles[i].BackgroundColor3 = BASE_COLOR
		end
	end
end

function Resize:isDragInProgress()
	return m_currentlyDragging
end

-- Updates the resize mouse icon.
--
-- void Resize:updateMouseIcon()
function Resize:updateMouseIcon()
	if m_mouseOverHandle ~= Direction.NOT_SET then
		if #m_filteredSelection == 1 then
			local absoluteRotation = m_filteredSelection[1].AbsoluteRotation
			local mouseIconDirection = MouseIconManager:calcMouseIconDirection(m_mouseOverHandle, absoluteRotation)
			MouseIconManager:setToResizeIcon(mouseIconDirection)
		else				
			-- If there's more than one object selected, then the bounding box is axis aligned
			MouseIconManager:setToResizeIcon(m_mouseOverHandle)
		end
	end
end

-- Hides all handles except for one, which is set to visible.
--
-- void onlyShowHandle(Direction handleToShow)
function onlyShowHandle(handleToShow)
	for i = 1, #m_handles do
		if i == handleToShow then
			m_handles[i].Visible = true
		else
			m_handles[i].Visible = false
		end
	end
end

function Resize:startDrag(location)
	if FFlagStudioUIEditorV2Alpha then
		if not hasSelection() then
			return
		end
	end	
	
	if m_currentlyDragging then return end
	
	m_currentlyDragging = true
			
	if FFlagStudioUIEditorV2Alpha then
		m_draggingHandle = m_mouseOverHandle
		onlyShowHandle(m_draggingHandle)
				
		for i = 1, #m_filteredSelection do
			table.insert(m_originalSelectionData,
						{
							m_filteredSelection[i], 
							m_filteredSelection[i].AbsolutePosition,
							m_filteredSelection[i].Position,
							m_filteredSelection[i].AbsoluteSize,
							m_filteredSelection[i].Size
						})
		end
	
		m_originalExtents = Extents2D:getExtentsFromGuis(m_filteredSelection)
		m_originalAspectRatio = m_originalExtents.Width / m_originalExtents.Height
	else
		--hide handles
		for i = 1, #m_handles do
			if (DEPRECATED_isPointInBox(location, m_handles[i].AbsolutePosition, m_handles[i].AbsoluteSize)) then
				m_draggingHandle = i
				m_handles[i].Visible = true
			else
				m_handles[i].Visible = false
			end
		end
		
		local selection = SelectionManager:getFilteredSelection()
	
		for i = 1, #selection do
			table.insert(m_originalSelectionData,
						{
							selection[i], 
							selection[i].AbsolutePosition,
							selection[i].Position,
							selection[i].AbsoluteSize,
							selection[i].Size
						})
		end
	
		m_originalExtents = Extents2D:getExtentsFromGuis(SelectionManager:getFilteredSelection())
		m_originalAspectRatio = m_originalExtents.Width / m_originalExtents.Height
	end	
	
	m_originalMousePosition = location
	
	if FFlagStudioUIEditorV2Alpha then
		m_actionMediator:onResizeBegan(location)
	end
end

--void retainAspectRatio(table(mt Extents2D)& extents, Vector2 mouseLocation, bool hasSnappedX, bool hasSnappedY)
local function retainAspectRatio(extents, mouseLocation, hasSnappedX, hasSnappedY)
		
	local snapXOnly = hasSnappedX and not hasSnappedY
	local snapYOnly = hasSnappedY and not hasSnappedX
			
	if (m_draggingHandle == HANDLE_E or
		m_draggingHandle == HANDLE_W) then
		
		local height = extents.Width / m_originalAspectRatio
		extents:expandFromCenter(Vector2.new(0, height - extents.Height))
		
	elseif (m_draggingHandle == HANDLE_N or
			m_draggingHandle == HANDLE_S) then
		
		local width = m_originalAspectRatio * extents.Height
		extents:expandFromCenter(Vector2.new(width - extents.Width, 0))
		
	elseif (m_draggingHandle == HANDLE_SE) then
		
		local mouseDelta = mouseLocation - m_originalExtents.TopLeft
		local mouseAspectRatio = mouseDelta.X / mouseDelta.Y
		local isCloserX = mouseDelta.Y <= 0 or mouseAspectRatio > m_originalAspectRatio
				
		if ((isCloserX or snapXOnly) and (not snapYOnly)) then
			extents.BottomRight = extents.TopLeft + Vector2.new(extents.Width, extents.Width / m_originalAspectRatio)
		else
			extents.BottomRight = extents.TopLeft + Vector2.new(m_originalAspectRatio * extents.Height, extents.Height)
		end
		
	elseif (m_draggingHandle == HANDLE_NE) then
	
		local multiplier = Vector2.new(1, -1)	
		
		local mouseDelta = (mouseLocation - m_originalExtents.BottomLeft) * multiplier
		local mouseAspectRatio = mouseDelta.X / mouseDelta.Y
		local isCloserX = mouseDelta.y <= 0 or mouseAspectRatio > m_originalAspectRatio
		
		if (isCloserX) then
			extents.TopRight = extents.BottomLeft + (Vector2.new(extents.Width, extents.Width / m_originalAspectRatio) * multiplier)
		else
			extents.TopRight = extents.BottomLeft + (Vector2.new(m_originalAspectRatio * extents.Height, extents.Height) * multiplier)
		end
	elseif (m_draggingHandle == HANDLE_SW) then
		local multiplier = Vector2.new(-1, 1)	
		
		local mouseDelta = (mouseLocation - m_originalExtents.TopRight) * multiplier
		local mouseAspectRatio = mouseDelta.X / mouseDelta.Y
		local isCloserX = mouseDelta.y <= 0 or mouseAspectRatio > m_originalAspectRatio
		
		if (isCloserX) then
			extents.BottomLeft = extents.TopRight + (Vector2.new(extents.Width, extents.Width / m_originalAspectRatio) * multiplier)
		else
			extents.BottomLeft = extents.TopRight + (Vector2.new(m_originalAspectRatio * extents.Height, extents.Height) * multiplier)
		end
	elseif (m_draggingHandle == HANDLE_NW) then
		
		local multiplier = Vector2.new(-1, -1)
		
		local mouseDelta = (mouseLocation - m_originalExtents.BottomRight) * multiplier
		local mouseAspectRatio = mouseDelta.X / mouseDelta.Y
		local isCloserX = mouseDelta.y <= 0 or mouseAspectRatio > m_originalAspectRatio
		
		if ((isCloserX or snapXOnly) and (not snapYOnly)) then
			extents.TopLeft = extents.BottomRight + (Vector2.new(extents.Width, extents.Width / m_originalAspectRatio) * multiplier)
		else
			extents.TopLeft = extents.BottomRight + (Vector2.new(m_originalAspectRatio * extents.Height, extents.Height) * multiplier)
		end		
	end
	
end

-- void Resize:updateDrag(Vector2 location)
function Resize:updateDrag(location)

	if not m_currentlyDragging then return end
		
	local selection = SelectionManager:getFilteredSelection()
	local newExtents = Utility:cloneTable(m_originalExtents)
	
	AdornmentModule:hideSnappingLines()
	
	-----------------------
	--Contextual Snapping--
	-----------------------
	
	local delta = location - m_originalMousePosition
		
	if (m_draggingHandle == HANDLE_NW or
		m_draggingHandle == HANDLE_W or
		m_draggingHandle == HANDLE_SW) then
	
		newExtents:translate(Vector2.new(delta.X, 0))
		newExtents:resize(newExtents.Size - Vector2.new(delta.X, 0))
				
	elseif (m_draggingHandle == HANDLE_NE or
			m_draggingHandle == HANDLE_E or
			m_draggingHandle == HANDLE_SE) then
	
		newExtents:resize(newExtents.Size + Vector2.new(delta.X, 0))
	end
	
	if (m_draggingHandle == HANDLE_NW or
		m_draggingHandle == HANDLE_N or
		m_draggingHandle == HANDLE_NE) then
	
		newExtents:translate(Vector2.new(0, delta.Y))
		newExtents:resize(newExtents.Size - Vector2.new(0, delta.Y))

	elseif (m_draggingHandle == HANDLE_SW or
			m_draggingHandle == HANDLE_S or
			m_draggingHandle == HANDLE_SE) then
	
		newExtents:resize(newExtents.Size + Vector2.new(0, delta.Y))
	end
	
	if (UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift)) then
		retainAspectRatio(newExtents, location, false, false)
	end
	
	local snappingLines, hasSnappedX, hasSnappedY
	newExtents, snappingLines, hasSnappedX, hasSnappedY = SnappingPointManager:snapExtents(newExtents, getSnappingTypeFromHandle(m_draggingHandle))
			
	for i = 1, #snappingLines do
		AdornmentModule:showSnappingLine(snappingLines[i])
	end
	
	if (UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift)) then
		retainAspectRatio(newExtents, location, hasSnappedX, hasSnappedY)
	end
	
	local intendedPosition = {}
	local intendedSize = {}	
	
	--calculate intended position and size
	
	for i = 1, #m_originalSelectionData do
		
		local data = m_originalSelectionData[i]
		local guiObject = data[DATA_INSTANCE]
			
		local percentPosition = (data[DATA_ABSPOSITION] - m_originalExtents.TopLeft) / m_originalExtents.Size
		local newAbsolutePosition = (percentPosition * newExtents.Size) + newExtents.TopLeft
		
		local newAbsoluteSize = (data[DATA_ABSSIZE] / m_originalExtents.Size) * newExtents.Size
		
		--adjust for anchor point
		newAbsolutePosition = newAbsolutePosition + (newAbsoluteSize * guiObject.AnchorPoint)
		
		if (newAbsoluteSize.X <= 0 or newAbsoluteSize.Y <= 0) then return end

		local shouldUseScalePosition = Utility:isOnlyScaleUDim2(data[DATA_POSITION]) or 
									(not Utility:isOnlyOffsetUDim2(data[DATA_POSITION]) and
									GlobalValues:isScale())
									
		local shouldUseScaleSize = Utility:isOnlyScaleUDim2(data[DATA_SIZE]) or 
									(not Utility:isOnlyOffsetUDim2(data[DATA_SIZE]) and
									GlobalValues:isScale())

		intendedPosition[guiObject], intendedSize[guiObject] = Convert:convertAbsoluteToScaleOrOffset(
											shouldUseScalePosition, shouldUseScaleSize,
											newAbsolutePosition, newAbsoluteSize, 
											data[DATA_POSITION], data[DATA_SIZE],
											guiObject.Parent)
	end
	
	
	for i = 1, #m_originalSelectionData do
		local guiObject = m_originalSelectionData[i][DATA_INSTANCE]
		
		guiObject.Position = intendedPosition[guiObject]
		guiObject.Size = intendedSize[guiObject]
		
		
	end
	
	updateHandlePositionFromExtents(newExtents)

	if FFlagStudioUIEditorV2Alpha then
		m_actionMediator:onResizeChanged(location)
	end
end

--void Resize:finishDrag(Vector2 location)
function Resize:finishDrag(location)
	if not m_currentlyDragging then return end
	
	AdornmentModule:hideSnappingLines()
	
	if m_originalMousePosition ~= location then
		Analytics:reportEvent("Resize")
		ChangeHistoryService:SetWaypoint("Resize")
	end
	
	m_currentlyDragging = false
	
	AdornmentModule:hideXSnappingLine()
	AdornmentModule:hideYSnappingLine()
	
	m_originalSelectionData = {}
	m_originalMousePosition = nil
	m_originalExtents = nil
	m_draggingHandle = nil
	for i = 1, #m_handles do
		m_handles[i].Visible = true
	end
	
	if FFlagStudioUIEditorV2Alpha then
		m_actionMediator:onResizeEnded(location)
	end
end

-- void Resize:hide()
function Resize:hide()
	if m_isHidden then return end
	m_isHidden = true
	if m_screenGui then
		m_screenGui.Enabled = false
	end
end

-- void Resize:show()
function Resize:show()
	if FFlagStudioUIEditorV2Alpha then
		if not m_isHidden or #m_filteredSelection == 0 then
			return
		end
	else
		if not m_isHidden then return end
	end
	m_isHidden = false
	if m_screenGui then
		m_screenGui.Enabled = true
	end
end

function Resize:setActionMediator(actionMediator)
	m_actionMediator = actionMediator
end

-- Turns the Resize on and performs initialization. Called when the plugin is turned on.
function Resize:On()
	createResizeAdorns()
end

-- Turns the Resize off and performs de-initialization. Called when the plugin is turned off.
function Resize:Off()
	deleteResizeAdorns()
end

return Resize
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBXA0D1333C62F04C9DAC77F51069431AF4">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">Error</string>
				<string name="ScriptGuid">{171BD556-A514-41FD-BF0A-2E58CDFAD4A0}</string>
				<ProtectedString name="Source"><![CDATA[local e = nil

function Error(str)
	print("ERROR:", str)
	e:throw()
end

return Error
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX7D2512DE58BD4667A0F94AE73A046821">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">AdornmentModule</string>
				<string name="ScriptGuid">{902789FF-89A7-4491-AA7B-170A05D1A24A}</string>
				<ProtectedString name="Source"><![CDATA[

local CoreGuiManager = require(script.Parent.CoreGuiManager)

local Utility		= require(script.Parent.Utility)

local m_reparentInstance = nil
local m_reparentOverlay = nil

local m_xSnappingLine = nil
local m_ySnappingLine = nil

-- ImageLabel createSnappingLine()
local function createSnappingLine()
	local line = Instance.new("ImageLabel")
	line.BorderSizePixel = 0
	line.BackgroundTransparency = 1
	line.Image = "rbxasset://textures/blockUpperLeft.png"
	line.ScaleType = Enum.ScaleType.Tile
	line.TileSize = UDim2.new(0, 16, 0, 16)
	line.AnchorPoint = Vector2.new(0.5, 0.5)
	line.ImageColor3 = Color3.new(0.8, 0.8, 0.8)
	line.Parent = CoreGuiManager:findOrCreateScreenGui("Adornments")
	return line
end

local function createFrame()
	local frame = Instance.new("Frame")
	frame.BorderSizePixel = 0
	frame.BackgroundColor3 = Color3.new(0, 0, 0)
	frame.AnchorPoint = Vector2.new(0.5, 0.5)
	frame.Parent = CoreGuiManager:findOrCreateScreenGui("Adornments")
	return frame
end


local AdornmentModule = {}

local snappingLines = {}

-- void AdornmentModule:showSnappingLine(table line)
function AdornmentModule:showSnappingLine(line)
	local sl = createSnappingLine()
	sl.AnchorPoint = Vector2.new(0,0)
	sl.Position = UDim2.new(0, line[1].X, 0, line[1].Y)
	sl.Size = UDim2.new(0, math.max(1, Utility:distance(line[1].X, line[2].X)), 0, math.max(1, Utility:distance(line[1].Y, line[2].Y)))
	sl.ImageColor3 = line[3]
	table.insert(snappingLines, sl)
end

-- void AdornmentModule:hideSnappingLines()
function AdornmentModule:hideSnappingLines()
	for i = 1, #snappingLines do
		snappingLines[i]:Destroy()
	end
	
	snappingLines = {}
end

function AdornmentModule:showXSnappingLine(point, size)
	if (not m_xSnappingLine) then
		m_xSnappingLine = createFrame()
	end
	
	m_xSnappingLine.Visible = true
	
	m_xSnappingLine.Size = UDim2.new(0, 1, 0, size)
	m_xSnappingLine.Position = UDim2.new(0, point.X, 0, point.Y)
end

function AdornmentModule:showYSnappingLine(point, size)
	if (not m_ySnappingLine) then
		m_ySnappingLine = createFrame()
	end
	
	m_ySnappingLine.Visible = true
	
	m_ySnappingLine.Size = UDim2.new(0, size, 0, 1)
	m_ySnappingLine.Position = UDim2.new(0, point.X, 0, point.Y)
end

function AdornmentModule:hideXSnappingLine()
	if (m_xSnappingLine) then
		m_xSnappingLine.Visible = false
	end
end

function AdornmentModule:hideYSnappingLine()
	if (m_ySnappingLine) then
		m_ySnappingLine.Visible = false
	end
end

function AdornmentModule:showOfferReparentAdornments(instance,offeredParent)
	if (not m_reparentInstance) then
		m_reparentInstance = instance:Clone()
		m_reparentInstance.AnchorPoint = Vector2.new(0,0)
		m_reparentInstance.ZIndex = 3
		m_reparentOverlay = createFrame()
		
		m_reparentOverlay.BackgroundColor3 = Color3.new(0,0,0)
		m_reparentOverlay.BackgroundTransparency = 0.8
		m_reparentOverlay.AnchorPoint = Vector2.new(0,0)
		m_reparentOverlay.ZIndex = 2
	end
	
	m_reparentInstance.Parent = CoreGuiManager:findOrCreateScreenGui("Adornments")
	
	m_reparentInstance.Position = UDim2.new(0, instance.AbsolutePosition.X, 0, instance.AbsolutePosition.Y)
	m_reparentInstance.Size = UDim2.new(0, instance.AbsoluteSize.X, 0, instance.AbsoluteSize.Y)
	
	m_reparentOverlay.Position = UDim2.new(0, offeredParent.AbsolutePosition.X, 0, offeredParent.AbsolutePosition.Y)
	m_reparentOverlay.Size = UDim2.new(0, offeredParent.AbsoluteSize.X, 0, offeredParent.AbsoluteSize.Y)
end

function AdornmentModule:hideOfferReparent()
	if m_reparentInstance then
		m_reparentInstance:Destroy()
		m_reparentOverlay:Destroy()
		
		m_reparentInstance = nil
		m_reparentOverlay = nil
	end
end


return AdornmentModule
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBXB80E9933D1824046B9108A40E1C50291">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">SelectionManager</string>
				<string name="ScriptGuid">{B2A1FB18-0D9B-4C62-9ABE-2322E03FF971}</string>
				<ProtectedString name="Source"><![CDATA[--[[
	The SelectionManager module interfaces with Selection Service. It filters
	the selection down to GUI objects. It is also used for getting updates
	when a selected object's properties changes.
--]]

-- Module scripts
local FFlag = require(script.Parent.FFlag)
local Utility = require(script.Parent.Utility)

-- Services
local SelectionService = game:GetService("Selection")

-- Flags
local FFlagStudioUIEditorV2Alpha = FFlag:isEnabled("StudioUIEditorV2Alpha")

--filtered selection
--when selection changes register to changed event on new items

local m_rawSelection = {}
local m_filteredSelection = {}
local m_filteredSelectionAncestors = {}

local m_changedEvents = {}

local m_changedEventCallbacks = {}
local m_callbackIdentifier = 0


local function onChangedEvent(instance, property)

	for k, v in pairs(m_changedEventCallbacks) do
		v(instance, property)
	end
end


local function disconnectChangedEvents()
	for i = 1, #m_filteredSelection do
		m_changedEvents[m_filteredSelection[i]]:disconnect()
	end
end

local function connectChangedEvents()
	for i = 1, #m_filteredSelection do
		m_changedEvents[m_filteredSelection[i]] = m_filteredSelection[i].Changed:connect(
			function(property) onChangedEvent(m_filteredSelection[i], property) end)
	end
end

local function ancestorExistsInList(instance, list)
	if (not instance or
		not instance:IsA("GuiBase2d")) then
		return false
	end
	if (Utility:findItemInTable(instance, list) ~= 0) then
		return true
	end
	return ancestorExistsInList(instance.Parent, list)
end

local SelectionManager = {}

function SelectionManager:connectSelectionInstancesChanged(func)
	m_callbackIdentifier = m_callbackIdentifier + 1
	m_changedEventCallbacks[m_callbackIdentifier] = func
	
	return m_callbackIdentifier
end

function SelectionManager:disconnectSelectionInstancesChanged(identifier)
	if not identifier then return nil end
		
	m_changedEventCallbacks[identifier] = nil
	return nil
end

function SelectionManager:onSelectionChanged()
	disconnectChangedEvents()
	
	local selection = SelectionService:Get()
	
	m_rawSelection = selection
	m_filteredSelection = {}
	m_filteredSelectionAncestors = {}
	for i = 1, #m_rawSelection do
		if FFlagStudioUIEditorV2Alpha then
			--[[
				Checking for GuiObject instead of GuiBase2d because GuiBase2d does
				not have a Position property.
			--]]
			if m_rawSelection[i]:IsA("GuiObject") then
				table.insert(m_filteredSelection, m_rawSelection[i])
			end
		else
			if m_rawSelection[i]:IsA("GuiBase2d") then
				table.insert(m_filteredSelection, m_rawSelection[i])
			end
		end
	end
	
	for i = 1, #m_filteredSelection do
		if (not ancestorExistsInList(selection[i].Parent, selection)) then
			table.insert(m_filteredSelectionAncestors, selection[i])
		end
	end
		
	connectChangedEvents()
end

function SelectionManager:getRawSelection()
	return {unpack(m_rawSelection)}
end

function SelectionManager:getFilteredSelection()
	return {unpack(m_filteredSelection)}
end

function SelectionManager:getFilteredSelectionCommonAncestors()
	return {unpack(m_filteredSelectionAncestors)}
end

function SelectionManager:hasSelection()
	return #m_rawSelection ~= 0
end

function SelectionManager:hasFilteredSelection()
	return #m_filteredSelection ~= 0
end

function SelectionManager:setSelection(selection)
	if (Utility:tablesAreEquivalent(m_rawSelection, selection)) then return false end
	
	SelectionService:Set(selection)
	return true
end



return SelectionManager



]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX863609DAF7274535BDC532672D5100B5">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">Move</string>
				<string name="ScriptGuid">{8DFF8734-9E4B-45E6-9882-933F80386C52}</string>
				<ProtectedString name="Source"><![CDATA[

-----------------------------------
--------------MODULES--------------
-----------------------------------
local AdornmentModule		= require(script.Parent.AdornmentModule)
local Analytics				= require(script.Parent.Analytics)
local Convert				= require(script.Parent.Convert)
local Extents2D				= require(script.Parent.Extents2D)
local FFlag					= require(script.Parent.FFlag)
local GlobalValues			= require(script.Parent.GlobalValues)
local MouseIconManager		= require(script.Parent.MouseIconManager)
local Resize				= require(script.Parent.Resize) -- TODO: Remove when removing FFlagStudioUIEditorV2Alpha
local Select 				= require(script.Parent.Select)
local SelectionManager		= require(script.Parent.SelectionManager)
local SnappingPointManager	= require(script.Parent.SnappingPointManager)
local Utility				= require(script.Parent.Utility)

local SnappingType 			= require(script.Parent.Enum.SnappingType)

-----------------------------------
--------------SERVICES-------------
-----------------------------------
local UserInputService = game:GetService("UserInputService")
local ChangeHistoryService = game:GetService("ChangeHistoryService")


-----------------------------------
-------------VARIABLES-------------
-----------------------------------

local m_actionMediator = nil

local m_originalMousePosition = nil

local m_draggingStarted = false
local m_currentlyDragging = false

local UP = 1
local DOWN = 2
local LEFT = 3
local RIGHT = 4

local DATA_INSTANCE = 1
local DATA_ABSPOSITION = 2
local DATA_POSITION = 3

local MANHATTAN_DRAG_START_DELTA = 3

local m_originalSelectionData = {}

local m_originalExtents = nil

-----------------------------------
-------------FUNCTIONS-------------
-----------------------------------

local function dragElementsBy(vector)
	
	for i = 1, #m_originalSelectionData do
		local element = m_originalSelectionData[i][DATA_INSTANCE]
		
		if (element.Parent and element.Parent:IsA("GuiBase2d")) then
			
			local shouldUseScalePosition = Utility:isOnlyScaleUDim2(m_originalSelectionData[i][DATA_POSITION]) or 
									(not Utility:isOnlyOffsetUDim2(m_originalSelectionData[i][DATA_POSITION]) and
									GlobalValues:isScale())
										
			if (shouldUseScalePosition) then
				local scale = vector / element.Parent.AbsoluteSize
				if FFlag:isEnabled("StudioUIEditorV2Alpha") then
					-- divide by AbsoluteWindowSize to get Frame without scrollbars and further divide
					-- scale by CanvasSize scale since that represents the entire area of ScrollFrame
					-- to get accurate scale for position when dragging
					if (element.Parent:IsA("ScrollingFrame")) then
						scale = vector / element.Parent.AbsoluteWindowSize
						if (element.Parent.CanvasSize.Width.Scale > 1) then
							scale = scale / Vector2.new(element.Parent.CanvasSize.Width.Scale + 1.0, 1)
						end
						if (element.Parent.CanvasSize.Height.Scale > 1) then
							scale = scale / Vector2.new(1, element.Parent.CanvasSize.Height.Scale + 1.0)
						end
					end
				end
				element.Position = m_originalSelectionData[i][DATA_POSITION] + UDim2.new(scale.X, 0, scale.Y, 0)
			else
				element.Position = m_originalSelectionData[i][DATA_POSITION] + UDim2.new(0, vector.X, 0, vector.Y)
			end
		end
		
		
	end
	
end

local function dragElements(location)
	dragElementsBy(location - m_originalMousePosition)
end

local function directionToDirectionVector(direction)
	if (direction == UP) then
		return Vector2.new(0, -1)
	elseif (direction == DOWN) then
		return Vector2.new(0, 1)
	elseif (direction == LEFT) then
		return Vector2.new(-1, 0)
	elseif (direction == RIGHT) then
		return Vector2.new(1, 0)
	end
	
	--assert	
	return Vector2.new(0, -1)
end

local function getFirstAncestorOfType(instance, objectType)
	if not instance or not instance.Parent then
		return nil
	end
	
	if (instance.Parent:IsA(objectType)) then
		return instance.Parent
	end
	
	return getFirstAncestorOfType(instance.Parent, objectType)
end

--[[ Commenting out reparenting functionality until we have better flow
local function offerReparent(instance, offeredParent)
	
	if not instance then
		return
	end
	
	
	if not offeredParent then
		offeredParent = getFirstAncestorOfType(instance, "ScreenGui")

		if not offeredParent then
			AdornmentModule:hideOfferReparent()
			return
		end
	end
	
	if (offeredParent == instance.Parent) then
		AdornmentModule:hideOfferReparent()
	else
		AdornmentModule:showOfferReparentAdornments(instance,offeredParent)
	end
	
end
--]]

local function isDescendantOf(item, potentialAncestor)
	while (item and item.Parent) do
		if (item.Parent == potentialAncestor) then 
			return true
		end
		item = item.Parent
	end
	return false
end

function getHighestZIndexOfSelfAndDescendants(instance, original)
	
	if instance == original then return 0 end
	
	local zIndex = 0
	
	if (instance:IsA("GuiObject")) then
		
		zIndex = instance.ZIndex		
	end
	
	local children = instance:GetChildren()
	
	for i = 1, #children do
		zIndex = math.max(zIndex, getHighestZIndexOfSelfAndDescendants(children[i], original))
	end
	
	return zIndex
end

function incrementZIndexOfSelfAndDescendantsBy(instance, number)

	if (instance:IsA("GuiObject")) then
		instance.ZIndex = instance.zIndex + number	
	end
	
	local children = instance:GetChildren()
	
	for i = 1, #children do
		incrementZIndexOfSelfAndDescendantsBy(children[i], number)
	end
end

local Move = {}

function Move:isDragInProgress()
	return m_draggingStarted
end

--void Move:startDrag(Vector2 location)
function Move:startDrag(location)
	m_originalSelectionData = {}
	local draggableElements = SelectionManager:getFilteredSelectionCommonAncestors()
	
	for i = 1, #draggableElements do
		table.insert(m_originalSelectionData, {draggableElements[i], draggableElements[i].AbsolutePosition, draggableElements[i].Position})
	end
	
	if (#m_originalSelectionData == 0) then return end	
	
	m_originalMousePosition = location
	m_draggingStarted = true
	m_currentlyDragging = false	
	
	m_originalExtents = Extents2D:getExtentsFromGuis(draggableElements)
	if FFlag:isEnabled("StudioUIEditorV2Alpha") then
		MouseIconManager:setToMoveIcon()
		m_actionMediator:onMoveBegan(location)
	end
end

--void Move:finishDrag(Vector2 location)
function Move:finishDrag(location)
	if (m_currentlyDragging) then
		Analytics:reportEvent("Move")
		ChangeHistoryService:SetWaypoint("Translate Objects (better tt needed)")
	end
	
	m_draggingStarted = false
	
	m_originalMousePosition = nil
	
	AdornmentModule:hideSnappingLines()
	
	--[[ Commenting out reparenting functionality until we have better flow
	if (#m_originalSelectionData == 1 and m_currentlyDragging) then
		local guiObject = m_originalSelectionData[1][DATA_INSTANCE]
		local guiObjectsAtPoint = Select:getGuiObjectsAtPoint(location)
		Utility:removeItemFromTable(guiObject, guiObjectsAtPoint)
				
		acceptReparent(guiObject, guiObjectsAtPoint[1])
	end
	--]]
	
	m_currentlyDragging = false
	
	if FFlag:isEnabled("StudioUIEditorV2Alpha") then
		MouseIconManager:setToDefaultIcon()
		m_actionMediator:onMoveEnded(location)
	end
end

-- void Move:updateDrag(Vector2 location)
function Move:updateDrag(location)
	
	if not m_currentlyDragging and Utility:manhattanDistance(location - m_originalMousePosition) <= MANHATTAN_DRAG_START_DELTA then
		return
	end

	m_currentlyDragging = true
	
	AdornmentModule:hideSnappingLines()
	
	local snapType = SnappingType.MoveXY
	
	if (UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift)) then
		local distanceToXAxis = math.abs(location.Y - m_originalMousePosition.Y)
		local distanceToYAxis = math.abs(location.X - m_originalMousePosition.X)
		
		if (distanceToXAxis < distanceToYAxis) then
			location = Vector2.new(location.X, m_originalMousePosition.Y)
		else
			location = Vector2.new(m_originalMousePosition.X, location.Y)
		end
	end
	
	local extents = Extents2D:translate(m_originalExtents, location - m_originalMousePosition)
	local snappingLines
	
	extents, snappingLines = SnappingPointManager:snapExtents(extents, SnappingType.MoveXY)
	
	
	for i = 1, #snappingLines do
		AdornmentModule:showSnappingLine(snappingLines[i])
	end
	
	local positionOffset
	if FFlag:isEnabled("StudioUIEditorV2Alpha") then
		-- The extents centers can be non-integers. Floor them so we always have a consistent
		-- center. We had an issue with frames with an odd size would snap on different sides
		-- of the "middle" of the screen depending on how you moved the mouse. See CLISTUDIO-14120
		positionOffset = Utility:floorVector2(extents.TopLeft - m_originalExtents.TopLeft)
	else
		positionOffset = extents.TopLeft - m_originalExtents.TopLeft
	end
	dragElements(m_originalMousePosition + positionOffset)
	if not FFlag:isEnabled("StudioUIEditorV2Alpha") then
		Resize:hide()
	end
	--[[ Commenting out reparenting functionality until we have better flow
	if (#m_originalSelectionData == 1) then
			
		local guiObject = m_originalSelectionData[1][DATA_INSTANCE]
		local guiObjectsAtPoint = Select:getGuiObjectsAtPoint(location)
		Utility:removeItemFromTable(guiObject, guiObjectsAtPoint)
		
		offerReparent(guiObject, guiObjectsAtPoint[1])			
	end
	--]]
	
	if FFlag:isEnabled("StudioUIEditorV2Alpha") then
		m_actionMediator:onMoveChanged(location)
	end
end

function Move:bump(direction)
	Move:startDrag(Vector2.new(0,0))
	dragElementsBy(directionToDirectionVector(direction))
	Move:finishDrag(direction)
end

function Move:setActionMediator(actionMediator)
	m_actionMediator = actionMediator
end

Move.UP = UP
Move.DOWN = DOWN
Move.LEFT = LEFT
Move.RIGHT = RIGHT

return Move
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX48BB746A2D134BFBAC623AF22012CA06">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">Rotate</string>
				<string name="ScriptGuid">{92882F28-8124-4DC8-9C73-D41393974D28}</string>
				<ProtectedString name="Source"><![CDATA[--[[
	The Rotate module handles rotating a selected object. It changes the mouse cursor
	when you hover outside the corners or the mid-points of the selected object. On
	mouse down it starts the rotation. The rotation is changed as the mouse is
	moved. The rotation stops on mouse up.
--]]

local Rotate = {}

-- Modules
local CoreGuiManager = require(script.Parent.CoreGuiManager)
local Direction = require(script.Parent.Enum.Direction)
local MouseIconManager = require(script.Parent.MouseIconManager)
local SelectionManager = require(script.Parent.SelectionManager)
local Utility = require(script.Parent.Utility)

-- Services
local ChangeHistoryService = game:GetService("ChangeHistoryService")

-- Constants
local ROTATION_HANDLE_SIZE = 20

-- Variables
local m_actionMediator = nil
local m_selectedObject = nil
local m_rotationHandles = {}
local m_isMouseOverHandle = {}
local m_isRotating = false
local m_originalRotation = 0
local m_referenceRotation = 0
local m_accumulatedAngle = 0
local m_debugMode = false -- Show handles in debug mode

local m_center = nil -- The center of the selected object in absolute coordinates
local m_previousMouseVec = nil -- The vector from the center to where the mouse was previously 

local m_originalMousePosition = nil

local m_handleParent = nil -- The rotation handles are positioned relative to the m_handleParent
local m_handles = {}

-- Functions

-- A frame is used as a parent for all the rotation handles. The rotation
-- handles are positioned relative to the handle parent.  The handle parent's
-- position, size and rotation is made to match the selected object. That
-- ensures that the rotation handles show up in the right place. All the
-- frames are transparent so the user can't see them.
--
-- void createHandleParent()
local function createHandleParent()
	m_handleParent = Instance.new("Frame")
	m_handleParent.Name = "UIEditorRotationHandleParent"
	
	-- Handle parent should only show in debug mode
	m_handleParent.BackgroundTransparency = m_debugMode and 0 or 1
	m_handleParent.BackgroundColor3 = Color3.new(0, 0, 255)
	m_handleParent.BorderSizePixel = m_debugMode and 1 or 0
	
	-- Add to core ScreenGui
	m_handleParent.Parent = CoreGuiManager:findOrCreateScreenGui("RotationHandles")
end

-- Destroys the frame that all rotation the handles are parented to. It
-- also automatically destroys all the rotation handles since Destroy
-- will also call Destroy on all the children.
--
-- void destroyHandleParentAndRotationHandles(void)
local function destroyHandleParentAndRotationHandles()
	if m_handleParent then
		m_handleParent:Destroy()
	end
end

local function onHandleMouseEnter(handleDirection)
	m_isMouseOverHandle[handleDirection] = true
end

local function onHandleMouseLeave(handleDirection)
	m_isMouseOverHandle[handleDirection] = false
end

-- Returns the index of the rotate handle that the mouse is over. It returns
-- the lowest index if the mouse is over multiple rotate handles. 
--
-- Returns Direction.NOT_SET if the mouse was not over any handles.
--
-- int getMouseOverHandleIndex()
local function getMouseOverHandleIndex()
	local mouseOverIndex = Direction.NOT_SET
	for i = Direction.FIRST, Direction.LAST do
		if m_isMouseOverHandle[i] then
			mouseOverIndex = i
			break
		end	
	end
	
	return mouseOverIndex
end

-- Sets all the values in m_isMouseOverHandle to false.
--
-- void resetIsMouseOverHandle()
local function resetIsMouseOverHandle()
	for i = Direction.FIRST, Direction.LAST do
		m_isMouseOverHandle[i] = false		
	end
end

-- Creates the rotation handles. Called when the plugin is turned on and off.
local function createRotationHandles()
	if not m_handleParent then
		error("Could not create the rotation handles because the parent was nil.")
	end

	--[[
		Then handles should appear at the corners and the middle of the sides. Using
		the anchors points simplifies this, as we can just use those positions directly. 
	--]]
	local anchorPoints = {
		[Direction.E]  = Vector2.new(0, 0.5),
		[Direction.SE] = Vector2.new(0, 0),
		[Direction.S]  = Vector2.new(0.5, 0),
		[Direction.SW] = Vector2.new(1, 0),
		[Direction.W]  = Vector2.new(1, 0.5),
		[Direction.NW] = Vector2.new(1, 1),
		[Direction.N]  = Vector2.new(0.5, 1),
		[Direction.NE] = Vector2.new(0, 1)
	}
	
	--[[
		The rotation handles are positioned using Scale relative to the m_handleParent.
		That way their position will be updated automatically as the parent is resized.
	--]]
	local positions = {
		[Direction.E]  = UDim2.new(1, 0, 0.5, 0),
		[Direction.SE] = UDim2.new(1, 0, 1, 0),
		[Direction.S]  = UDim2.new(0.5, 0, 1, 0),
		[Direction.SW] = UDim2.new(0, 0, 1, 0),
		[Direction.W]  = UDim2.new(0, 0, 0.5, 0),
		[Direction.NW] = UDim2.new(0, 0, 0, 0),
		[Direction.N]  = UDim2.new(0.5, 0, 0, 0),
		[Direction.NE] = UDim2.new(1, 0, 0, 0)
	}	
	
	-- Create each rotation handle
	for i = Direction.FIRST, Direction.LAST do
		local rotationHandle = Instance.new("Frame")
		rotationHandle.Name = "RotationHandle_" .. Direction:toShortName(i)
		rotationHandle.AnchorPoint = anchorPoints[i]
		rotationHandle.Size = UDim2.new(0, ROTATION_HANDLE_SIZE, 0, ROTATION_HANDLE_SIZE)
		rotationHandle.Position = positions[i]
		-- Rotation handle only shows in debug mode
		rotationHandle.BackgroundColor3 = Color3.new(0, 255, 0)
		rotationHandle.BackgroundTransparency = m_debugMode and 0 or 1
		rotationHandle.BorderSizePixel = m_debugMode and 1 or 0
		
		-- Callbacks for when the handle is hovered		
		rotationHandle.MouseEnter:connect(function(x, y)
			onHandleMouseEnter(i)
		end)
		rotationHandle.MouseLeave:connect(function(x, y)
			onHandleMouseLeave(i)
		end)
		
		-- Add rotation handle
		rotationHandle.Parent = m_handleParent
		m_handles[i] = rotationHandle
	end
end

-- Creates the handle parent and the rotation handles
local function createHandles()
	createHandleParent()
	createRotationHandles()
end

function Rotate:getRotation()
	if not m_selectedObject then
		return 0.0
	end
	
	return m_selectedObject.AbsoluteRotation
end

-- Changes the mouse cursor to the relevant rotate cursor.
--
-- bool Rotate:updateMouseIcon()
function Rotate:updateMouseIcon()	
	if m_isRotating then
		return
	end	
	
	local handle = getMouseOverHandleIndex()
	if handle ~= Direction.NOT_SET then
		local absoluteRotation = m_selectedObject.AbsoluteRotation
		local mouseIconDirection = MouseIconManager:calcMouseIconDirection(handle, absoluteRotation)
		MouseIconManager:setToRotateIcon(mouseIconDirection)
	end
end

-- Returns true if the mouse cursor is over one of the rotation handles.
--
-- bool Rotate:isOverAHandle()
function Rotate:isOverAHandle()
	return getMouseOverHandleIndex() ~= Direction.NOT_SET
end

-- Returns the center in absolute pixels of a GuiObject, e.g. frame.
--
-- Vector2 calcCenter(GuiObject guiObject)
local function calcCenter(guiObject)
	local x = guiObject.AbsolutePosition.X + math.floor(guiObject.AbsoluteSize.X/2.0)
	local y = guiObject.AbsolutePosition.Y + math.floor(guiObject.AbsoluteSize.Y/2.0)
	
	return Vector2.new(x, y)
end

-- Starts rotating the selected object if the mouse is over a rotate handle.
--
-- void Rotate:onMouseDown(Vector2 location)
function Rotate:onMouseDown(location)
	if not m_selectedObject then
		return
	end	
	
	local mouseOverHandleIndex = getMouseOverHandleIndex()
	-- Don't start a rotation if the mouse is not over a rotation handle
	if not Direction:isValid(mouseOverHandleIndex) then
		return
	end
	
	m_isRotating = true
	m_originalRotation = m_selectedObject.Rotation
	m_referenceRotation = m_selectedObject.Rotation
	m_center = calcCenter(m_selectedObject)
	m_accumulatedAngle = 0
	-- Calculate the where the mouse is so that it can be used when the mouse is moved.
	m_previousMouseVec = location - m_center

	m_actionMediator:onRotateBegan(location)
end

-- Rounds the rotation angle to one degree.
-- 
-- double roundRotationAngle(double angle)
local function roundRotationAngle(angle)	
	return math.floor(angle + 0.5)
end

-- Constrains the rotation angle to between -360 and 360 degrees.
-- 
-- double constrainRotationAngle(double angle)
local function constrainRotationAngle(angle)
	local maxRotation = 360
	if angle >= 0 then
		return angle % maxRotation
	else
		return -(-angle % maxRotation)
	end
end

-- Rotates the selected object if rotation has been started.
--
-- void Rotate:onMouseMove(Vector2 location)
function Rotate:onMouseMove(location)
	if not m_isRotating then
		return
	end
			
	local mouseMoveVec = location - m_center -- From center to new mouse location
	local angleRadians = Utility:angleVector2(m_previousMouseVec, mouseMoveVec)
	local angle = math.deg(angleRadians)
	
	-- We want the user to be able to rotate the object counter-clockwise
	-- and get negative values all the way up to -360. Then it should roll
	-- over back to 0. When rotating clock-wise we want the user to get
	-- positive values all the way up to 360, and then roll over to 0. We
	-- ran into an issue where when the rotation became sufficiently large
	-- we could not know if the user had rotated one way or the other way.
	-- If we "reset" the vectors we meassure the angles between every so
	-- often, e.g. every 90 degrees, then we'll always get a small enough
	-- angle so the rotation remains positive or negative.
	m_accumulatedAngle = m_accumulatedAngle + angle
	local roundedRotation = roundRotationAngle(m_referenceRotation + m_accumulatedAngle)
	m_selectedObject.Rotation = constrainRotationAngle(roundedRotation)
	m_previousMouseVec = mouseMoveVec
	
	if math.abs(m_accumulatedAngle) > 90 then
		-- Make the current angle the reference angle, so we never have a
		-- large angle between the vectors. The 90 degrees was chosen 
		-- arbitrarily as something less than 180 degrees.
		m_referenceRotation = m_selectedObject.Rotation
		m_accumulatedAngle = 0
	end
	
	Rotate:update()
	
	m_actionMediator:onRotateChanged(location)
end

-- Ends rotating the selected object if rotation was started.
--
-- void Rotate:onMouseUp(Vector2 location)
function Rotate:onMouseUp(location)
	if not m_isRotating then
		return
	end

	-- Add undo point if the selected object was rotated
	if m_selectedObject.Rotation ~= m_originalRotation then 	
		ChangeHistoryService:SetWaypoint("Rotate object")
	end
	
	m_isRotating = false
	m_center = nil
	m_previousMouseVec = nil
	Rotate:update()

	m_actionMediator:onRotateEnded(location)
end

-- Returns true is the selected object is being rotated.
--
-- bool Rotate:isRotating()
function Rotate:isRotating()
	return m_isRotating
end

-- Updates the position of the rotate handles when the selected object's position,
-- anchor point, size or rotation changes. It can be either from from Properties
-- widget or by using the tools. 
function Rotate:update()
	if not m_selectedObject then
		return
	end
	
	m_handleParent.AnchorPoint = m_selectedObject.AnchorPoint
	local position = m_selectedObject.AbsolutePosition
	m_handleParent.Position = UDim2.new(0, position.X, 0, position.Y)
	local size = m_selectedObject.AbsoluteSize
	m_handleParent.Size = UDim2.new(0, size.X, 0, size.Y)
	m_handleParent.Rotation = m_selectedObject.AbsoluteRotation
end

function Rotate:onSelectionChanged()
	local filteredSelection = SelectionManager:getFilteredSelection()
	if #filteredSelection == 1 then
		m_selectedObject = filteredSelection[1]
		Rotate:update()
		-- The m_handleParent is completely transparent, so it's still not "visible" to
		-- the user. Setting it to visible enables the handles mouseEnter and mouseLeave
		-- events. It also looks better when m_debugMode is enabled.
		m_handleParent.Visible = true
	else
		m_selectedObject = nil
		m_handleParent.Visible = false
	end
end

-- Turns the Rotate feature on and performs initialization. Called when the plugin is turned on.
function Rotate:On()
	createHandles()
	resetIsMouseOverHandle()
	m_isRotating = false
	Rotate:update()
end

-- Turns the Rotate feature off and performs de-initialization. Called when the plugin is turned off.
function Rotate:Off()
	destroyHandleParentAndRotationHandles()
	m_isRotating = false
end

function Rotate:setActionMediator(actionMediator)
	m_actionMediator = actionMediator
end

return Rotate
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX035055C5AE0340A1B088236650AD91B7">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">Select</string>
				<string name="ScriptGuid">{0F669255-450A-4C1B-BC43-EF8797844724}</string>
				<ProtectedString name="Source"><![CDATA[

local Utility = require(script.Parent.Utility)
local SelectionManager = require(script.Parent.SelectionManager)
local InstanceInfo = require(script.Parent.InstanceInfo)
local Analytics		= require(script.Parent.Analytics)

local UserInputService = game:GetService("UserInputService")

local paintOrder = {} --array of paintOrder
local paintOrderMap = {} --map of child to position in order

local BUFFER_SIZE_MINIMUM = 5


local function doesPointExistInInstance(point, instance)
	if not instance or not instance:IsA("GuiBase2d") then return false end	
	
	local sizeBuffer = instance.AbsoluteSize
	sizeBuffer = Vector2.new(math.max(BUFFER_SIZE_MINIMUM, sizeBuffer.X), math.max(BUFFER_SIZE_MINIMUM, sizeBuffer.Y))
	
	local upperLeft = instance.AbsolutePosition + (instance.AbsoluteSize * 0.5) - (sizeBuffer * 0.5)
	
	return point.x >= upperLeft.x and
		point.x <= upperLeft.x + sizeBuffer.x and
		point.y >= upperLeft.y and
		point.y <= upperLeft.y + sizeBuffer.y
end



local function collectVisibleGuiObjectsUnder(instance)
	local children = instance:GetChildren()
	
	local allItems = {}
	for i = 1, #children do
		if (children[i]:IsA("GuiObject")) then
			
			local ancestors = collectVisibleGuiObjectsUnder(children[i])
			
			if (InstanceInfo:isVisible(children[i])) then
				table.insert(allItems, children[i])
			end
						
			for j = 1, #ancestors do
				table.insert(allItems, ancestors[j])
			end
		end
	end
	return allItems
end


local function guessScreenGui(sg)
	local anc = collectVisibleGuiObjectsUnder(sg)
	
	local orderMap = {}
	
	for i = 1, #anc do
		orderMap[anc[i]] = i;
	end
		
	local function guiSort(a, b)
		if (a.ZIndex == b.ZIndex) then
			return orderMap[a] < orderMap[b]
		end
		return a.ZIndex < b.ZIndex
	end
	
	table.sort(anc, guiSort)
	
	return anc
end

local function refreshPaintOrder()
	local starterGui = game.StarterGui
	local children = starterGui:GetChildren()
	
	paintOrder = {}
	
	for i = 1, #children do
		if (children[i]:IsA("ScreenGui")) then
			
			local guiAncestors = guessScreenGui(children[i])
			
			for i = 1, #guiAncestors do
				table.insert(paintOrder, guiAncestors[i])
				paintOrderMap[guiAncestors[i]] = #paintOrder
			end
		end
	end
	
	
end

local function getGuiObjectsAtPoint(point)
	local objectsAtPoint = {}
	
	for i = #paintOrder, 1, -1 do
		if (doesPointExistInInstance(point, paintOrder[i])) then
			table.insert(objectsAtPoint, paintOrder[i])
		end
	end
	return objectsAtPoint
end


local function getTopLevelItemAtPoint(point)
	refreshPaintOrder()
	
	local objectsAtPoint = getGuiObjectsAtPoint(point)
	local objectToSelect = objectsAtPoint[1]
	
	if (UserInputService:IsKeyDown(Enum.KeyCode.LeftAlt) or UserInputService:IsKeyDown(Enum.KeyCode.RightAlt)) then
		local location = Utility:findItemInTable(lastSelectedElement, objectsAtPoint)
		if (location ~= 0 and location ~= #objectsAtPoint) then
			objectToSelect = objectsAtPoint[location + 1]
		end
	end
	
	return objectToSelect
end

--return true if added, false if removed
local function toggleItemsExistenceInTable(item, t)

	local itemLocation = Utility:findItemInTable(item, t)
	
	if (itemLocation > 0) then
		table.remove(t, itemLocation)
		return false
	end
	
	table.insert(t, item)
	return true
end


local Select = {}

function Select:getGuiObjects()
	return {unpack(paintOrder)}
end

function Select:getGuiObjectsAtPoint(point)
	return getGuiObjectsAtPoint(point)
end

function Select:selectTopLevelItemAtPoint(point)
	
	local objectToSelect = getTopLevelItemAtPoint(point)
	
	local selection = SelectionManager:getRawSelection()
	
	local newSelection = {unpack(selection)}
	
	local analyticsSelectionReported = false
	
	if (objectToSelect) then
		if (UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) or
			UserInputService:IsKeyDown(Enum.KeyCode.RightControl) or
			UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or 
			UserInputService:IsKeyDown(Enum.KeyCode.RightShift)) then
			
			if (toggleItemsExistenceInTable(objectToSelect, newSelection)) then
				Analytics:reportEvent("AddToSelection")
			else
				Analytics:reportEvent("RemoveFromSelection")
			end
			analyticsSelectionReported = true
		elseif (Utility:findItemInTable(objectToSelect, newSelection) == 0) then
			newSelection = {objectToSelect}			
		end
	else
		if (UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or 
			UserInputService:IsKeyDown(Enum.KeyCode.RightShift)) then
			return nil
		elseif (Utility:findItemInTable(objectToSelect, newSelection) == 0) then
			newSelection = {objectToSelect}			
		end
	end
			
	lastSelectedElement = objectToSelect
	if (SelectionManager:setSelection(newSelection) and not analyticsSelectionReported) then
		if (SelectionManager:hasFilteredSelection()) then
			Analytics:reportEvent("Select")
		else
			Analytics:reportEvent("Deselect")
		end
	end
	
	return lastSelectedElement
end



function Select:selectAllObjectsInBounds(point1, point2)
	local min = Vector2.new(math.min(point1.X, point2.X), math.min(point1.Y, point2.Y))
	local max = Vector2.new(math.max(point1.X, point2.X), math.max(point1.Y, point2.Y))
	
	local totalSelected = {}
	for i = 1, #paintOrder do
		if (paintOrder[i].AbsolutePosition.X >= min.X and
			paintOrder[i].AbsolutePosition.Y >= min.Y and
			paintOrder[i].AbsolutePosition.X + paintOrder[i].AbsoluteSize.X <= max.X and
			paintOrder[i].AbsolutePosition.Y + paintOrder[i].AbsoluteSize.Y <= max.Y) then
		
			table.insert(totalSelected, paintOrder[i])
		end
	end
	
	SelectionManager:setSelection(totalSelected)	
end

function Select:toggleSelectionOfAllObjectsInBounds(previousSelection, point1, point2)
	local min = Vector2.new(math.min(point1.X, point2.X), math.min(point1.Y, point2.Y))
	local max = Vector2.new(math.max(point1.X, point2.X), math.max(point1.Y, point2.Y))
	
	local totalSelected = {}
	for i = 1, #paintOrder do
		if (paintOrder[i].AbsolutePosition.X >= min.X and
			paintOrder[i].AbsolutePosition.Y >= min.Y and
			paintOrder[i].AbsolutePosition.X + paintOrder[i].AbsoluteSize.X <= max.X and
			paintOrder[i].AbsolutePosition.Y + paintOrder[i].AbsoluteSize.Y <= max.Y) then
		
			table.insert(totalSelected, paintOrder[i])
		end
	end
	
	for i = 1, #previousSelection do
		local location = Utility:findItemInTable(previousSelection[i], totalSelected)
		
		if (location ~= 0) then
			table.remove(totalSelected, location)
		else
			table.insert(totalSelected, previousSelection[i])
		end
	end
	
	SelectionManager:setSelection(totalSelected)
end

return Select
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX93C446585EC64C03AF7138A4F1BA32FE">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">GlobalValues</string>
				<string name="ScriptGuid">{27B4468D-96B1-4D16-804E-4EFDDDDCE260}</string>
				<ProtectedString name="Source"><![CDATA[


local SCALE = 1
local OFFSET = 2

local m_gridType = SCALE








local GlobalValues = {}

function GlobalValues:isScale()
	return m_gridType == SCALE
end


function GlobalValues:toggleGridType()
	if (GlobalValues:isScale()) then
		m_gridType = OFFSET
		print("Setting Grid mode: Offset")
	else
		m_gridType = SCALE
		print("Setting Grid mode: Scale")
	end
end

function GlobalValues:getScreenSize()
	return game.Workspace.CurrentCamera.ViewportSize
end

--function GlobalValues:getGridType()
--	return m_gridType
--end
--
--function GlobalValues:setGridType(gridType)
--	m_gridType = gridType
--end

--GlobalValues.SCALE = SCALE
--GlobalValues.OFFSET = OFFSET

return GlobalValues
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="Script" referent="RBXD8CDB2B2F2404501AE335D775D7DE4CC">
			<Properties>
				<bool name="Disabled">false</bool>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">README</string>
				<string name="ScriptGuid">{246CC8ED-7B99-466C-B6BB-3B59DBE59695}</string>
				<ProtectedString name="Source"><![CDATA[
--[[
	
	---Overview---

	The UI Editor is an Official Roblox supported plugin shipped with Roblox Studio.
	
	The intention of this plugin is to enable developers to easily create good looking
	cross-platform user interfaces.
	
	
	---Function Comments---
	
	Given that lua is a weakly typed language we are using comments on functions to document 
	expected return and parameter types.
	
	Given the example
	
	-- void extend(table(mt Extents2D)& extents, Vector2 ...)
	local function extend(extents, ...) end
	
	We have a function named extend that takes a variable number of arguments.
	The first argument we expect is a table that has a metatable with the functionality of
	Extents2D (defined in the Extents2D module script). All other arguments after
	the first are expected to be of type Vector2(userdata). We expect that this function will
	not return anything. One thing of note is that we use the & symbol to describe that the
	extents table may be mutated by the function. Although not demonstrated here, we use the
	symbol ? to acknowledge that the type is not known
	
	
--]]

]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX81C0E2F99326451DAE139CE4641928E1">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">InstanceInfo</string>
				<string name="ScriptGuid">{55E2295C-E264-4599-9A2D-9250CEABDA31}</string>
				<ProtectedString name="Source"><![CDATA[







local function areAncestorsEnabledAndVisible(instance)
	if not instance or not instance.Parent then return false end
	
	if (instance.Parent:IsA("ScreenGui") and instance.Parent.Enabled == true) then
		return true
	end
	
	if (instance.Parent:IsA("GuiObject") and instance.Parent.Visible == true) then
		return areAncestorsEnabledAndVisible(instance.Parent)
	end
	
	if (instance.Parent:IsA("Folder")) then
		return areAncestorsEnabledAndVisible(instance.Parent)
	end
	
	return false
	
	--GuiObject    -Visible
	--ScreenGui    -Enabled
	
	
	--non GuiBase2d Parent or screen gui final
	
	
end



local InstanceInfo = {}

function InstanceInfo:isVisible(object, p)

	if (not object:IsA("GuiObject")) then
		return false
	end
	
	if (not object.Visible) then
		return false
	end	
	
	if (not areAncestorsEnabledAndVisible(object)) then
		return false
	end
	
	if (object.BackgroundTransparency >= 1.0) then
		if (object:IsA("ImageLabel") or object:IsA("ImageButton")) then
			return object.Image ~= "" and object.ImageTransparency < 1.0
		end
		
		if (object:IsA("TextLabel") or object:IsA("TextButton")) then
			return object.Text ~= "" and object.TextTransparency < 1.0
		end
		return false
	end
	
	return true
end

-- bool InstanceInfo:canSeeThrough(GuiObject object)
function InstanceInfo:canSeeThrough(object)
		
	if (not object:IsA("GuiObject") or
		not object.Visible or
		not areAncestorsEnabledAndVisible(object) or
		object.BackgroundTransparency > 0) then
		return true
	end
		
	return false
	
end

return InstanceInfo
















]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX3F98558B31C44A08841EE8E25945FE57">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">SnappingPointManager</string>
				<string name="ScriptGuid">{4ABC8724-DB27-4AF0-B141-A7C746152F09}</string>
				<ProtectedString name="Source"><![CDATA[
local Extents2D			= require(script.Parent.Extents2D)
local FFlag				= require(script.Parent.FFlag)
local GlobalValues		= require(script.Parent.GlobalValues)
local Select			= require(script.Parent.Select)
local SelectionManager	= require(script.Parent.SelectionManager)
local Set				= require(script.Parent.Set)
local Utility			= require(script.Parent.Utility)

local SnappingType 	= require(script.Parent.Enum.SnappingType)

--List of Generated Snapping Extents
local gExt = {}

local m_threshold = 1

local function closestSnappingLine(value, center, t)
	local closestLine = nil
	local closestDistance = 9e9
	
	for i = 1, #t do
		if (t[i][2] == center) then
			local delta = math.abs(value - t[i][1])
			if (delta < closestDistance) then
				closestDistance = delta
				closestLine = t[i][1]
			else
				break
			end
		end
	end
	
	return closestLine
end

-- void removeInstanceAndDescendantsFromTableExcludingSet(Instance instance, table t, table set)
local function removeInstanceAndDescendantsFromTableExcludingSet(instance, t, set)
	
	if (set[instance] ~= nil) then return end
	set[instance] = true
	
	--remove all entries of instance from the table
	while (Utility:removeItemFromTable(instance, t)) do end
	
	local children = instance:GetChildren()
	
	for i = 1, #children do
		removeInstanceAndDescendantsFromTableExcludingSet(children[i], t, set)
	end
end


local SnappingPointManager = {}

-- void SnappingPointManager:generateSnappingLines()
function SnappingPointManager:generateSnappingLines()
		
	gExt = {}
	
	local filteredSelection = SelectionManager:getFilteredSelection()
	if (#filteredSelection == 0) then return end
	
	local snappingInstances = Select:getGuiObjects()
	if (#snappingInstances == 0) then return end
	
	-- Remove currently selected items from table of all gui objects
	-- Using set to prevent removal of the same item
	local previouslyRemovedItems = {}
	for i = 1, #filteredSelection do
		removeInstanceAndDescendantsFromTableExcludingSet(filteredSelection[i], snappingInstances, previouslyRemovedItems)
	end
	
	for i = 1, #snappingInstances do
		table.insert(gExt, Extents2D:getExtentsFromGui(snappingInstances[i]))
	end
	
	-- Adding viewport
	table.insert(gExt, Extents2D.new(Vector2.new(0,0), GlobalValues:getScreenSize()))
end

local SNAPPING_LINE_MARGIN = 10

local EDGE_LINE_COLOR = Color3.new(255 / 255, 8 / 255, 103 / 255)
local CENTER_LINE_COLOR = Color3.new(0 / 255, 255 / 255, 0 / 255)

-- table(mt Extents2D), table(table), hasSnappedX, hasSnappedY SnappingPointManager:snapExtents(table(mt Extents2D) extents, int snappingType)
function SnappingPointManager:snapExtents(extents, snappingType)
	
	-- We don't want to edit extents, copying table
	extents = Utility:cloneTable(extents)
	
	local finalListOfSnappingLines = {}
	
	local hasSnappedX = false
	local hasSnappedY = false
	
	local distance, offset
	local listOfSnappingLines = {}
	
	local function clearData()
		--resetting distance to maximum snapping threshold
		-- We always want to test for less than distance, so adding 1
		distance = m_threshold + 1
		offset = 0
		listOfSnappingLines = {}
	end
	
	local function checkAndMaybeAddToSnappingLines(p1, p2, lp1, lp2, c)
		local d = Utility:distance(p1, p2)
		local o = p2 - p1
				
		if (d < distance) then
			listOfSnappingLines = {}
			distance = d
			offset = o
			table.insert(listOfSnappingLines, {lp1, lp2, c})
		elseif (d == distance and o == offset) then
			table.insert(listOfSnappingLines, {lp1, lp2, c})
		end
	end
	
	if (SnappingType:containsType(snappingType, SnappingType.MoveX)) then
		clearData()
		
		for i = 1, #gExt do
			
			if (gExt[i].LeftVisible) then
				checkAndMaybeAddToSnappingLines(
					extents.Left, gExt[i].Left,
					Vector2.new(gExt[i].Left, math.min(extents.Top, gExt[i].Top) - SNAPPING_LINE_MARGIN),
					Vector2.new(gExt[i].Left, math.max(extents.Bottom, gExt[i].Bottom) + SNAPPING_LINE_MARGIN),
					EDGE_LINE_COLOR)
				
				checkAndMaybeAddToSnappingLines(
					extents.Right, gExt[i].Left,
					Vector2.new(gExt[i].Left, math.min(extents.Top, gExt[i].Top) - SNAPPING_LINE_MARGIN),
					Vector2.new(gExt[i].Left, math.max(extents.Bottom, gExt[i].Bottom) + SNAPPING_LINE_MARGIN),
					EDGE_LINE_COLOR)
			end
			
			if (gExt[i].RightVisible) then
				checkAndMaybeAddToSnappingLines(
					extents.Left, gExt[i].Right,
					Vector2.new(gExt[i].Right, math.min(extents.Top, gExt[i].Top) - SNAPPING_LINE_MARGIN),
					Vector2.new(gExt[i].Right, math.max(extents.Bottom, gExt[i].Bottom) + SNAPPING_LINE_MARGIN),
					EDGE_LINE_COLOR)
				
				checkAndMaybeAddToSnappingLines(
					extents.Right, gExt[i].Right,
					Vector2.new(gExt[i].Right, math.min(extents.Top, gExt[i].Top) - SNAPPING_LINE_MARGIN),
					Vector2.new(gExt[i].Right, math.max(extents.Bottom, gExt[i].Bottom) + SNAPPING_LINE_MARGIN),
					EDGE_LINE_COLOR)
			end
			
			if (gExt[i].CenterVisible) then
				checkAndMaybeAddToSnappingLines(
					extents.Center.X, gExt[i].Center.X,
					Vector2.new(gExt[i].Center.X, math.min(extents.Top, gExt[i].Top) - SNAPPING_LINE_MARGIN),
					Vector2.new(gExt[i].Center.X, math.max(extents.Bottom, gExt[i].Bottom) + SNAPPING_LINE_MARGIN),
					CENTER_LINE_COLOR)						
			end
		end
		
		hasSnappedX = offset ~= 0
		extents = Extents2D:translate(extents, Vector2.new(offset, 0))
		finalListOfSnappingLines = Utility:joinTables(finalListOfSnappingLines, listOfSnappingLines)
	end
	
	if (SnappingType:containsType(snappingType, SnappingType.MoveY)) then
		clearData()
		
		for i = 1, #gExt do
			
			if (gExt[i].TopVisible) then
				checkAndMaybeAddToSnappingLines(
					extents.Top, gExt[i].Top,
					Vector2.new(math.min(extents.Left, gExt[i].Left) - SNAPPING_LINE_MARGIN, gExt[i].Top),
					Vector2.new(math.max(extents.Right, gExt[i].Right) + SNAPPING_LINE_MARGIN, gExt[i].Top),
					EDGE_LINE_COLOR)
				
				checkAndMaybeAddToSnappingLines(
					extents.Bottom, gExt[i].Top,
					Vector2.new(math.min(extents.Left, gExt[i].Left) - SNAPPING_LINE_MARGIN, gExt[i].Top),
					Vector2.new(math.max(extents.Right, gExt[i].Right) + SNAPPING_LINE_MARGIN, gExt[i].Top),
					EDGE_LINE_COLOR)
			end
			
			if (gExt[i].BottomVisible) then
				checkAndMaybeAddToSnappingLines(
					extents.Top, gExt[i].Bottom,
					Vector2.new(math.min(extents.Left, gExt[i].Left) - SNAPPING_LINE_MARGIN, gExt[i].Bottom),
					Vector2.new(math.max(extents.Right, gExt[i].Right) + SNAPPING_LINE_MARGIN, gExt[i].Bottom),
					EDGE_LINE_COLOR)
			
				checkAndMaybeAddToSnappingLines(
					extents.Bottom, gExt[i].Bottom,
					Vector2.new(math.min(extents.Left, gExt[i].Left) - SNAPPING_LINE_MARGIN, gExt[i].Bottom),
					Vector2.new(math.max(extents.Right, gExt[i].Right) + SNAPPING_LINE_MARGIN, gExt[i].Bottom),
					EDGE_LINE_COLOR)
			end

			if (gExt[i].CenterVisible) then
				checkAndMaybeAddToSnappingLines(
					extents.Center.Y, gExt[i].Center.Y,
					Vector2.new(math.min(extents.Left, gExt[i].Left) - SNAPPING_LINE_MARGIN, gExt[i].Center.Y),
					Vector2.new(math.max(extents.Right, gExt[i].Right) + SNAPPING_LINE_MARGIN, gExt[i].Center.Y),
					CENTER_LINE_COLOR)						
			end		
		end
		
		hasSnappedY = offset ~= 0
		extents = Extents2D:translate(extents, Vector2.new(0, offset))
		finalListOfSnappingLines = Utility:joinTables(finalListOfSnappingLines, listOfSnappingLines)
		
	end
	
	-- Positive X
	if (SnappingType:containsType(snappingType, SnappingType.ResizeXp)) then
		clearData()
				
		for i = 1, #gExt do
			if (gExt[i].LeftVisible) then
				checkAndMaybeAddToSnappingLines(
					extents.Right, gExt[i].Left,
					Vector2.new(gExt[i].Left, math.min(extents.Top, gExt[i].Top) - SNAPPING_LINE_MARGIN),
					Vector2.new(gExt[i].Left, math.max(extents.Bottom, gExt[i].Bottom) + SNAPPING_LINE_MARGIN),
					EDGE_LINE_COLOR)
			end
			
			if (gExt[i].RightVisible) then
				checkAndMaybeAddToSnappingLines(
					extents.Right, gExt[i].Right,
					Vector2.new(gExt[i].Right, math.min(extents.Top, gExt[i].Top) - SNAPPING_LINE_MARGIN),
					Vector2.new(gExt[i].Right, math.max(extents.Bottom, gExt[i].Bottom) + SNAPPING_LINE_MARGIN),
					EDGE_LINE_COLOR)	
			end
			

		end
		
		hasSnappedX = offset ~= 0	
		extents.Right = extents.Right + offset
		finalListOfSnappingLines = Utility:joinTables(finalListOfSnappingLines, listOfSnappingLines)
	end
	
	-- Negative X
	if (SnappingType:containsType(snappingType, SnappingType.ResizeXn)) then
		clearData()
		
		for i = 1, #gExt do
			
			if (gExt[i].LeftVisible) then
				checkAndMaybeAddToSnappingLines(
					extents.Left, gExt[i].Left,
					Vector2.new(gExt[i].Left, math.min(extents.Top, gExt[i].Top) - SNAPPING_LINE_MARGIN),
					Vector2.new(gExt[i].Left, math.max(extents.Bottom, gExt[i].Bottom) + SNAPPING_LINE_MARGIN),
					EDGE_LINE_COLOR)
			end
			
			if (gExt[i].RightVisible) then
				checkAndMaybeAddToSnappingLines(
					extents.Left, gExt[i].Right,
					Vector2.new(gExt[i].Right, math.min(extents.Top, gExt[i].Top) - SNAPPING_LINE_MARGIN),
					Vector2.new(gExt[i].Right, math.max(extents.Bottom, gExt[i].Bottom) + SNAPPING_LINE_MARGIN),
					EDGE_LINE_COLOR)
			end
			
		end
		
		hasSnappedX = offset ~= 0	
		extents.Left = extents.Left + offset
		finalListOfSnappingLines = Utility:joinTables(finalListOfSnappingLines, listOfSnappingLines)
	end
	
	-- Positive Y
	if (SnappingType:containsType(snappingType, SnappingType.ResizeYp)) then
		clearData()
				
		for i = 1, #gExt do
			
			if (gExt[i].TopVisible) then
				checkAndMaybeAddToSnappingLines(
					extents.Bottom, gExt[i].Top,
					Vector2.new(math.min(extents.Left, gExt[i].Left) - SNAPPING_LINE_MARGIN, gExt[i].Top),
					Vector2.new(math.max(extents.Right, gExt[i].Right) + SNAPPING_LINE_MARGIN, gExt[i].Top),
					EDGE_LINE_COLOR)
			end
			
			if (gExt[i].BottomVisible) then
				checkAndMaybeAddToSnappingLines(
					extents.Bottom, gExt[i].Bottom,
					Vector2.new(math.min(extents.Left, gExt[i].Left) - SNAPPING_LINE_MARGIN, gExt[i].Bottom),
					Vector2.new(math.max(extents.Right, gExt[i].Right) + SNAPPING_LINE_MARGIN, gExt[i].Bottom),
					EDGE_LINE_COLOR)
			end
		end
		
		hasSnappedY = offset ~= 0
		extents.Bottom = extents.Bottom + offset
		finalListOfSnappingLines = Utility:joinTables(finalListOfSnappingLines, listOfSnappingLines)
	end
	
	-- Negative Y
	if (SnappingType:containsType(snappingType, SnappingType.ResizeYn)) then
		clearData()
				
		for i = 1, #gExt do
			
			if (gExt[i].TopVisible) then
				checkAndMaybeAddToSnappingLines(
					extents.Top, gExt[i].Top,
					Vector2.new(math.min(extents.Left, gExt[i].Left) - SNAPPING_LINE_MARGIN, gExt[i].Top),
					Vector2.new(math.max(extents.Right, gExt[i].Right) + SNAPPING_LINE_MARGIN, gExt[i].Top),
					EDGE_LINE_COLOR)
			end
			
			if (gExt[i].BottomVisible) then
				checkAndMaybeAddToSnappingLines(
					extents.Top, gExt[i].Bottom,
					Vector2.new(math.min(extents.Left, gExt[i].Left) - SNAPPING_LINE_MARGIN, gExt[i].Bottom),
					Vector2.new(math.max(extents.Right, gExt[i].Right) + SNAPPING_LINE_MARGIN, gExt[i].Bottom),
					EDGE_LINE_COLOR)
			end
							
		end
		
		hasSnappedY = offset ~= 0
		extents.Top = extents.Top + offset
		finalListOfSnappingLines = Utility:joinTables(finalListOfSnappingLines, listOfSnappingLines)
	end
	return extents, finalListOfSnappingLines, hasSnappedX, hasSnappedY
end

function SnappingPointManager:setThreshold(value)
	m_threshold = value
end

return SnappingPointManager
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX23032C8104094BB4AFA9704E001D4521">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">Set</string>
				<string name="ScriptGuid">{526CED19-5FF7-4070-A852-B7ACD5447A74}</string>
				<ProtectedString name="Source"><![CDATA[
local HttpService = game:GetService("HttpService")

local function getUniqueKey(t)
	return HttpService:JSONEncode(t)
end


local Set = {}

function Set.new()
	local setTable = {}
	setTable.map = {}
	setTable.mt = {}
	
	function setTable.mt.__index(t, k)
		if k == "insert" then
			return function(v)
				
				local pk = v
				if (type(pk) == "table") then
					pk = getUniqueKey(pk)
				end
				
				if (not t.map[pk]) then
					table.insert(t, v)
					t.map[pk] = #t
				end
			end
		elseif k == "remove" then
			return function(v)
				
				local pk = v
				if (type(pk) == "table") then
					pk = getUniqueKey(pk)
				end
				
				if (t.map[pk]) then
					local index = t.map[pk]
					table.remove(setTable, index)
					for i = index, #t do
						
						pk = t[i]
						if (type(pk) == "table") then
							pk = getUniqueKey(pk)
						end
						
						t.map[pk] = i
					end
				end
			end
		elseif k == "exists" then
			return function(v)
				
				local pk = v
				if (type(pk) == "table") then
					pk = getUniqueKey(pk)
				end
				
				return t.map[pk] ~= nil
			end
		elseif k == "clear" then
			return function()
				while #t > 0 do
					
					local pk = t[1]
					if (type(pk) == "table") then
						pk = getUniqueKey(pk)
					end
				
					t.map[pk] = nil
					table.remove(t, 1)
				end
			end
		end
	end
	
	setmetatable(setTable, setTable.mt)	
	return setTable
end



return Set


]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBXB38810A102104FAE8932FF7B1CB532F3">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">UniqueArrayMap</string>
				<string name="ScriptGuid">{90ADDAC7-524C-4817-9CF1-5957A24B30A3}</string>
				<ProtectedString name="Source"><![CDATA[local UniqueArrayMap = {}

function UniqueArrayMap.new()
	local setTable = {}
	setTable.map = {}
	setTable.mt = {}
	
	function setTable.mt.__index(t, k)
		if k == "insert" then
			return function(key, value)
				if (not t.map[key]) then
					table.insert(t, {key, value})
					t.map[key] = #t
				end
			end
		elseif k == "remove" then
			return function(key, value)
				if (t.map[key]) then
					local index = t.map[key]
					table.remove(setTable, index)
					for i = index, #t do
						t.map[t[i][1]] = i
					end
				end
			end
		elseif k == "exists" then
			return function(key)
				return t.map[key] ~= nil
			end
		elseif k == "clear" then
			return function()
				while #t > 0 do
					t.map[t[1][1]] = nil
					table.remove(t, 1)
				end
			end
		end
	end
	
	setmetatable(setTable, setTable.mt)	
	return setTable
end

return UniqueArrayMap
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBXBD3D1D7FC21A475F8E19877B6B5F0F10">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">Analytics</string>
				<string name="ScriptGuid">{B36AE4D4-87BA-4539-B18A-679A05D2AF81}</string>
				<ProtectedString name="Source"><![CDATA[
local success, AnalyticsService = pcall(function() return game:GetService("AnalyticsService") end)

local Analytics = {}

-- void Analytics:reportEvent(string event)
function Analytics:reportEvent(event)
	if (not success or not AnalyticsService) then return end --Not currently enabled
	AnalyticsService:TrackEvent("Studio", "UIEditorAction", event)
end

return Analytics
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX37AC2C12C95147FB93651A6972A387A0">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">Convert</string>
				<string name="ScriptGuid">{C7662E52-DE31-43E9-A36E-202A8DF06CAE}</string>
				<ProtectedString name="Source"><![CDATA[local GlobalValues = require(script.Parent.GlobalValues)

local Convert = {}

function Convert:convertAbsoluteToScaleOrOffset(positionUDimTypeIsScale, sizeUDimTypeIsScale, absPosition, absSize, pos, size, parent)
	
	local finalPosition
	local finalSize
	
	if (positionUDimTypeIsScale) then
		--scale
		local scalePosition = ((absPosition - Vector2.new(pos.X.Offset, pos.Y.Offset)) - parent.AbsolutePosition) / parent.AbsoluteSize
		finalPosition = UDim2.new( scalePosition.X, pos.X.Offset, scalePosition.Y, pos.Y.Offset)
	else
		--offset
		local offsetPosition = absPosition - (Vector2.new(pos.X.Scale, pos.Y.Scale) * parent.AbsoluteSize) - parent.AbsolutePosition
		finalPosition = UDim2.new( pos.X.Scale, offsetPosition.X, pos.Y.Scale, offsetPosition.Y)
	end
	
	if (sizeUDimTypeIsScale) then
		--scale
		local scaleSize = (absSize - Vector2.new(size.X.Offset, size.Y.Offset)) / parent.AbsoluteSize
		finalSize = UDim2.new( scaleSize.X, size.X.Offset, scaleSize.Y, size.Y.Offset)
	else
		--offset
		local offsetSize = absSize - (Vector2.new(size.X.Scale, size.Y.Scale) * parent.AbsoluteSize)
		finalSize = UDim2.new( size.X.Scale, offsetSize.X, size.Y.Scale, offsetSize.Y)
	end
	
	return finalPosition, finalSize
end

return Convert
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX76D12A518B504CA3931774DEBA4978BB">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">FFlag</string>
				<string name="ScriptGuid">{65FDFEE9-A352-40A8-BCDB-37473F6BB9DC}</string>
				<ProtectedString name="Source"><![CDATA[
local flagMap = {}

-- void getFFlagValue(string flag)
local function getFFlagValue(flag)
	local flagExists, flagValue = pcall(function () return settings():GetFFlag(flag) end)
	flagMap[flag] = flagExists and flagValue
end


local FFlag = {}

-- bool FFlag:isEnabled(string flag)
function FFlag:isEnabled(flag)
	if (flagMap[flag] == nil) then
		getFFlagValue(flag)
	end
	
	return flagMap[flag]
end

return FFlag
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX90E5CDA518324D00A0CF01EEB17E3C21">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">Extents2D</string>
				<string name="ScriptGuid">{6653155F-BD2E-4D8D-8842-995B9061446E}</string>
				<ProtectedString name="Source"><![CDATA[--[[
	The Extents2D module is used for calculating the position and size of the bounding box
	and the resize handles. It will contain all the selected objects.
--]]

-- Module scripts
local FFlag	= require(script.Parent.FFlag)
local InstanceInfo = require(script.Parent.InstanceInfo)
local Utility = require(script.Parent.Utility)
local Select = require(script.Parent.Select)

-- Flags
local FFlagStudioUIEditorV2Alpha = FFlag:isEnabled("StudioUIEditorV2Alpha")

-- Functions

-- void refreshData(table(mt Extents2D)& extents)
local function refreshData(extents)
	
	-- We use extents.hidden.TopLeft and extents.hidden.BottomRight as
	-- the source of truth for data. Everything else is derived from those
	-- two points.
	extents.Center = (extents.hidden.TopLeft + extents.hidden.BottomRight) * 0.5
	
	extents.hidden.Left = extents.hidden.TopLeft.X
	extents.hidden.Right = extents.hidden.BottomRight.X
	extents.hidden.Top = extents.hidden.TopLeft.Y
	extents.hidden.Bottom = extents.hidden.BottomRight.Y
	extents.hidden.TopRight = Vector2.new(extents.Right, extents.Top)
	extents.hidden.BottomLeft = Vector2.new(extents.Left, extents.Bottom)
	
	extents.Width = extents.hidden.Right - extents.hidden.Left
	extents.Height = extents.hidden.Bottom - extents.hidden.Top
	
	extents.Size = Vector2.new(extents.Width, extents.Height)
	
end

-- bool isPointVisible(Instance instance, Vector2 point)
local function isPointVisible(instance, point)
	if (not instance) then return true end
	local guis = Select:getGuiObjectsAtPoint(point)
		
	for i = 1, #guis do
		if (guis[i] == instance) then
			return true
		end
		
		if (not InstanceInfo:canSeeThrough(guis[i])) then
			return false
		end
	end
	return false
end

-- void refreshVisibility(table(mt Extents2D), Instance instance)
local function refreshVisibility(extents, instance)
	
	extents.hidden.TopLeftVisible = isPointVisible(instance, extents.hidden.TopLeft)
	extents.hidden.TopRightVisible = isPointVisible(instance, extents.hidden.TopRight)
	extents.hidden.BottomLeftVisible = isPointVisible(instance, extents.hidden.BottomLeft)
	extents.hidden.BottomRightVisible = isPointVisible(instance, extents.hidden.BottomRight)
	extents.hidden.CenterVisible = isPointVisible(instance, extents.Center)
end

-- void extend(table(mt Extents2D)& extents, Vector2 ...)
local function extend(extents, ...)
	local args = {...}
	
	for i = 1, #args do
		extents.hidden.TopLeft = Utility:minVector2(extents.hidden.TopLeft, args[i])
		extents.hidden.BottomRight = Utility:maxVector2(extents.hidden.BottomRight, args[i])
	end
	
	refreshData(extents)
end

-- void set(table(mt Extents2D)& extents, Vector2 ...)
local function set(extents, ...)
	local args = {...}
	if (#args > 0) then
		extents.hidden.TopLeft = args[1]
		extents.hidden.BottomRight = args[1]
		
		table.remove(args, 1)
		
		extend(extents, unpack(args))
	else
		refreshData(extents)
	end
	
end

-- void Extents2D:translate(table(mt Extents2D)& extents, Vector2 offset)
function translate(extents, offset)
	extents.hidden.TopLeft = extents.hidden.TopLeft + offset
	extents.hidden.BottomRight = extents.hidden.BottomRight + offset
	refreshData(extents)
end

-- void Extents2D:resize(table(mt Extents2D)& extents, Vector2 offset)
function resize(extents, size)
	extents.hidden.BottomRight = extents.hidden.TopLeft + size
	refreshData(extents)
end

-- void Extents2D:extendFromCenter(table(mt Extents2D)& extents, Vector2 offset)
function expandFromCenter(extents, sizeOffset)	
	local offset = sizeOffset * 0.5
	
	extents.TopLeft = extents.TopLeft - offset
	extents.BottomRight = extents.BottomRight + offset
	
	refreshData(extents)
end



local Extents2D = {}

-- table(mt Extents2D) Extents2D.new(Vector2 ...)
function Extents2D.new(...)
	local extents = {}
	extents.map = {}
	extents.mt = {}
	extents.hidden = {}
	extents.hidden.TopLeft = Vector2.new(0,0)
	extents.hidden.BottomRight = Vector2.new(0,0)
	
	set(extents, ...)
	refreshVisibility(extents)
	
	function extents.mt.__index(t, k)
		if k == "extend" then
			return extend
		elseif k == "set" then
			return set
		elseif k == "TopLeft" then
			return t.hidden.TopLeft
		elseif k == "BottomRight" then
			return t.hidden.BottomRight	
		elseif k == "TopRight" then
			return t.hidden.TopRight
		elseif k == "BottomLeft" then
			return t.hidden.BottomLeft		
		elseif k == "Top" then
			return t.hidden.Top
		elseif k == "Bottom" then
			return t.hidden.Bottom
		elseif k == "Left" then
			return t.hidden.Left
		elseif k == "Right" then
			return t.hidden.Right
			
		elseif k == "TopLeftVisible" then
			return extents.hidden.TopLeftVisible
		elseif k == "TopRightVisible" then
			return extents.hidden.TopRightVisible
		elseif k == "BottomLeftVisible" then
			return extents.hidden.BottomLeftVisible
		elseif k == "BottomRightVisible" then
			return extents.hidden.BottomRightVisible
		elseif k == "TopVisible" then
			return extents.hidden.TopLeftVisible or extents.hidden.TopRightVisible
		elseif k == "BottomVisible" then
			return extents.hidden.BottomLeftVisible or extents.hidden.BottomRightVisible
		elseif k == "LeftVisible" then
			return extents.hidden.TopLeftVisible or extents.hidden.BottomLeftVisible
		elseif k == "RightVisible" then
			return extents.hidden.TopRightVisible or extents.hidden.BottomRightVisible
		elseif k == "CenterVisible" then
			return extents.hidden.CenterVisible
			
		elseif k == "translate" then
			return translate
		elseif k == "resize" then
			return resize
		elseif k == "expandFromCenter" then
			return expandFromCenter
		end
	end
	
	function extents.mt.__newindex(t, k, v)
		if k == "TopLeft" then
			t.hidden.TopLeft = v
		elseif k == "BottomRight" then
			t.hidden.BottomRight = v
		elseif k == "TopRight" then
			t.hidden.TopLeft = Vector2.new(t.hidden.Left, v.Y)
			t.hidden.BottomRight = Vector2.new(v.X, t.hidden.Bottom)
		elseif k == "BottomLeft" then
			t.hidden.TopLeft = Vector2.new(v.X, t.hidden.Top)
			t.hidden.BottomRight = Vector2.new(t.hidden.Right, v.Y)
		elseif k == "Top" then
			t.hidden.TopLeft = Vector2.new(t.hidden.Left, v)
		elseif k == "Bottom" then
			t.hidden.BottomRight = Vector2.new(t.hidden.Right, v)
		elseif k == "Left" then
			t.hidden.TopLeft = Vector2.new(v, t.hidden.Top)
		elseif k == "Right" then
			t.hidden.BottomRight = Vector2.new(v, t.hidden.Bottom)
		end
		refreshData(t)
	end
	
	setmetatable(extents, extents.mt)	
	return extents
end

-- table(mt Extents2D) Extents2D:translate(table(mt Extents2D) extents, Vector2 offset)
function Extents2D:translate(extents, offset)
	local clone = Utility:cloneTable(extents)
	translate(clone, offset)
	return clone
end

-- table(mt Extents2D) Extents2D:resize(table(mt Extents2D) extents, Vector2 size)
function Extents2D:resize(extents, size)
	local clone = Utility:cloneTable(extents)
	resize(extents, size)
	return clone
end

-- table(mt Extents2D) Extents2D:expandFromCenter(table(mt Extents2D) extents, Vector2 sizeOffset)
function Extents2D:expandFromCenter(extents, sizeOffset)
	local clone = Utility:cloneTable(extents)
	expandFromCenter(extents, sizeOffset)
	return clone
end

-- table(mt Extents2D) Extents2D:getExtentsFromGui(GuiBase2d guiObject)
function Extents2D:getExtentsFromGui(guiObject)
	local extents = Extents2D.new()
	set(extents, guiObject.AbsolutePosition, guiObject.AbsolutePosition + guiObject.AbsoluteSize)
	
	refreshVisibility(extents, guiObject)
	
	return extents
end

-- table(mt Extents2D) Extents2D:getExtentsFromGuis(table(GuiBase2d) guiObjects)
function Extents2D:getExtentsFromGuis(guiObjects)
	if (#guiObjects == 0) then return nil end
	
	local extents = Extents2D.new()
	set(extents, guiObjects[1].AbsolutePosition, guiObjects[1].AbsolutePosition + guiObjects[1].AbsoluteSize)
	
	if FFlagStudioUIEditorV2Alpha then
		for i = 2, #guiObjects do
			extend(extents, guiObjects[i].AbsolutePosition, guiObjects[i].AbsolutePosition + guiObjects[i].AbsoluteSize)
		end		
	else
		for i = 2, #guiObjects do
			extend(extents, guiObjects[2].AbsolutePosition, guiObjects[2].AbsolutePosition + guiObjects[2].AbsoluteSize)
		end	
	end
	
	return extents
end

return Extents2D
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="Folder" referent="RBXF91F94A37C5740719F3914384A88C42C">
			<Properties>
				<string name="Name">Enum</string>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
			<Item class="ModuleScript" referent="RBX13E4C26CE68A4447A7A758243A3F36E6">
				<Properties>
					<Content name="LinkedSource"><null></null></Content>
					<string name="Name">SnappingType</string>
					<string name="ScriptGuid">{5C0DCE85-5878-4418-8545-030BF2B0CB20}</string>
					<ProtectedString name="Source"><![CDATA[

local SnappingType = {}

SnappingType.MoveX			= 0
SnappingType.MoveY			= 1
SnappingType.MoveXY			= 2

SnappingType.ResizeXp		= 3
SnappingType.ResizeXn		= 4
SnappingType.ResizeYp		= 5
SnappingType.ResizeYn		= 6
SnappingType.ResizeXpYp		= 7
SnappingType.ResizeXnYp		= 8
SnappingType.ResizeXpYn		= 9
SnappingType.ResizeXnYn		= 10

function SnappingType:containsType(baseType, containType)
	if (baseType == containType) then
		return true
	end
	
	if (baseType == SnappingType.MoveXY) then
		return containType == SnappingType.MoveX or containType == SnappingType.MoveY
	elseif (baseType == SnappingType.ResizeXpYp) then
		return containType == SnappingType.ResizeXp or containType == SnappingType.ResizeYp
	elseif (baseType == SnappingType.ResizeXnYp) then
		return containType == SnappingType.ResizeXn or containType == SnappingType.ResizeYp
	elseif (baseType == SnappingType.ResizeXpYn) then
		return containType == SnappingType.ResizeXp or containType == SnappingType.ResizeYn
	elseif (baseType == SnappingType.ResizeXnYn) then
		return containType == SnappingType.ResizeXn or containType == SnappingType.ResizeYn
	end
	
	return false
end

return SnappingType
]]></ProtectedString>
					<BinaryString name="Tags"></BinaryString>
				</Properties>
			</Item>
			<Item class="ModuleScript" referent="RBX68617554C7D14718A04F4C92C94E179D">
				<Properties>
					<Content name="LinkedSource"><null></null></Content>
					<string name="Name">Axis</string>
					<string name="ScriptGuid">{BB6169DC-17DB-419E-8A0F-1BD51E53EC7C}</string>
					<ProtectedString name="Source"><![CDATA[--[[
	Defines the x and y axis as positive numbers so they can be used for looking up data.  
--]] 

local Axis = {}
Axis.X = 1
Axis.Y = 2
return Axis
]]></ProtectedString>
					<BinaryString name="Tags"></BinaryString>
				</Properties>
			</Item>
			<Item class="ModuleScript" referent="RBX77D8B3B50A5E4D6E9AE3CDCEA6DDA1D3">
				<Properties>
					<Content name="LinkedSource"><null></null></Content>
					<string name="Name">Direction</string>
					<string name="ScriptGuid">{473B14D8-418B-43F2-BC05-FA03EECC0261}</string>
					<ProtectedString name="Source"><![CDATA[--[[
	Direction defines the common compass directions, e.g. northwest, north, ...
--]]

local Direction = {}

-- Constants
local DEGREES_IN_CIRCLE = 360
local NUM_DIRECTIONS = 8
local INV_DEGREES_IN_CIRCLE = 1/DEGREES_IN_CIRCLE
local SPAN_IN_DEGREES = DEGREES_IN_CIRCLE/NUM_DIRECTIONS
local INV_SPAN_IN_DEGREES = 1/SPAN_IN_DEGREES
local HALF_SPAN_IN_DEGREES = SPAN_IN_DEGREES/2

-- The directions
-- NOTE: The functions Direction:angleToDirection and Direction:directionToAngle depend
-- on the current direction values. They will need to be changed if the values change.
Direction.NOT_SET = 0
Direction.E   = 1
Direction.SE  = 2
Direction.S   = 3
Direction.SW  = 4
Direction.W   = 5
Direction.NW  = 6
Direction.N   = 7
Direction.NE  = 8

-- You can use the FIRST and LAST to iterate over the directions
Direction.FIRST = Direction.E
Direction.LAST  = Direction.NE

local m_shortNames = {
	[Direction.E]  = "E",
	[Direction.SE] = "SE",
	[Direction.S]  = "S",
	[Direction.SW] = "SW",
	[Direction.W]  = "W",
	[Direction.NW] = "NW",
	[Direction.N]  = "N",
	[Direction.NE] = "NE"
}

-- Returns true if the passed in direction(as an integer) is valid. Returns
-- false otherwise.
--
-- bool Direction:isValid(int direction)
function Direction:isValid(direction)
	return Direction.FIRST <= direction and direction <= Direction.LAST 
end

-- Returns the short name, e.g. N, S, E, W,... given a direction.
--
-- string Direction:toShortName(int direction)
function Direction:toShortName(direction)
	if not Direction:isValid(direction) then
		error("Direction", direction, "is not valid. Cannot convert to short name.")
	end
	
	return m_shortNames[direction]
end

-- Normalizes an angle in degrees to 0..360 degress.
--
-- double normalizeAngle(double angle)
function normalizeAngle(angle)
	-- Using INV_DEGREES_IN_CIRCLE to avoid division
	return angle + math.ceil(-angle*INV_DEGREES_IN_CIRCLE)*DEGREES_IN_CIRCLE
end

-- Returns the closest direction from an angle.
--
-- For example, 15 degrees returns Direction.E.
--
-- Direction Direction:angleToDirection(double angle)
function Direction:angleToDirection(angle)	
	-- The first handle direction is 1. It spans 45 degrees from 337.5 to 22.5 degrees,
	-- which is why we first need to add 22.5 and then divide by 45. We need mod 8 so
	-- the maximum handle is 8. Finally the plus one is to start at one insted of zero. 
	local normalizedAngle = normalizeAngle(angle)
	return (math.floor((normalizedAngle + HALF_SPAN_IN_DEGREES) * INV_SPAN_IN_DEGREES) % NUM_DIRECTIONS) + 1
end

-- Returns the angle to a direction.
--
-- For example, Direction.E returns 0, Direction.SE returns 45 and so forth.
--
-- double Direction:directionToAngle(Direction direction)
function Direction:directionToAngle(direction)
	assert(Direction.E == 1, "Direction.E was not the first direction.")
	assert(Direction.NE == 8, "Direction.NE was not the last direction.")
	assert(Direction:isValid(direction))	
	
	-- There are eight directions, 360/8 is 45.
	return (direction - 1) * SPAN_IN_DEGREES
end

return Direction]]></ProtectedString>
					<BinaryString name="Tags"></BinaryString>
				</Properties>
			</Item>
		</Item>
		<Item class="ModuleScript" referent="RBXF28226C5B14A4BEB98B943A35202E26F">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">Log</string>
				<string name="ScriptGuid">{DB87BDB3-0926-48F1-9118-DF42631F642F}</string>
				<ProtectedString name="Source"><![CDATA[-----------------------------------
---------------Log-----------------
-----------------------------------
--[[
	The log module script lets you log message from the plugin. Use this instead of print. It
	was added because we kept forgetting to remove print statements. You have to set
	isLoggingEnabled to true when logging, and remember to set it back to false before
	submitting your code. That means that there's only one place to turn the log messages
	on and off.
--]]
local Log = {}

-- Don't check isLoggingEnabled in as true! It will spam the Output window.
local isLoggingEnabled = false

-- Use this log method instead of print to avoid stray print messages getting shipped.
-- You can pass additional arguments when logging, e.g. Log:log("x is", x)
function Log:log(message, ...)
	if isLoggingEnabled then
		print(message, ...)
	end
end

return Log]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX8AE373D97B124AEFA7555F029D7C9616">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">SizeBox</string>
				<string name="ScriptGuid">{D6073BB5-9075-40A6-8654-BC86985670BC}</string>
				<ProtectedString name="Source"><![CDATA[--[[
	The SizeBox is displayed when the user selects an object in the UI Editor. It
	doesn't show if multiple objects are selected.
	
	The SizeBox updates its size as the selected object is resized. It also updates
	its position as the selected object is moved.
	
	The SizeBox is using the ValueBox to display the size.
--]]
local SizeBox = {}

-- Module scripts
local SelectionManager = require(script.Parent.SelectionManager)
local ValueBox = require(script.Parent.ValueBox)

-- Variables
local m_selectedObject = nil
local m_valueBox = nil

-- Constants
local VALUE_BOX_MARGIN = Vector2.new(2, 6) -- Margin between the selected object and ValueBox

-- Functions

-- Takes a GUI object and returns a UDim2 with the position of
-- where the SizeBox should be positioned.
--
-- UDim2 calcSizeBoxPosition(GuiObject object)
local function calcSizeBoxPosition(object)
	local objectSize = object.AbsoluteSize
	local objectPosition = object.AbsolutePosition
	local valueBoxSize = m_valueBox:getSize()

	-- Use max x so that when an object is very narrow the SizeBox always appears to the
	-- right of the left side.
	local newX = math.max(objectPosition.X + objectSize.X - valueBoxSize.X.Offset - VALUE_BOX_MARGIN.X, 
		objectPosition.X + VALUE_BOX_MARGIN.X)
	local newY = objectPosition.Y + objectSize.Y + VALUE_BOX_MARGIN.Y
	
	return UDim2.new(0, newX, 0, newY)
end

-- Updates the text, size and the position of the SizeBox from the GUI object. It needs to
-- be called when the selected object is changed or resized.
function SizeBox:update()
	if not m_selectedObject then
		return
	end

	-- Set label text to the size of the selected object. The properties widget
	-- truncates to an integer so we'll do the same here.
	local objectSize = m_selectedObject.AbsoluteSize
	local newText = ("%d x %d"):format(objectSize.X, objectSize.Y)
	m_valueBox:setText(newText)
	
	SizeBox:updatePosition()
end

-- Shows or hides the SizeBox.
--
-- void SizeBox:setVisible(bool visible)
function SizeBox:setVisible(visible)
	if not m_selectedObject then
		return
	end	
	
	m_valueBox:setVisible(visible)
end

function SizeBox:onSelectionChanged()
	local filteredSelection = SelectionManager:getFilteredSelection()
	-- Only show the SizeBox if one GUI object is selected for now.
	if #filteredSelection == 1 then
		m_selectedObject = filteredSelection[1]
		SizeBox:update()
		SizeBox:setVisible(true)
	else
		SizeBox:setVisible(false)
		m_selectedObject = nil
	end
end

-- Updates the position of the SizeBox. Used when moving the selected object around
-- without re-sizing it.
function SizeBox:updatePosition()
	if not m_selectedObject then
		return
	end
	
	local newPosition = calcSizeBoxPosition(m_selectedObject)
	m_valueBox:setPosition(newPosition)
end

-- Turns the SizeBox on and performs initialization. Called when the plugin is turned on.
function SizeBox:On()
	m_valueBox = ValueBox.new()
end

-- Turns the SizeBox off and performs de-initialization. Called when the plugin is turned off.
function SizeBox:Off()	
	m_selectedObject = nil
	m_valueBox:Destroy()	
	m_valueBox = nil
end

return SizeBox
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX591CD0E4245349A59F533962F3B72F6F">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">DistanceLinesManager</string>
				<string name="ScriptGuid">{7C6CA309-9FEA-4B2B-B46D-53FF45390DB8}</string>
				<ProtectedString name="Source"><![CDATA[--[[
	The DistanceLinesManager holds references to the two distance lines. The distance lines
	are updated and turned on and off through it. The DistanceLinesManager responds to
	selection changes, and only shows the distance lines when one GUI object is selected.
--]]

local DistanceLinesManager = {}

-- Module scripts
local Axis = require(script.Parent.Enum.Axis)
local DistanceLine = require(script.Parent.DistanceLine)
local Log = require(script.Parent.Log)
local SelectionManager = require(script.Parent.SelectionManager)

-- Variables
local m_selectedObject = nil
local m_xDistanceLine = nil
local m_yDistanceLine = nil

-- Functions

-- void doDeselect(void)
local function doDeselect()
	DistanceLinesManager:setVisible(false)
	
	m_selectedObject = nil
end

-- void DistanceLinesManager:onSelectionChanged(void)
function DistanceLinesManager:onSelectionChanged()
	local filteredSelection = SelectionManager:getFilteredSelection()
	-- Only draw distance lines when one object is selected
	if #filteredSelection ~= 1 then
		doDeselect()
		return
	end
	local selectedObject = filteredSelection[1]
	local parent = selectedObject.Parent
	
	-- The parent must have absolute position, rotation and size to determine the
	-- distance from the selected object to the parent. 
	if not parent:IsA("GuiBase2d") then
		doDeselect()
		return
	end
	
	-- We can potentially draw the distance lines of the selected object
	m_selectedObject = selectedObject
	DistanceLinesManager:update()
	DistanceLinesManager:setVisible(true)
end

-- Peforms initialization when the UI Editor plugin is turned on.
--
-- void DistanceLinesManager:On(void)
function DistanceLinesManager:On()
	m_xDistanceLine = DistanceLine.new(Axis.X)
	m_yDistanceLine = DistanceLine.new(Axis.Y)
end

-- Peforms clean-up when the UI Editor plugin is turned off. 
--
-- void DistanceLinesManager:Off()
function DistanceLinesManager:Off()
	m_xDistanceLine:destroy()
	m_yDistanceLine:destroy()
	
	m_xDistanceLine = nil
	m_yDistanceLine = nil
end

-- Updates the distance lines, i.e. where they are drawn and the content of the distance labels.
--
-- void DistanceLinesManager:Off()
function DistanceLinesManager:update()
	if m_selectedObject == nil then
		return
	end
	
	m_xDistanceLine:update(m_selectedObject)
	m_yDistanceLine:update(m_selectedObject)
end

function DistanceLinesManager:setVisible(visible)
	if not m_selectedObject then
		return
	end	
	
	-- We dont support showing the distance lines when there is a rotation
 	-- because we haven't specified what the distance to the parent edge
	-- means in that case.
	local minimumRotation = 0.001	 
	local isRotated = math.abs(m_selectedObject.AbsoluteRotation) >= minimumRotation
	if visible and isRotated then
		m_xDistanceLine:setVisible(false)
		m_yDistanceLine:setVisible(false)
		return
	end
	
	m_xDistanceLine:setVisible(visible)
	m_yDistanceLine:setVisible(visible)
end

return DistanceLinesManager
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX3A105BFFF1BF4ABB9AB944B7E99A6614">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">RectUtility</string>
				<string name="ScriptGuid">{4E938C81-B706-4229-B14E-DCD8096FFB24}</string>
				<ProtectedString name="Source"><![CDATA[--[[
	The RectUtility module script contains functions for doing calculations on Rect instances.
--]]

local RectUtility = {}

-- Use pointOnSideOfLine to determine if the point is on one side or the other
-- of the line. It will return a negative number if it's one side and a positive
-- number if it's on the other side. It will finally return zero if the point
-- is on the line.
--
-- The Vector2s a and b are the start and end of the line. The Vector2 point is
-- the point that you want to determine which side it is on.
--
-- number RectUtility:pointOnSideOfLine(Vector2 a, Vector2 b, Vector2 p)
function RectUtility:pointOnSideOfLine(a, b, p)
	-- See https://math.stackexchange.com/questions/274712/calculate-on-which-side-of-a-straight-line-is-a-given-point-located
	local d = (p.X - a.X)*(b.Y - a.Y) - (p.Y - a.Y)*(b.X - a.X)
	return d
end

-- Returns true if the a point is inside or on the sides of a rectangle. 
--
-- Assumes that the Rect is axis aligned.
--
-- RectUtility:containsPoint(Rect rectangle, Vector2 point)
function RectUtility:containsPoint(rectangle, point)
	local topLeftPoint = rectangle.Min
	local topRightPoint = Vector2.new(topLeftPoint.X + rectangle.Width, topLeftPoint.Y)
	local bottomRightPoint = rectangle.Max
	local bottomLeftPoint = Vector2.new(bottomRightPoint.X - rectangle.Width, bottomRightPoint.Y)
	
	local top = RectUtility:pointOnSideOfLine(topLeftPoint, topRightPoint, point)
	local right = RectUtility:pointOnSideOfLine(topRightPoint, bottomRightPoint, point)
	local bottom = RectUtility:pointOnSideOfLine(bottomRightPoint, bottomLeftPoint, point)
	local left = RectUtility:pointOnSideOfLine(bottomLeftPoint, topLeftPoint, point)

	-- If the the point is on the right side of all the sides of the rectangle
	-- then it's inside the rectangle. Notice that the winding order matters.
	local isInside = top <= 0 and right <= 0 and bottom <= 0 and left <= 0
	
	return isInside
end

return RectUtility
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="Folder" referent="RBXC820EC84007443F3B7DD557D7675A930">
			<Properties>
				<string name="Name">Tests</string>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
			<Item class="Script" referent="RBXC96CA84A707C4DD999A897E355FCE896">
				<Properties>
					<bool name="Disabled">true</bool>
					<Content name="LinkedSource"><null></null></Content>
					<string name="Name">RectUtilityTest</string>
					<string name="ScriptGuid">{26DC7C62-63FA-4451-851C-DB3FE41D8E81}</string>
					<ProtectedString name="Source"><![CDATA[--[[
	This is a test script to test the functions in RectUtility. If you want to run
	the tests, then you need to set Disabled to true in the Properties widget. 
--]]

local Log = require(script.Parent.Parent.Log)
local RectUtility = require(script.Parent.Parent.RectUtility)

local function testPointIsInsideInMiddle()
	local rectangle = Rect.new(Vector2.new(1, 1), Vector2.new(3, 3))
	local pointMiddle = Vector2.new(2, 2)
	assert(RectUtility:containsPoint(rectangle, pointMiddle) == true, "Point was not inside rectangle")
end

local function testPointIsOnTopSide()
	local rectangle = Rect.new(Vector2.new(1, 1), Vector2.new(3, 3))
	local pointTopSide = Vector2.new(2, 1)
	assert(RectUtility:containsPoint(rectangle, pointTopSide) == true, "Point was not inside rectangle")
end

local function testPointIsOutsideAtOrigin()
	local rectangle = Rect.new(Vector2.new(1, 1), Vector2.new(3, 3))
	local pointOutsideAtOrigin = Vector2.new(0, 0)
	assert(RectUtility:containsPoint(rectangle, pointOutsideAtOrigin) == false, "Point was not outside rectangle")
end

local function testPointIsOutsideOnTop()
	local rectangle = Rect.new(Vector2.new(1, 1), Vector2.new(3, 3))
	local pointOutsideTop = Vector2.new(2, 0.5)
	assert(RectUtility:containsPoint(rectangle, pointOutsideTop) == false, "Point was not outside rectangle")
end

local function testPointIsOutsideBelow()
	local rectangle = Rect.new(Vector2.new(1, 1), Vector2.new(3, 3))
	local pointOutsideBelow = Vector2.new(2, 3.5)
	assert(RectUtility:containsPoint(rectangle, pointOutsideBelow) == false, "Point was not outside rectangle")
end

local function testPointIsOutsideLeft()
	local rectangle = Rect.new(Vector2.new(1, 1), Vector2.new(3, 3))
	local pointOutsideLeft = Vector2.new(0.5, 2)
	assert(RectUtility:containsPoint(rectangle, pointOutsideLeft) == false, "Point was not outside rectangle")
end

local function testPointIsOutsideRight()
	local rectangle = Rect.new(Vector2.new(1, 1), Vector2.new(3, 3))
	local pointOutsideRight = Vector2.new(0.5, 2)
	assert(RectUtility:containsPoint(rectangle, pointOutsideRight) == false, "Point was not outside rectangle")
end

local function rectUtilityTestSuite()
	Log:log("Running RectUtilityTest")
	
	testPointIsInsideInMiddle()
	testPointIsOnTopSide()
	
	testPointIsOutsideAtOrigin()
	testPointIsOutsideOnTop()
	testPointIsOutsideBelow()
	testPointIsOutsideLeft()
	testPointIsOutsideRight()
end

rectUtilityTestSuite()]]></ProtectedString>
					<BinaryString name="Tags"></BinaryString>
				</Properties>
			</Item>
		</Item>
		<Item class="ModuleScript" referent="RBX1106677EA6754079B6C5338AA140F457">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">DistanceLine</string>
				<string name="ScriptGuid">{94C5A240-65DC-429F-94E7-9EE180432E76}</string>
				<ProtectedString name="Source"><![CDATA[--[[
	The DistanceLine draws a line from the selected object to its parents'
	"closest" side. It also draws a text label next to the line with the
	distance. 	
	
	When the selected object is fully inside the parent, then it is trivial
	to find the closest side. When the selected object is no longer fully 
	inside the parent, then there is no clear answer to which side is the
	closest and we have to define what we mean. We currently draw a line
	from the side that's inside to the parent's far side, as below:
	
	+--------------------------+
	|                       |  |
	|                       |  |
	|                       |  |
	|               +---------------+
	|               |               |
	|               |               |
	|               |               |
	|               |               |
	|               |               |
	|---------------|               |
	|               |               |
	+----------------               |
	                |               |
	                |               |
	                +---------------+
	
	We currently do not handle the case where the mid point is outside the
	parent.
--]]

local DistanceLine = {}

-- Module scripts
local Axis = require(script.Parent.Enum.Axis)
local CoreGuiManager = require(script.Parent.CoreGuiManager)
local Log = require(script.Parent.Log)
local RectUtility = require(script.Parent.RectUtility)
local ValueBox = require(script.Parent.ValueBox)

-- Constants
local LINE_COLOR = Color3.fromRGB(255, 205, 0)
local LINE_WIDTH = 2
local LINEEND_WIDTH = 10

-- Creates a thin frame which is used to draw the distance line.
--
-- Frame createDistanceFrame()
local function createDistanceFrame(axis)
	local distanceFrame = Instance.new("Frame")
	distanceFrame.Name = "DistanceLine"
	distanceFrame.BorderSizePixel = 0
	distanceFrame.BackgroundColor3 = LINE_COLOR
	distanceFrame.Visible = false
	distanceFrame.Parent = CoreGuiManager:findOrCreateScreenGui("DistanceLines")
	
	-- This is the small end mark at the border of viewport.
	-- It's parented to distanceFrame because it needs to be updated together
	-- with distanceFrame. Parenting to distanceFrame also helps so that
	-- when distanceFrame is invisible, endFrame is invisible automatically.
	local endFrame = Instance.new("Frame")
	endFrame.Name = "DistanceEnd"
	endFrame.BorderSizePixel = 0
	endFrame.BackgroundColor3 = LINE_COLOR
	endFrame.Visible = true
	endFrame.Parent = distanceFrame
	
	local endSize = {
		UDim2.new(0, LINE_WIDTH, 0, LINEEND_WIDTH),
		UDim2.new(0, LINEEND_WIDTH, 0, LINE_WIDTH)
	}
	endFrame.Size = endSize[axis]
	
	-- The AnchorPoint and Position of end mark are always opposite to the distanceFrame
	-- Whenever AnchorPoint of distanceFrame changes, we update endFrame and move it
	-- to the other end of distance line
	distanceFrame:GetPropertyChangedSignal("AnchorPoint"):Connect(function()
		if axis == Axis.X then
			if distanceFrame.AnchorPoint.X == 0 then
				endFrame.AnchorPoint = Vector2.new(1, 0.5)
				endFrame.Position = UDim2.new(1, 0, 0.5, 0)
			else
				endFrame.AnchorPoint = Vector2.new(0, 0.5)
				endFrame.Position = UDim2.new(0, 0, 0.5, 0)
			end
		elseif axis == Axis.Y then
			if distanceFrame.AnchorPoint.Y == 0.0 then
				endFrame.AnchorPoint = Vector2.new(0.5, 1)
				endFrame.Position = UDim2.new(0.5, 0, 1, 0)
			else
				endFrame.AnchorPoint = Vector2.new(0.5, 0)
				endFrame.Position = UDim2.new(0.5, 0, 0, 0)
			end
		end
	end)
	
	return distanceFrame
end

-- Creates a distance value box in the middle of the distance line and shows the distance.
--
-- ValueBox createDistanceBox(Axis axis, Instance parent)
local function createDistanceBox(axis, parent)
	local positions = {
		UDim2.new(0.5, 0, 0, 0),
		UDim2.new(0, 0, 0.5, 0)
	}	
	
	local distanceBox = ValueBox.new(parent)
	distanceBox.Name = "DistanceBox"
 
	distanceBox:setAnchorPoint(Vector2.new(0.5, 0.5))
	distanceBox:setPosition(positions[axis])
	if parent ~= nil then
		distanceBox.Parent = parent
	end

	return distanceBox
end

-- The DistanceLine constructor. The axis must be specified, i.e. if it's drawn
-- along the x or y axis, for example Axis.X or Axis.Y.
--
-- DistanceLine DistanceLine.new(Axis axis)
function DistanceLine.new(axis)
	local newDistanceLine = {}	
	
	newDistanceLine.m_axis = axis	
	-- A frame is used for drawing the distance line. It's a thin frame.
	newDistanceLine.m_distanceFrame = createDistanceFrame(axis)
	-- The distance box displays how far away the parent's side it is. The box
	-- is parented to the line and always updated together, which is why they're
	-- in the same class for now.
	newDistanceLine.m_distanceBox = createDistanceBox(axis, newDistanceLine.m_distanceFrame)
	-- If child object is very far outside its parent then we can't show the distance line.
	newDistanceLine.m_canShow = false
	
	return setmetatable(newDistanceLine, DistanceLine)
end
DistanceLine.__index = DistanceLine

-- Destroys the distance line and its associated distance label.
--
-- void DistanceLine:destroy()
function DistanceLine:destroy()
	self.m_distanceBox:Destroy()
	self.m_distanceFrame:Destroy()
	
	self.m_distanceBox = nil
	self.m_distanceFrame = nil
end

-- Calculates the distance from the left of the object to the
-- left of the parent.
--
-- int calcLeftDistance(GuiBase2d object, GuiBase2d parent)
local function calcLeftDistance(object, parent)
	return object.AbsolutePosition.X - parent.AbsolutePosition.X
end

-- Calculates the distance from the right of the object to the
-- right of the parent.
--
-- int calcRightDistance(GuiBase2d object, GuiBase2d parent)
local function calcRightDistance(object, parent)
	local objectRightSide = object.AbsolutePosition.X + object.AbsoluteSize.X
	local parentRightSide = parent.AbsolutePosition.X + parent.AbsoluteSize.X
	return parentRightSide - objectRightSide
end

-- Calculates the distance from the top of the object to the
-- top of the parent.
--
-- int calcTopDistance(GuiBase2d object, GuiBase2d parent)
local function calcTopDistance(object, parent)
	return object.AbsolutePosition.Y - parent.AbsolutePosition.Y
end

-- Calculates the distance from the bottom of the object to the
-- bottom of the parent.
--
-- int calcBottomDistance(GuiBase2d object, GuiBase2d parent)
local function calcBottomDistance(object, parent)
	local objectBottom = object.AbsolutePosition.Y + object.AbsoluteSize.Y
	local parentBottom = parent.AbsolutePosition.Y + parent.AbsoluteSize.Y
	return parentBottom - objectBottom
end


local function updateDistanceBoxText(self, distance)
	-- The specification calls for also being able to display the distance
	-- as Offset and Scale but that will be implemented in a later story.
	self.m_distanceBox:setText(("%d"):format(distance))
end

-- Figures out how to draw the distance line on the x axis. It then draws
-- the line and updates the distance box.
--
-- void updateX(DistanceLine self, GuiBase2d selectedObject, GuiBase2d parent)
local function updateX(self, selectedObject, parent)
	local distanceFrame = self.m_distanceFrame

	-- Determine if the mid points are inside the parent. Floor center values
	-- otherwise the line will appear to jerk for objects with odd sizes.
	local parentRect = Rect.new(parent.AbsolutePosition, parent.AbsolutePosition + parent.AbsoluteSize)
	local leftMidPoint = Vector2.new(selectedObject.AbsolutePosition.X,
									  math.floor(selectedObject.AbsolutePosition.Y + selectedObject.AbsoluteSize.Y/2.0))
	local rightMidPoint = Vector2.new(selectedObject.AbsolutePosition.X + selectedObject.AbsoluteSize.X,
									   math.floor(selectedObject.AbsolutePosition.Y + selectedObject.AbsoluteSize.Y/2.0))
	local leftMidPointInside = RectUtility:containsPoint(parentRect, leftMidPoint)
	local rightMidPointInside = RectUtility:containsPoint(parentRect, rightMidPoint)
	
	-- The anchor coordinates are in the space of the frame
	local leftAnchor = Vector2.new(1.0, 0.5) -- Draw from the left side of the selected object and to the left
	local rightAnchor = Vector2.new(0.0, 0.5) -- Draw from the right side of the selected object and to the right
	
	local distance
	if leftMidPointInside and rightMidPointInside then
		-- Both mid points are inside the parent. It just needs to draw the distance
		-- to the parent side which is closer.
		local leftDistance = calcLeftDistance(selectedObject, parent)
		local rightDistance = calcRightDistance(selectedObject, parent)
		distance = math.min(leftDistance, rightDistance)
		distanceFrame.Size = UDim2.new(0, distance, 0, LINE_WIDTH)
		if leftDistance <= rightDistance then
			distanceFrame.AnchorPoint = leftAnchor
			distanceFrame.Position = UDim2.new(0, leftMidPoint.X, 0, leftMidPoint.Y)
		else
			distanceFrame.AnchorPoint = rightAnchor
			distanceFrame.Position = UDim2.new(0, rightMidPoint.X, 0, rightMidPoint.Y)
		end
	elseif leftMidPointInside then
		-- The left mid point is inside but the right is outside. The closest parent
		-- side should be the parent's left side.
		distanceFrame.AnchorPoint = leftAnchor
		distanceFrame.Position = UDim2.new(0, leftMidPoint.X, 0, leftMidPoint.Y)
		distance = calcLeftDistance(selectedObject, parent)
		distanceFrame.Size = UDim2.new(0, distance, 0, LINE_WIDTH)
	elseif rightMidPointInside then
		-- The right mid point is inside but the left is outside. The closest parent
		-- side should be the parent's right side.
		distanceFrame.AnchorPoint = rightAnchor
		distanceFrame.Position = UDim2.new(0, rightMidPoint.X, 0, rightMidPoint.Y)
		distance = calcRightDistance(selectedObject, parent)
		distanceFrame.Size = UDim2.new(0, distance, 0, LINE_WIDTH)
	else
		-- The mid points are both outside the parent. This will be handled in a later story.
		self.m_canShow = false
		return
	end

	self.m_canShow = true
	
	updateDistanceBoxText(self, distance)
end

-- Figures out how to draw the distance line on the y axis. It then draws
-- the line and updates the distance box.
--
-- void updateY(DistanceLine self, GuiBase2d selectedObject, GuiBase2d parent)
local function updateY(self, selectedObject, parent)
	local distanceFrame = self.m_distanceFrame
	
	-- Determine if the mid points are inside the parent. Floor center values
	-- otherwise the line will appear to jerk for objects with odd sizes.
	local parentRect = Rect.new(parent.AbsolutePosition, parent.AbsolutePosition + parent.AbsoluteSize)
	local topMidPoint = Vector2.new(math.floor(selectedObject.AbsolutePosition.X + selectedObject.AbsoluteSize.X/2.0),
									selectedObject.AbsolutePosition.Y)
	local bottomMidPoint = Vector2.new(math.floor(selectedObject.AbsolutePosition.X + selectedObject.AbsoluteSize.X/2.0),
									   selectedObject.AbsolutePosition.Y + selectedObject.AbsoluteSize.Y)
	local topMidPointInside = RectUtility:containsPoint(parentRect, topMidPoint)
	local bottomMidPointInside = RectUtility:containsPoint(parentRect, bottomMidPoint)
	
	-- The anchor coordinates are in the space of the frame
	local topAnchor = Vector2.new(0.5, 1.0) -- Draw from the top side of the selected object and to the top
	local bottomAnchor = Vector2.new(0.5, 0.0) -- Draw from the bottom side of the selected object and to the bottom	
	
	local distance
	if topMidPointInside and bottomMidPointInside then
		-- Both mid points are inside the parent. We just need to draw the distance
		-- to the parent side which is closer.
		local topDistance = calcTopDistance(selectedObject, parent)
		local bottomDistance = calcBottomDistance(selectedObject, parent)
		distance = math.min(topDistance, bottomDistance)
		distanceFrame.Size = UDim2.new(0, LINE_WIDTH, 0, distance)
		if topDistance <= bottomDistance then
			distanceFrame.AnchorPoint = topAnchor
			distanceFrame.Position = UDim2.new(0, topMidPoint.X, 0, topMidPoint.Y)
		else
			distanceFrame.AnchorPoint = bottomAnchor
			distanceFrame.Position = UDim2.new(0, bottomMidPoint.X, 0, bottomMidPoint.Y)
		end	
	elseif topMidPointInside then
		-- The top mid point is inside but the bottom is outside. The closest parent
		-- side should be the parent's top side.
		distanceFrame.Visible = true		
		distanceFrame.AnchorPoint = topAnchor
		distanceFrame.Position = UDim2.new(0, topMidPoint.X, 0, topMidPoint.Y)
		distance = calcTopDistance(selectedObject, parent)
		distanceFrame.Size = UDim2.new(0, LINE_WIDTH, 0, distance)
	elseif bottomMidPointInside then
		-- The bottom mid point is inside but the top is outside. The closest parent
		-- side should be the parent's bottom side.
		distanceFrame.Visible = true		
		distanceFrame.AnchorPoint = bottomAnchor
		distanceFrame.Position = UDim2.new(0, bottomMidPoint.X, 0, bottomMidPoint.Y)
		distance = calcBottomDistance(selectedObject, parent)
		distanceFrame.Size = UDim2.new(0, LINE_WIDTH, 0, distance)
	else
		-- The mid points are both outside the parent. This will be handled in a later story.
		self.m_canShow = false
		return
	end	
	
	self.m_canShow = true	
	
	-- Update y distance box
	updateDistanceBoxText(self, distance)
end

-- Updates the DistanceLine object, i.e. where it is drawn and the contents of the distance label.
--
-- void DistanceLine:update(GuiBase2d selectedObject)
function DistanceLine:update(selectedObject)
	local parent = selectedObject.Parent
	
	if self.m_axis == Axis.X then
		updateX(self, selectedObject, parent)
	elseif self.m_axis == Axis.Y then
		updateY(self, selectedObject, parent)
	else
		error("Could not update the DistanceLine. The axis must be either X or Y")
	end
end

-- Sets the visibilty of the distance line and its associated distance label (through parenting).
--
-- It only shows the distance lines if they can be shown, e.g. the child is not too
-- far outside the parent.
--
-- void DistanceLine:setVisible(bool visible)
function DistanceLine:setVisible(visible)
	if visible then
		self.m_distanceFrame.Visible = self.m_canShow
	else
		self.m_distanceFrame.Visible = false
	end
end

return DistanceLine
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX3ADDFBC897B540F2A8A0C3F98BBCA4A5">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">MouseIconManager</string>
				<string name="ScriptGuid">{389A6BD1-9BBA-44F8-AF5D-196044924711}</string>
				<ProtectedString name="Source"><![CDATA[--[[
	The MouseIconManager is used for changing the mouse cursor icon. It
	keeps the current state so it knows not to change the cursor icon
	unless it needs to be changed.
--]]
local MouseIconManager = {}

-- Modules
local Direction = require(script.Parent.Enum.Direction)

-- Constants
local MOUSE_MOVE_ICON = "rbxasset://textures/advClosed-hand.png"

-- The winding order must match m_handles in the Move module. Using Enum.Direction for 
-- both ensures it.
-- TODO: Replace placeholder icons with real assets once we get them.
local MOUSE_RESIZE_ICONS = {
	[Direction.E]  = "rbxasset://textures/StudioUIEditor/icon_resize2.png",   -- HANDLE_E
	[Direction.SE] = "rbxasset://textures/StudioUIEditor/icon_resize3.png", -- HANDLE_SE
	[Direction.S]  = "rbxasset://textures/StudioUIEditor/icon_resize4.png",     -- HANDLE_S
	[Direction.SW] = "rbxasset://textures/StudioUIEditor/icon_resize1.png",   -- HANDLE_SW
	[Direction.W]  = "rbxasset://textures/StudioUIEditor/icon_resize2.png",   -- HANDLE_W
	[Direction.NW] = "rbxasset://textures/StudioUIEditor/icon_resize3.png", -- HANDLE_NW
	[Direction.N]  = "rbxasset://textures/StudioUIEditor/icon_resize4.png",     -- HANDLE_N
	[Direction.NE] = "rbxasset://textures/StudioUIEditor/icon_resize1.png"    -- HANDLE_NE
}

local MOUSE_ROTATE_ICONS = {
	[Direction.E]  = "rbxasset://textures/StudioUIEditor/icon_rotate1.png",
	[Direction.SE] = "rbxasset://textures/StudioUIEditor/icon_rotate2.png",
	[Direction.S]  = "rbxasset://textures/StudioUIEditor/icon_rotate3.png",
	[Direction.SW] = "rbxasset://textures/StudioUIEditor/icon_rotate4.png",
	[Direction.W]  = "rbxasset://textures/StudioUIEditor/icon_rotate5.png",
	[Direction.NW] = "rbxasset://textures/StudioUIEditor/icon_rotate6.png",
	[Direction.N]  = "rbxasset://textures/StudioUIEditor/icon_rotate7.png",
	[Direction.NE] = "rbxasset://textures/StudioUIEditor/icon_rotate8.png",
}

-- Enums
local IconType = {}
IconType.DEFAULT = 0 
IconType.MOVE = 1
IconType.RESIZE = 2
IconType.ROTATE = 3

-- Variables
local m_defaultIcon = nil
local m_iconType = IconType.DEFAULT
local m_handleDirection = Direction.NOT_SET

-- Functions

-- Returns which direction the hovered handle corresponds to with
-- the object rotation. It's used to figure out which mouse cursor
-- icons to use when the object is rotated.
--
-- Direction MouseIconManager:calcMouseIconDirection(Direction handle, double absoluteRotation)
function MouseIconManager:calcMouseIconDirection(handle, absoluteRotation)	
	local handleAngle = Direction:directionToAngle(handle)	
	return Direction:angleToDirection(handleAngle + absoluteRotation)
end

-- Restores the mouse cursor icon to what it was when the plugin was turned on.
--
-- void MouseIconManager:setToDefaultIcon()
function MouseIconManager:setToDefaultIcon()
	if m_iconType ~= IconType.DEFAULT then
		m_iconType = IconType.DEFAULT
		m_mouse.Icon = m_defaultIcon
		m_handleDirection = Direction.NOT_SET
	end
end

-- Set the mouse cursor icon to the hand when you move an object.
--
-- void MouseIconManager:setToMoveIcon()
function MouseIconManager:setToMoveIcon()
	if m_iconType ~= IconType.MOVE then
		m_iconType = IconType.MOVE
		m_mouse.Icon = MOUSE_MOVE_ICON
		m_handleDirection = Direction.NOT_SET
	end
end

-- Sets the resize icon depending on the handle. There are eight handles
-- around the resizable boxes. They are labeled northwest, north, norteast,  
-- and so on. Use the enums from Enum.Direction to specify the direction.
--
-- void MouseIconManager:setToResizeIcon(Enum.Direction handleDirection)
function MouseIconManager:setToResizeIcon(handleDirection)
	assert(Direction:isValid(handleDirection), "The handle direction was not valid.")
	
	if (m_iconType == IconType.RESIZE and m_handleDirection ~= handleDirection)
		or m_iconType ~= IconType.RESIZE then
		m_iconType = IconType.RESIZE
		m_mouse.Icon = MOUSE_RESIZE_ICONS[handleDirection]
		m_handleDirection = handleDirection
	end
end

-- void MouseIconManager:setToRotateIcon(Enum.Direction handleDirection)
function MouseIconManager:setToRotateIcon(handleDirection)
	assert(Direction:isValid(handleDirection), "The handle direction was not valid.")
	
	if (m_iconType == IconType.ROTATE and m_handleDirection ~= handleDirection)
		or m_iconType ~= IconType.ROTATE then
		m_iconType = IconType.ROTATE
		m_mouse.Icon = MOUSE_ROTATE_ICONS[handleDirection]
		m_handleDirection = handleDirection
	end
end

-- Call this when turning the plugin off. It de-initializes the module.
--
-- void MouseIconManager:Off(Mouse mouse)
function MouseIconManager:Off(mouse)
	MouseIconManager:setToDefaultIcon()	
	
	m_mouse = nil
	m_defaultIcon = nil
end

-- Call this when turning the plugin on. It initializes the module.
--
-- void MouseIconManager:On(Mouse mouse)
function MouseIconManager:On(mouse)
	assert(mouse ~= nil, "Cannot initialize MouseIconManager. Got a nil mouse.")
	assert(mouse.Icon ~= nil, "Cannot initialize MouseIconManager. The mouse icon was nil")
	
	m_mouse = mouse
	m_defaultIcon = mouse.Icon
	m_iconType = IconType.DEFAULT
	m_handleDirection = Direction.NOT_SET
end

return MouseIconManager
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBXBCC35DEBBB1D4475ABA817BA66F121AE">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">ValueBox</string>
				<string name="ScriptGuid">{48540BF7-11EF-4D0C-A2B5-6EFBC3AC2D5D}</string>
				<ProtectedString name="Source"><![CDATA[--[[
	A box with rounded corners that displays a value. It's used by the SizeBox and the RotationBox.
--]]
local ValueBox = {}

-- Module scripts
local CoreGuiManager = require(script.Parent.CoreGuiManager)

-- Services
local TextService = game:GetService("TextService")

-- Constants
local IMAGE_LABEL_PADDING = Vector2.new(12, 4) -- Padding inside the m_imageLabel

-- Functions

-- Returns the current size of the ValueBox.
--
-- UDim2 ValueBox:getSize()
function ValueBox:getSize()
	return self.m_imageLabel.Size
end

-- void ValueBox:setPosition(UDim2 position)
function ValueBox:setPosition(position)
	self.m_imageLabel.Position = position
end

-- void ValueBox::setAnchorPoint(Vector2 anchorPoint)
function ValueBox:setAnchorPoint(anchorPoint)
	self.m_imageLabel.AnchorPoint = anchorPoint
end

-- Returns the painted size of the text label's text in pixels.
--
-- Vector2 calcTextSize(TextLabel textLabel) 
local function calcTextSize(textLabel)
	return TextService:GetTextSize(textLabel.Text, textLabel.TextSize, textLabel.Font, Vector2.new(0, 0))
end

-- Sets the text and updates the size of the ValueBox. 
function ValueBox:setText(text)
	self.m_textLabel.Text = text
	
	-- Update the size of the text label and image label to fit the text in the text label.
	local textSize = calcTextSize(self.m_textLabel)
	self.m_textLabel.Size = UDim2.new(0, textSize.X, 0, textSize.Y)
	local newWidth = textSize.X + 2*IMAGE_LABEL_PADDING.X
	local newHeight = textSize.Y + 2*IMAGE_LABEL_PADDING.Y
	self.m_imageLabel.Size = UDim2.new(0, newWidth, 0, newHeight)
end

-- Shows or hides the ValueBox.
--
-- void ValueBox:setVisible(bool visible)
function ValueBox:setVisible(visible)
	self.m_imageLabel.Visible = visible
	self.m_textLabel.Visible = visible
end

-- ImageLabel createImageLabel()
local function createImageLabel()
	local imageLabel = Instance.new("ImageLabel")
	imageLabel.Name = "UIEditorValueBoxImageLabel"
	-- Change display order so it shows on top of Resize adornments
	local screenGui = CoreGuiManager:findOrCreateScreenGui("ValueBoxes")
	screenGui.DisplayOrder = 1
	imageLabel.Parent = screenGui
	imageLabel.BackgroundTransparency = 1.0
	imageLabel.Image = "rbxasset://textures/StudioUIEditor/valueBoxRoundedRectangle.png"
        imageLabel.ImageColor3 = Color3.fromRGB(255, 205, 0)
	-- The m_imageLabel uses a 9-patch image to make the corners round. The Enum.ScaleType.Slice
	-- makes it slice the image into 9 parts.
	imageLabel.ScaleType = Enum.ScaleType.Slice
	 -- Image is 16x16 with border-radius 3, so the end corner is at 16-3 = 13
	imageLabel.SliceCenter = Rect.new(3, 3, 13, 13)
	
	return imageLabel
end

-- TextLabel createTextLabel()
local function createTextLabel()
	local textLabel = Instance.new("TextLabel")
	textLabel.Name = "UIEditorValueBoxTexLabel"
	textLabel.TextColor3 = Color3.new(0, 0, 0)
	textLabel.BackgroundColor3 = Color3.fromRGB(118, 118, 118)
	textLabel.BackgroundTransparency = 1.0
	textLabel.BorderSizePixel = 0
	textLabel.Font = Enum.Font.SourceSans
	textLabel.TextXAlignment = Enum.TextXAlignment.Center
	textLabel.TextYAlignment = Enum.TextYAlignment.Center
	textLabel.TextSize = 15
	-- The m_textLabel TextLabel is centered inside the ImageLabel using a Scale
	-- and an AnchorPoint. The text inside the TextLabel is not completely
	-- centered though, so we have to subtract a couple of pixels to center the text.
	local offCenterYPaddingFix = -2
	textLabel.AnchorPoint = Vector2.new(0.5, 0.5)
	textLabel.Position = UDim2.new(0.5, 0, 0.5, offCenterYPaddingFix)

	return textLabel	
end

function ValueBox.new(parent)
	local newValueBox = {}	
	
	-- The ValueBox consists of an ImageLabel and a TextLabel. The ImageLabel draws the rounded corners
	-- and the TextLabel draws the text.
	newValueBox.m_imageLabel = createImageLabel()
	if parent ~= nil then
		newValueBox.m_imageLabel.Parent = parent
	end
	newValueBox.m_textLabel = createTextLabel()
	newValueBox.m_textLabel.Parent = newValueBox.m_imageLabel
	
	return setmetatable(newValueBox, ValueBox)
end
ValueBox.__index = ValueBox

function ValueBox:Destroy()
	-- The m_textLabel is parented to the m_imageLabel and will be destroyed with it.
	self.m_imageLabel:Destroy()
end

return ValueBox
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBX7B05366D32104D8ABBD3CBD04D75DCE8">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">RotationBox</string>
				<string name="ScriptGuid">{6E982974-84B0-4C6C-A931-19590033338B}</string>
				<ProtectedString name="Source"><![CDATA[local RotationBox = {}

-- Modules
local ValueBox = require(script.Parent.ValueBox)

-- Constants
local MOUSE_POSITION_OFFSET = Vector2.new(4, 20)

-- Variables
local m_valueBox = nil

-- Functions

-- Updates where the box is shown (close to the mouse cursor), and updates
-- the rotation value in the box.
--
-- void RotationBox:update(Vector2 mousePosition, double rotation)
function RotationBox:update(mousePosition, rotation)
	local newPosition = mousePosition + MOUSE_POSITION_OFFSET
	m_valueBox:setPosition(UDim2.new(0, newPosition.X, 0, newPosition.Y))
	local newText = string.format("%d°", rotation)
	m_valueBox:setText(newText)
end

-- Shows or hides the RotationBox.
--
-- void SizeBox:setVisible(bool visible)
function RotationBox:setVisible(visible)
	m_valueBox:setVisible(visible)
end

function RotationBox:On()
	m_valueBox = ValueBox.new()
end

-- Turns the RotationBox off and performs de-initialization.
function RotationBox:Off()
	m_valueBox:Destroy()	
	m_valueBox = nil
end

return RotationBox
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
		<Item class="ModuleScript" referent="RBXBE5F65A44CF3422B97206C63D5540C78">
			<Properties>
				<Content name="LinkedSource"><null></null></Content>
				<string name="Name">ActionMediator</string>
				<string name="ScriptGuid">{68ECCB4F-CB88-48F4-A685-63B3EB6B9316}</string>
				<ProtectedString name="Source"><![CDATA[--[[
	The ActionMediator decouples the interaction between the "action modules" such as Move,
	Resize, Rotate, Rubberband and TextEditor module.
	
	The modules call the event handlers through a reference instead of 	direct inclusion. We
	avoid having to use BindableEvents and their performance issues, but still decouple the
	modules to a degree.

	The ActionMediator should be injected into the modules that need them. That way there will
	not be a direct circular dependency between the module scripts.
	
	The modules associated with the "action modules" are updated here, e.g. the 
	DistanceLinesManager, RotationBox and SizeBox. That way it's easier to see when
	they're updated and when their visibility change.
--]]

local ActionMediator = {}

-- Variables
local m_move = nil
local m_resize = nil
local m_rotate = nil
local m_rubberband = nil
local m_textEditor = nil

local m_distanceLinesManager = nil
local m_rotationBox = nil
local m_sizeBox = nil

-- void ActionMediator:onMoveBegan(Vector2 location)
function ActionMediator:onMoveBegan(location)
	m_resize:hide()
	m_sizeBox:setVisible(false)
end

-- void ActionMediator:onMoveChanged(Vector2 location)
function ActionMediator:onMoveChanged(location)
	m_rotate:update()
	m_distanceLinesManager:update()
	m_distanceLinesManager:setVisible(true)
end

-- void ActionMediator:onMoveEnded(Vector2 location)
function ActionMediator:onMoveEnded(location)
	m_resize:updatePosition()
	m_resize:show()	
	m_sizeBox:updatePosition()
	m_sizeBox:setVisible(true)
end

-- void ActionMediator:onResizeBegan(Vector2 location)
function ActionMediator:onResizeBegan(location)
end

-- void ActionMediator:onResizeChanged(Vector2 location)
function ActionMediator:onResizeChanged(location)
	m_distanceLinesManager:update()
	m_rotate:update()
	m_sizeBox:update()
end

-- void ActionMediator:onResizeEnded(Vector2 location)
function ActionMediator:onResizeEnded(location)
end

-- void ActionMediator:onRotateBegan(Vector2 location)
function ActionMediator:onRotateBegan(location)
	m_distanceLinesManager:setVisible(false)
	m_rotationBox:update(location, m_rotate:getRotation())
	m_rotationBox:setVisible(true)
	m_resize:hide()
	m_sizeBox:setVisible(false)
end

-- void ActionMediator:onRotateChanged(Vector2 location)
function ActionMediator:onRotateChanged(location)
	m_rotationBox:update(location, m_rotate:getRotation())
end

-- void ActionMediator:onRotateEnded(Vector2 location)
function ActionMediator:onRotateEnded(location)
	m_resize:updatePosition()
	m_resize:show()
	
	m_rotationBox:setVisible(false)
	m_sizeBox:setVisible(true)
	m_distanceLinesManager:update()
	m_distanceLinesManager:setVisible(true)
end

-- void ActionMediator:onRubberbandBegan(Vector2 location)
function ActionMediator:onRubberbandBegan(location)
	m_resize:hide()
	-- Don't show the sizebox and distance lines while selecting objects with
	-- the rubberband. They'll only show if you have one object. Otherwise
	-- they might flicker on and off. Show them again when done with the selection.
	m_sizeBox:setVisible(false)
	m_distanceLinesManager:setVisible(false)
end

-- void ActionMediator:onRubberbandEnded()
function ActionMediator:onRubberbandEnded()
	-- The selection changes were suppressed while the rubberband was active. The
	-- listeners need to be notified of the selection changes during the rubberband
	-- selection.
	m_distanceLinesManager:onSelectionChanged()	
	m_resize:onSelectionChanged()
	m_rotate:onSelectionChanged()
	m_sizeBox:onSelectionChanged()
end

-- void ActionMediator:onTextEditorBegan()
function ActionMediator:onTextEditorBegan()
	m_distanceLinesManager:setVisible(false)
	m_resize:hide()
	m_sizeBox:setVisible(false)
end

-- void ActionMediator:onTextEditorEnded()
function ActionMediator:onTextEditorEnded()
	m_distanceLinesManager:setVisible(true)
	m_resize:show()
	m_sizeBox:setVisible(true)
end

-- For setting the Move module
function ActionMediator:setMove(move)
	m_move = move
end

-- For setting the Rotate module
function ActionMediator:setRotate(rotate)
	m_rotate = rotate
end

-- For setting the Resize module
function ActionMediator:setResize(resize)
	m_resize = resize
end

-- For setting the Rubberband module
function ActionMediator:setRubberband(rubberband)
	m_rubberband = rubberband
end

-- For setting the TextEditor module
function ActionMediator:setTextEditor(textEditor)
	m_textEditor = textEditor
end

-- For setting the DistanceLinesManager module
function ActionMediator:setDistanceLinesManager(distanceLinesManager)
	m_distanceLinesManager = distanceLinesManager
end

-- For setting the RotationBox module
function ActionMediator:setRotationBox(rotationBox)
	m_rotationBox = rotationBox
end

-- For setting the SizeBox module
function ActionMediator:setSizeBox(sizeBox)
	m_sizeBox = sizeBox	
end

return ActionMediator
]]></ProtectedString>
				<BinaryString name="Tags"></BinaryString>
			</Properties>
		</Item>
	</Item>
</roblox>