do local function C(C)local c=C.Active C.Active=not c C.Active=c end local function c(C,c,r,O)local p=Create("\070\114\097\109\101",{Name="\065\114\114\111\119 \071\114\097\112\104\105\099",BorderSizePixel=0,Size=UDim2.new(0,C,0,C),Transparency=1})if not O then O=Instance.new("\070\114\097\109\101")O.BorderSizePixel=0 end local b if c==nil or c=="\085\112"then function b(C,c)return C,c end elseif c=="\068\111\119\110"then function b(c,r)return UDim2.new(0,c.X.Offset,0,(C-c.Y.Offset)-1),r end elseif c=="\076\101\102\116"then function b(C,c)return UDim2.new(0,C.Y.Offset,0,C.X.Offset),UDim2.new(0,c.Y.Offset,0,c.X.Offset)end elseif c=="\082\105\103\104\116"then function b(c,r)return UDim2.new(0,(C-c.Y.Offset)-1,0,c.X.Offset),UDim2.new(0,r.Y.Offset,0,r.X.Offset)end end local t if r then function t(c,r)return UDim2.new(c.X.Offset/C,0,c.Y.Offset/C,0),UDim2.new(r.X.Offset/C,0,r.Y.Offset/C,0)end else function t(C,c)return C,c end end local B=math.floor(C/4)if C%2==0 then local c=C/2-1 for C=0,c,1 do local r=O:Clone()local Y,q=t(b(UDim2.new(0,c-C,0,B+C),UDim2.new(0,(C+1)*2,0,1)))r.Position=Y r.Size=q r.Parent=p end else local c=(C-1)/2 for C=0,c,1 do local r=O:Clone()local Y,q=t(b(UDim2.new(0,c-C,0,B+C),UDim2.new(0,C*2+1,0,1)))r.Position=Y r.Size=q r.Parent=p end end if C%4>1 then local c=O:Clone()local r,Y=t(b(UDim2.new(0,0,0,(C-B)-1),UDim2.new(0,C,0,1)))c.Position=r c.Size=Y c.Parent=p end return p end local function r(C,c,r,O,p)local b=Create("\070\114\097\109\101",{Name="\071\114\105\112 \071\114\097\112\104\105\099",BorderSizePixel=0,Size=UDim2.new(0,C.x,0,C.y),Transparency=1})if not p then p=Instance.new("\070\114\097\109\101")p.BorderSizePixel=0 end r=r or 2 local t if O then function t(c)return UDim2.new(c.X.Offset/C.x,0,c.Y.Offset/C.y,0)end else function t(C)return C end end if c=="\086\101\114\116\105\099\097\108"then for c=0,C.x-1,r do local r=p:Clone()r.Size=t(UDim2.new(0,1,0,C.y))r.Position=t(UDim2.new(0,c,0,0))r.Parent=b end elseif c==nil or c=="\072\111\114\105\122\111\110\116\097\108"then for c=0,C.y-1,r do local r=p:Clone()r.Size=t(UDim2.new(0,C.x,0,1))r.Position=t(UDim2.new(0,0,0,c))r.Parent=b end end return b end local O={__index={GetScrollPercent=function(C)return C.ScrollIndex/(C.TotalSpace-C.VisibleSpace)end;CanScrollDown=function(C)return C.ScrollIndex+C.VisibleSpace<C.TotalSpace end;CanScrollUp=function(C)return C.ScrollIndex>0 end,ScrollDown=function(C)C.ScrollIndex=C.ScrollIndex+C.PageIncrement C:Update()end,ScrollUp=function(C)C.ScrollIndex=C.ScrollIndex-C.PageIncrement C:Update()end;ScrollTo=function(C,c)C.ScrollIndex=c C:Update()end,SetScrollPercent=function(C,c)C.ScrollIndex=math.floor((C.TotalSpace-C.VisibleSpace)*c+.5)C:Update()end}}O.__index.CanScrollRight=O.__index.CanScrollDown O.__index.CanScrollLeft=O.__index.CanScrollUp O.__index.ScrollLeft=O.__index.ScrollUp O.__index.ScrollRight=O.__index.ScrollDown function ScrollBar(p)local b=Create("\070\114\097\109\101",{Name="\083\099\114\111\108\108\070\114\097\109\101",Position=p and UDim2.new(0,0,1,-GUI_SIZE)or UDim2.new(1,-GUI_SIZE,0,0);Size=p and UDim2.new(1,0,0,GUI_SIZE)or UDim2.new(0,GUI_SIZE,1,0);BackgroundTransparency=1;Create("\073\109\097\103\101\066\117\116\116\111\110",{Name="\083\099\114\111\108\108\068\111\119\110",Position=p and UDim2.new(1,-GUI_SIZE,0,0)or UDim2.new(0,0,1,-GUI_SIZE);Size=UDim2.new(0,GUI_SIZE,0,GUI_SIZE);BackgroundColor3=GuiColor.Button;BorderColor3=GuiColor.Border}),Create("\073\109\097\103\101\066\117\116\116\111\110",{Name="\083\099\114\111\108\108\085\112";Size=UDim2.new(0,GUI_SIZE,0,GUI_SIZE);BackgroundColor3=GuiColor.Button;BorderColor3=GuiColor.Border}),Create("\073\109\097\103\101\066\117\116\116\111\110",{Name="\083\099\114\111\108\108\066\097\114";Size=p and UDim2.new(1,-GUI_SIZE*2,1,0)or UDim2.new(1,0,1,-GUI_SIZE*2);Position=p and UDim2.new(0,GUI_SIZE,0,0)or UDim2.new(0,0,0,GUI_SIZE);AutoButtonColor=false,BackgroundColor3=Color3.new(.94902,.94902,.94902);BorderColor3=GuiColor.Border;Create("\073\109\097\103\101\066\117\116\116\111\110",{Name="\083\099\114\111\108\108\084\104\117\109\098",AutoButtonColor=false;Size=UDim2.new(0,GUI_SIZE,0,GUI_SIZE),BackgroundColor3=GuiColor.Button,BorderColor3=GuiColor.Border})})})local t=Create("\070\114\097\109\101",{Name="\071\114\097\112\104\105\099",BorderSizePixel=0;BackgroundColor3=GuiColor.Border})local B=GUI_SIZE/2 local Y=b.ScrollDown local q=c(B,p and"\082\105\103\104\116"or"\068\111\119\110",true,t)q.Position=UDim2.new(.5,-B/2,.5,-B/2)q.Parent=Y local Z=b.ScrollUp local M=c(B,p and"\076\101\102\116"or"\085\112",true,t)M.Position=UDim2.new(.5,-B/2,.5,-B/2)M.Parent=Z local e=b.ScrollBar local J=e.ScrollThumb do local C=(GUI_SIZE*3)/8 local c=r(Vector2.new(C,C),p and"\086\101\114\116\105\099\097\108"or"\072\111\114\105\122\111\110\116\097\108",2,t)c.Position=UDim2.new(.5,-C/2,.5,-C/2)c.Parent=J end local A=setmetatable({GUI=b;ScrollIndex=0,VisibleSpace=0,TotalSpace=0,PageIncrement=1},O)local W if p then function W()J.Size=UDim2.new(A.VisibleSpace/A.TotalSpace,0,0,GUI_SIZE)if J.AbsoluteSize.x<GUI_SIZE then J.Size=UDim2.new(0,GUI_SIZE,0,GUI_SIZE)end local C=e.AbsoluteSize.x J.Position=UDim2.new((A:GetScrollPercent()*(C-J.AbsoluteSize.x))/C,0,0,0)end else function W()J.Size=UDim2.new(0,GUI_SIZE,A.VisibleSpace/A.TotalSpace,0)if J.AbsoluteSize.y<GUI_SIZE then J.Size=UDim2.new(0,GUI_SIZE,0,GUI_SIZE)end local C=e.AbsoluteSize.y J.Position=UDim2.new(0,0,(A:GetScrollPercent()*(C-J.AbsoluteSize.y))/C,0)end end local P local F local d={BackgroundColor3=GuiColor.Border;BackgroundTransparency=0}local G={BackgroundColor3=GuiColor.Border,BackgroundTransparency=.7}local function X()local C=A.TotalSpace local c=A.VisibleSpace local r=A.ScrollIndex if c<=C then if r>0 then if r+c>C then A.ScrollIndex=C-c end else A.ScrollIndex=0 end else A.ScrollIndex=0 end if A.UpdateCallback then if A.UpdateCallback(A)==false then return end end local O=A:CanScrollDown()local p=A:CanScrollUp()if O~=P then P=O Y.Active=O Y.AutoButtonColor=O local C=q:GetChildren()local c=O and d or G for r=1,#C,1 do Create(C[r],c)end end if p~=F then F=p Z.Active=p Z.AutoButtonColor=p local C=M:GetChildren()local c=p and d or G for r=1,#C,1 do Create(C[r],c)end end J.Visible=O or p W()end A.Update=X SetZIndexOnChanged(b)local E=Create("\073\109\097\103\101\066\117\116\116\111\110",{Name="\077\111\117\115\101\068\114\097\103",Position=UDim2.new(-0.25,0,-0.25,0);Size=UDim2.new(1.5,0,1.5,0),Transparency=1;AutoButtonColor=false,Active=true,ZIndex=10})local L=0 Y.MouseButton1Down:connect(function()L=tick()local c=L local r r=E.MouseButton1Up:connect(function()L=tick()E.Parent=nil C(Y)r:disconnect()drag=nil end)E.Parent=GetScreen(b)A:ScrollDown()wait(.2)while L==c do A:ScrollDown()if not A:CanScrollDown()then break end wait()end end)Y.MouseButton1Up:connect(function()L=tick()end)Z.MouseButton1Down:connect(function()L=tick()local c=L local r r=E.MouseButton1Up:connect(function()L=tick()E.Parent=nil C(Z)r:disconnect()drag=nil end)E.Parent=GetScreen(b)A:ScrollUp()wait(.2)while L==c do A:ScrollUp()if not A:CanScrollUp()then break end wait()end end)Z.MouseButton1Up:connect(function()L=tick()end)if p then e.MouseButton1Down:connect(function(c,r)L=tick()local O=L local p p=E.MouseButton1Up:connect(function()L=tick()E.Parent=nil C(Z)p:disconnect()drag=nil end)E.Parent=GetScreen(b)if c>J.AbsolutePosition.x then A:ScrollTo(A.ScrollIndex+A.VisibleSpace)wait(.2)while L==O do if c<J.AbsolutePosition.x+J.AbsoluteSize.x then break end A:ScrollTo(A.ScrollIndex+A.VisibleSpace)wait()end else A:ScrollTo(A.ScrollIndex-A.VisibleSpace)wait(.2)while L==O do if c>J.AbsolutePosition.x then break end A:ScrollTo(A.ScrollIndex-A.VisibleSpace)wait()end end end)else e.MouseButton1Down:connect(function(c,r)L=tick()local O=L local p p=E.MouseButton1Up:connect(function()L=tick()E.Parent=nil C(Z)p:disconnect()drag=nil end)E.Parent=GetScreen(b)if r>J.AbsolutePosition.y then A:ScrollTo(A.ScrollIndex+A.VisibleSpace)wait(.2)while L==O do if r<J.AbsolutePosition.y+J.AbsoluteSize.y then break end A:ScrollTo(A.ScrollIndex+A.VisibleSpace)wait()end else A:ScrollTo(A.ScrollIndex-A.VisibleSpace)wait(.2)while L==O do if r>J.AbsolutePosition.y then break end A:ScrollTo(A.ScrollIndex-A.VisibleSpace)wait()end end end)end if p then J.MouseButton1Down:connect(function(c,r)L=tick()local O=c-J.AbsolutePosition.x local p local t p=E.MouseMoved:connect(function(C,c)local r=e.AbsolutePosition.x local p=e.AbsoluteSize.x-J.AbsoluteSize.x local b=r+p C=C-O C=C<r and r or C>b and b or C C=C-r A:SetScrollPercent(C/p)end)t=E.MouseButton1Up:connect(function()L=tick()E.Parent=nil C(J)p:disconnect()p=nil t:disconnect()drag=nil end)E.Parent=GetScreen(b)end)else J.MouseButton1Down:connect(function(c,r)L=tick()local O=r-J.AbsolutePosition.y local p local t p=E.MouseMoved:connect(function(C,c)local r=e.AbsolutePosition.y local p=e.AbsoluteSize.y-J.AbsoluteSize.y local b=r+p c=c-O c=c<r and r or c>b and b or c c=c-r A:SetScrollPercent(c/p)end)t=E.MouseButton1Up:connect(function()L=tick()E.Parent=nil C(J)p:disconnect()p=nil t:disconnect()drag=nil end)E.Parent=GetScreen(b)end)end function A.Destroy(C)b:Destroy()E:Destroy()for C in pairs(A)do A[C]=nil end setmetatable(A,nil)end X()return A end end

do
	-- AutoButtonColor doesn't always reset properly
	local function ResetButtonColor(button)
		local active = button.Active
		button.Active = not active
		button.Active = active
	end

	local function ArrowGraphic(size,dir,scaled,template)
		local Frame = Create('Frame',{
			Name = "Arrow Graphic";
			BorderSizePixel = 0;
			Size = UDim2.new(0,size,0,size);
			Transparency = 1;
		})
		if not template then
			template = Instance.new("Frame")
			template.BorderSizePixel = 0
		end

		local transform
		if dir == nil or dir == 'Up' then
			function transform(p,s) return p,s end
		elseif dir == 'Down' then
			function transform(p,s) return UDim2.new(0,p.X.Offset,0,size-p.Y.Offset-1),s end
		elseif dir == 'Left' then
			function transform(p,s) return UDim2.new(0,p.Y.Offset,0,p.X.Offset),UDim2.new(0,s.Y.Offset,0,s.X.Offset) end
		elseif dir == 'Right' then
			function transform(p,s) return UDim2.new(0,size-p.Y.Offset-1,0,p.X.Offset),UDim2.new(0,s.Y.Offset,0,s.X.Offset) end
		end

		local scale
		if scaled then
			function scale(p,s) return UDim2.new(p.X.Offset/size,0,p.Y.Offset/size,0),UDim2.new(s.X.Offset/size,0,s.Y.Offset/size,0) end
		else
			function scale(p,s) return p,s end
		end

		local o = math.floor(size/4)
		if size%2 == 0 then
			local n = size/2-1
			for i = 0,n do
				local t = template:Clone()
				local p,s = scale(transform(
					UDim2.new(0,n-i,0,o+i),
					UDim2.new(0,(i+1)*2,0,1)
				))
				t.Position = p
				t.Size = s
				t.Parent = Frame
			end
		else
			local n = (size-1)/2
			for i = 0,n do
				local t = template:Clone()
				local p,s = scale(transform(
					UDim2.new(0,n-i,0,o+i),
					UDim2.new(0,i*2+1,0,1)
				))
				t.Position = p
				t.Size = s
				t.Parent = Frame
			end
		end
		if size%4 > 1 then
			local t = template:Clone()
			local p,s = scale(transform(
				UDim2.new(0,0,0,size-o-1),
				UDim2.new(0,size,0,1)
			))
			t.Position = p
			t.Size = s
			t.Parent = Frame
		end
		return Frame
	end


	local function GripGraphic(size,dir,spacing,scaled,template)
		local Frame = Create('Frame',{
			Name = "Grip Graphic";
			BorderSizePixel = 0;
			Size = UDim2.new(0,size.x,0,size.y);
			Transparency = 1;
		})
		if not template then
			template = Instance.new("Frame")
			template.BorderSizePixel = 0
		end

		spacing = spacing or 2

		local scale
		if scaled then
			function scale(p) return UDim2.new(p.X.Offset/size.x,0,p.Y.Offset/size.y,0) end
		else
			function scale(p) return p end
		end

		if dir == 'Vertical' then
			for i=0,size.x-1,spacing do
				local t = template:Clone()
				t.Size = scale(UDim2.new(0,1,0,size.y))
				t.Position = scale(UDim2.new(0,i,0,0))
				t.Parent = Frame
			end
		elseif dir == nil or dir == 'Horizontal' then
			for i=0,size.y-1,spacing do
				local t = template:Clone()
				t.Size = scale(UDim2.new(0,size.x,0,1))
				t.Position = scale(UDim2.new(0,0,0,i))
				t.Parent = Frame
			end
		end

		return Frame
	end

	local mt = {
		__index = {
			GetScrollPercent = function(self)
				return self.ScrollIndex/(self.TotalSpace-self.VisibleSpace)
			end;
			CanScrollDown = function(self)
				return self.ScrollIndex + self.VisibleSpace < self.TotalSpace
			end;
			CanScrollUp = function(self)
				return self.ScrollIndex > 0
			end;
			ScrollDown = function(self)
				self.ScrollIndex = self.ScrollIndex + self.PageIncrement
				self:Update()
			end;
			ScrollUp = function(self)
				self.ScrollIndex = self.ScrollIndex - self.PageIncrement
				self:Update()
			end;
			ScrollTo = function(self,index)
				self.ScrollIndex = index
				self:Update()
			end;
			SetScrollPercent = function(self,percent)
				self.ScrollIndex = math.floor((self.TotalSpace - self.VisibleSpace)*percent + 0.5)
				self:Update()
			end;
		};
	}
	mt.__index.CanScrollRight = mt.__index.CanScrollDown
	mt.__index.CanScrollLeft = mt.__index.CanScrollUp
	mt.__index.ScrollLeft = mt.__index.ScrollUp
	mt.__index.ScrollRight = mt.__index.ScrollDown

	function ScrollBar(horizontal)
		-- create row scroll bar
		local ScrollFrame = Create('Frame',{
			Name = "ScrollFrame";
			Position = horizontal and UDim2.new(0,0,1,-GUI_SIZE) or UDim2.new(1,-GUI_SIZE,0,0);
			Size = horizontal and UDim2.new(1,0,0,GUI_SIZE) or UDim2.new(0,GUI_SIZE,1,0);
			BackgroundTransparency = 1;
			Create('ImageButton',{
				Name = "ScrollDown";
				Position = horizontal and UDim2.new(1,-GUI_SIZE,0,0) or UDim2.new(0,0,1,-GUI_SIZE);
				Size = UDim2.new(0, GUI_SIZE, 0, GUI_SIZE);
				BackgroundColor3 = GuiColor.Button;
				BorderColor3 = GuiColor.Border;
				--BorderSizePixel = 0;
			});
			Create('ImageButton',{
				Name = "ScrollUp";
				Size = UDim2.new(0, GUI_SIZE, 0, GUI_SIZE);
				BackgroundColor3 = GuiColor.Button;
				BorderColor3 = GuiColor.Border;
				--BorderSizePixel = 0;
			});
			Create('ImageButton',{
				Name = "ScrollBar";
				Size = horizontal and UDim2.new(1,-GUI_SIZE*2,1,0) or UDim2.new(1,0,1,-GUI_SIZE*2);
				Position = horizontal and UDim2.new(0,GUI_SIZE,0,0) or UDim2.new(0,0,0,GUI_SIZE);
				AutoButtonColor = false;
				BackgroundColor3 = Color3.new(0.94902, 0.94902, 0.94902);
				BorderColor3 = GuiColor.Border;
				--BorderSizePixel = 0;
				Create('ImageButton',{
					Name = "ScrollThumb";
					AutoButtonColor = false;
					Size = UDim2.new(0, GUI_SIZE, 0, GUI_SIZE);
					BackgroundColor3 = GuiColor.Button;
					BorderColor3 = GuiColor.Border;
					--BorderSizePixel = 0;
				});
			});
		})

		local graphicTemplate = Create('Frame',{
			Name="Graphic";
			BorderSizePixel = 0;
			BackgroundColor3 = GuiColor.Border;
		})
		local graphicSize = GUI_SIZE/2

		local ScrollDownFrame = ScrollFrame.ScrollDown
			local ScrollDownGraphic = ArrowGraphic(graphicSize,horizontal and 'Right' or 'Down',true,graphicTemplate)
			ScrollDownGraphic.Position = UDim2.new(0.5,-graphicSize/2,0.5,-graphicSize/2)
			ScrollDownGraphic.Parent = ScrollDownFrame
		local ScrollUpFrame = ScrollFrame.ScrollUp
			local ScrollUpGraphic = ArrowGraphic(graphicSize,horizontal and 'Left' or 'Up',true,graphicTemplate)
			ScrollUpGraphic.Position = UDim2.new(0.5,-graphicSize/2,0.5,-graphicSize/2)
			ScrollUpGraphic.Parent = ScrollUpFrame
		local ScrollBarFrame = ScrollFrame.ScrollBar
		local ScrollThumbFrame = ScrollBarFrame.ScrollThumb
		do
			local size = GUI_SIZE*3/8
			local Decal = GripGraphic(Vector2.new(size,size),horizontal and 'Vertical' or 'Horizontal',2,graphicTemplate)
			Decal.Position = UDim2.new(0.5,-size/2,0.5,-size/2)
			Decal.Parent = ScrollThumbFrame
		end

		local Class = setmetatable({
			GUI = ScrollFrame;
			ScrollIndex = 0;
			VisibleSpace = 0;
			TotalSpace = 0;
			PageIncrement = 1;
		},mt)

		local UpdateScrollThumb
		if horizontal then
			function UpdateScrollThumb()
				ScrollThumbFrame.Size = UDim2.new(Class.VisibleSpace/Class.TotalSpace,0,0,GUI_SIZE)
				if ScrollThumbFrame.AbsoluteSize.x < GUI_SIZE then
					ScrollThumbFrame.Size = UDim2.new(0,GUI_SIZE,0,GUI_SIZE)
				end
				local barSize = ScrollBarFrame.AbsoluteSize.x
				ScrollThumbFrame.Position = UDim2.new(Class:GetScrollPercent()*(barSize - ScrollThumbFrame.AbsoluteSize.x)/barSize,0,0,0)
			end
		else
			function UpdateScrollThumb()
				ScrollThumbFrame.Size = UDim2.new(0,GUI_SIZE,Class.VisibleSpace/Class.TotalSpace,0)
				if ScrollThumbFrame.AbsoluteSize.y < GUI_SIZE then
					ScrollThumbFrame.Size = UDim2.new(0,GUI_SIZE,0,GUI_SIZE)
				end
				local barSize = ScrollBarFrame.AbsoluteSize.y
				ScrollThumbFrame.Position = UDim2.new(0,0,Class:GetScrollPercent()*(barSize - ScrollThumbFrame.AbsoluteSize.y)/barSize,0)
			end
		end

		local lastDown
		local lastUp
		local scrollStyle = {BackgroundColor3=GuiColor.Border,BackgroundTransparency=0}
		local scrollStyle_ds = {BackgroundColor3=GuiColor.Border,BackgroundTransparency=0.7}

		local function Update()
			local t = Class.TotalSpace
			local v = Class.VisibleSpace
			local s = Class.ScrollIndex
			if v <= t then
				if s > 0 then
					if s + v > t then
						Class.ScrollIndex = t - v
					end
				else
					Class.ScrollIndex = 0
				end
			else
				Class.ScrollIndex = 0
			end

			if Class.UpdateCallback then
				if Class.UpdateCallback(Class) == false then
					return
				end
			end

			local down = Class:CanScrollDown()
			local up = Class:CanScrollUp()
			if down ~= lastDown then
				lastDown = down
				ScrollDownFrame.Active = down
				ScrollDownFrame.AutoButtonColor = down
				local children = ScrollDownGraphic:GetChildren()
				local style = down and scrollStyle or scrollStyle_ds
				for i = 1,#children do
					Create(children[i],style)
				end
			end
			if up ~= lastUp then
				lastUp = up
				ScrollUpFrame.Active = up
				ScrollUpFrame.AutoButtonColor = up
				local children = ScrollUpGraphic:GetChildren()
				local style = up and scrollStyle or scrollStyle_ds
				for i = 1,#children do
					Create(children[i],style)
				end
			end
			ScrollThumbFrame.Visible = down or up
			UpdateScrollThumb()
		end
		Class.Update = Update

		SetZIndexOnChanged(ScrollFrame)

		local MouseDrag = Create('ImageButton',{
			Name = "MouseDrag";
			Position = UDim2.new(-0.25,0,-0.25,0);
			Size = UDim2.new(1.5,0,1.5,0);
			Transparency = 1;
			AutoButtonColor = false;
			Active = true;
			ZIndex = 10;
		})

		local scrollEventID = 0
		ScrollDownFrame.MouseButton1Down:connect(function()
			scrollEventID = tick()
			local current = scrollEventID
			local up_con
			up_con = MouseDrag.MouseButton1Up:connect(function()
				scrollEventID = tick()
				MouseDrag.Parent = nil
				ResetButtonColor(ScrollDownFrame)
				up_con:disconnect(); drag = nil
			end)
			MouseDrag.Parent = GetScreen(ScrollFrame)
			Class:ScrollDown()
			wait(0.2) -- delay before auto scroll
			while scrollEventID == current do
				Class:ScrollDown()
				if not Class:CanScrollDown() then break end
				wait()
			end
		end)

		ScrollDownFrame.MouseButton1Up:connect(function()
			scrollEventID = tick()
		end)

		ScrollUpFrame.MouseButton1Down:connect(function()
			scrollEventID = tick()
			local current = scrollEventID
			local up_con
			up_con = MouseDrag.MouseButton1Up:connect(function()
				scrollEventID = tick()
				MouseDrag.Parent = nil
				ResetButtonColor(ScrollUpFrame)
				up_con:disconnect(); drag = nil
			end)
			MouseDrag.Parent = GetScreen(ScrollFrame)
			Class:ScrollUp()
			wait(0.2)
			while scrollEventID == current do
				Class:ScrollUp()
				if not Class:CanScrollUp() then break end
				wait()
			end
		end)

		ScrollUpFrame.MouseButton1Up:connect(function()
			scrollEventID = tick()
		end)

		if horizontal then
			ScrollBarFrame.MouseButton1Down:connect(function(x,y)
				scrollEventID = tick()
				local current = scrollEventID
				local up_con
				up_con = MouseDrag.MouseButton1Up:connect(function()
					scrollEventID = tick()
					MouseDrag.Parent = nil
					ResetButtonColor(ScrollUpFrame)
					up_con:disconnect(); drag = nil
				end)
				MouseDrag.Parent = GetScreen(ScrollFrame)
				if x > ScrollThumbFrame.AbsolutePosition.x then
					Class:ScrollTo(Class.ScrollIndex + Class.VisibleSpace)
					wait(0.2)
					while scrollEventID == current do
						if x < ScrollThumbFrame.AbsolutePosition.x + ScrollThumbFrame.AbsoluteSize.x then break end
						Class:ScrollTo(Class.ScrollIndex + Class.VisibleSpace)
						wait()
					end
				else
					Class:ScrollTo(Class.ScrollIndex - Class.VisibleSpace)
					wait(0.2)
					while scrollEventID == current do
						if x > ScrollThumbFrame.AbsolutePosition.x then break end
						Class:ScrollTo(Class.ScrollIndex - Class.VisibleSpace)
						wait()
					end
				end
			end)
		else
			ScrollBarFrame.MouseButton1Down:connect(function(x,y)
				scrollEventID = tick()
				local current = scrollEventID
				local up_con
				up_con = MouseDrag.MouseButton1Up:connect(function()
					scrollEventID = tick()
					MouseDrag.Parent = nil
					ResetButtonColor(ScrollUpFrame)
					up_con:disconnect(); drag = nil
				end)
				MouseDrag.Parent = GetScreen(ScrollFrame)
				if y > ScrollThumbFrame.AbsolutePosition.y then
					Class:ScrollTo(Class.ScrollIndex + Class.VisibleSpace)
					wait(0.2)
					while scrollEventID == current do
						if y < ScrollThumbFrame.AbsolutePosition.y + ScrollThumbFrame.AbsoluteSize.y then break end
						Class:ScrollTo(Class.ScrollIndex + Class.VisibleSpace)
						wait()
					end
				else
					Class:ScrollTo(Class.ScrollIndex - Class.VisibleSpace)
					wait(0.2)
					while scrollEventID == current do
						if y > ScrollThumbFrame.AbsolutePosition.y then break end
						Class:ScrollTo(Class.ScrollIndex - Class.VisibleSpace)
						wait()
					end
				end
			end)
		end

		if horizontal then
			ScrollThumbFrame.MouseButton1Down:connect(function(x,y)
				scrollEventID = tick()
				local mouse_offset = x - ScrollThumbFrame.AbsolutePosition.x
				local drag_con
				local up_con
				drag_con = MouseDrag.MouseMoved:connect(function(x,y)
					local bar_abs_pos = ScrollBarFrame.AbsolutePosition.x
					local bar_drag = ScrollBarFrame.AbsoluteSize.x - ScrollThumbFrame.AbsoluteSize.x
					local bar_abs_one = bar_abs_pos + bar_drag
					x = x - mouse_offset
					x = x < bar_abs_pos and bar_abs_pos or x > bar_abs_one and bar_abs_one or x
					x = x - bar_abs_pos
					Class:SetScrollPercent(x/(bar_drag))
				end)
				up_con = MouseDrag.MouseButton1Up:connect(function()
					scrollEventID = tick()
					MouseDrag.Parent = nil
					ResetButtonColor(ScrollThumbFrame)
					drag_con:disconnect(); drag_con = nil
					up_con:disconnect(); drag = nil
				end)
				MouseDrag.Parent = GetScreen(ScrollFrame)
			end)
		else
			ScrollThumbFrame.MouseButton1Down:connect(function(x,y)
				scrollEventID = tick()
				local mouse_offset = y - ScrollThumbFrame.AbsolutePosition.y
				local drag_con
				local up_con
				drag_con = MouseDrag.MouseMoved:connect(function(x,y)
					local bar_abs_pos = ScrollBarFrame.AbsolutePosition.y
					local bar_drag = ScrollBarFrame.AbsoluteSize.y - ScrollThumbFrame.AbsoluteSize.y
					local bar_abs_one = bar_abs_pos + bar_drag
					y = y - mouse_offset
					y = y < bar_abs_pos and bar_abs_pos or y > bar_abs_one and bar_abs_one or y
					y = y - bar_abs_pos
					Class:SetScrollPercent(y/(bar_drag))
				end)
				up_con = MouseDrag.MouseButton1Up:connect(function()
					scrollEventID = tick()
					MouseDrag.Parent = nil
					ResetButtonColor(ScrollThumbFrame)
					drag_con:disconnect(); drag_con = nil
					up_con:disconnect(); drag = nil
				end)
				MouseDrag.Parent = GetScreen(ScrollFrame)
			end)
		end

		function Class:Destroy()
			ScrollFrame:Destroy()
			MouseDrag:Destroy()
			for k in pairs(Class) do
				Class[k] = nil
			end
			setmetatable(Class,nil)
		end

		Update()

		return Class
	end
end
