do local function G(G)local v=G.Active G.Active=not v G.Active=v end local function v(G,v,S,d)local u=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,G,0,G);Transparency=1})if not d then d=Instance_new("\070\114\097\109\101")d.BorderSizePixel=0 end local t if v==nil or v=="\085\112"then function t(G,v)return G,v end elseif v=="\068\111\119\110"then function t(v,S)return UDim2_new(0,v.X.Offset,0,(G-v.Y.Offset)-1),S end elseif v=="\076\101\102\116"then function t(G,v)return UDim2_new(0,G.Y.Offset,0,G.X.Offset),UDim2_new(0,v.Y.Offset,0,v.X.Offset)end elseif v=="\082\105\103\104\116"then function t(v,S)return UDim2_new(0,(G-v.Y.Offset)-1,0,v.X.Offset),UDim2_new(0,S.Y.Offset,0,S.X.Offset)end end local l if S then function l(v,S)return UDim2_new(v.X.Offset/G,0,v.Y.Offset/G,0),UDim2_new(S.X.Offset/G,0,S.Y.Offset/G,0)end else function l(G,v)return G,v end end local g=math.floor(G/4)if G%2==0 then local v=G/2-1 for G=0,v,1 do local S=d:Clone()local h,W=l(t(UDim2_new(0,v-G,0,g+G),UDim2_new(0,(G+1)*2,0,1)))S.Position=h S.Size=W S.Parent=u end else local v=(G-1)/2 for G=0,v,1 do local S=d:Clone()local h,W=l(t(UDim2_new(0,v-G,0,g+G),UDim2_new(0,G*2+1,0,1)))S.Position=h S.Size=W S.Parent=u end end if G%4>1 then local v=d:Clone()local S,h=l(t(UDim2_new(0,0,0,(G-g)-1),UDim2_new(0,G,0,1)))v.Position=S v.Size=h v.Parent=u end return u end local function S(G,v,S,d,u)local t=Create("\070\114\097\109\101",{Name="\071\114\105\112 \071\114\097\112\104\105\099",BorderSizePixel=0;Size=UDim2_new(0,G.x,0,G.y);Transparency=1})if not u then u=Instance_new("\070\114\097\109\101")u.BorderSizePixel=0 end S=S or 2 local l if d then function l(v)return UDim2_new(v.X.Offset/G.x,0,v.Y.Offset/G.y,0)end else function l(G)return G end end if v=="\086\101\114\116\105\099\097\108"then for v=0,G.x-1,S do local S=u:Clone()S.Size=l(UDim2_new(0,1,0,G.y))S.Position=l(UDim2_new(0,v,0,0))S.Parent=t end elseif v==nil or v=="\072\111\114\105\122\111\110\116\097\108"then for v=0,G.y-1,S do local S=u:Clone()S.Size=l(UDim2_new(0,G.x,0,1))S.Position=l(UDim2_new(0,0,0,v))S.Parent=t end end return t end local d={__index={GetScrollPercent=function(G)return G.ScrollIndex/(G.TotalSpace-G.VisibleSpace)end,CanScrollDown=function(G)return G.ScrollIndex+G.VisibleSpace<G.TotalSpace end;CanScrollUp=function(G)return G.ScrollIndex>0 end;ScrollDown=function(G)G.ScrollIndex=G.ScrollIndex+G.PageIncrement G:Update()end;ScrollUp=function(G)G.ScrollIndex=G.ScrollIndex-G.PageIncrement G:Update()end,ScrollTo=function(G,v)G.ScrollIndex=v G:Update()end,SetScrollPercent=function(G,v)G.ScrollIndex=math.floor((G.TotalSpace-G.VisibleSpace)*v+.5)G:Update()end}}d.__index.CanScrollRight=d.__index.CanScrollDown d.__index.CanScrollLeft=d.__index.CanScrollUp d.__index.ScrollLeft=d.__index.ScrollUp d.__index.ScrollRight=d.__index.ScrollDown function ScrollBar(d)local u=Create("\070\114\097\109\101",{Name="\083\099\114\111\108\108\070\114\097\109\101",BorderSizePixel=0,Position=d and UDim2_new(0,0,1,-GUI_SIZE)or UDim2_new(1,-GUI_SIZE,0,0);Size=d 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=d 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=d and UDim2_new(1,-GUI_SIZE*2,1,0)or UDim2_new(1,0,1,-GUI_SIZE*2);Position=d and UDim2_new(0,GUI_SIZE,0,0)or UDim2_new(0,0,0,GUI_SIZE);AutoButtonColor=false;BackgroundColor3=Color3_new(.25,.25,.25),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 l=GUI_SIZE/2 local g=u.ScrollDown local h=v(l,d and"\082\105\103\104\116"or"\068\111\119\110",true,t)h.Position=UDim2_new(.5,-l/2,.5,-l/2)h.Parent=g local W=u.ScrollUp local c=v(l,d and"\076\101\102\116"or"\085\112",true,t)c.Position=UDim2_new(.5,-l/2,.5,-l/2)c.Parent=W local s=u.ScrollBar local L=s.ScrollThumb do local G=(GUI_SIZE*3)/8 local v=S(Vector2_new(G,G),d and"\086\101\114\116\105\099\097\108"or"\072\111\114\105\122\111\110\116\097\108",2,t)v.Position=UDim2_new(.5,-G/2,.5,-G/2)v.Parent=L end local X=setmetatable({GUI=u;ScrollIndex=0;VisibleSpace=0,TotalSpace=0,PageIncrement=1},{__index={GetScrollPercent=function(G)return G.ScrollIndex/(G.TotalSpace-G.VisibleSpace)end;CanScrollDown=function(G)return G.ScrollIndex+G.VisibleSpace<G.TotalSpace end;CanScrollUp=function(G)return G.ScrollIndex>0 end;CanScrollRight=function(G)return G.ScrollIndex+G.VisibleSpace<G.TotalSpace end,CanScrollLeft=function(G)return G.ScrollIndex>0 end,ScrollDown=function(G)G.ScrollIndex+=G.PageIncrement G:Update()end;ScrollUp=function(G)G.ScrollIndex-=G.PageIncrement G:Update()end,ScrollRight=function(G)G.ScrollIndex+=G.PageIncrement G:Update()end,ScrollLeft=function(G)G.ScrollIndex-=G.PageIncrement G:Update()end;ScrollTo=function(G,v)G.ScrollIndex=v G:Update()end;SetScrollPercent=function(G,v)G.ScrollIndex=math_floor((G.TotalSpace-G.VisibleSpace)*v+.5)G:Update()end}})local b if d then function b()L.Size=UDim2_new(X.VisibleSpace/X.TotalSpace,0,0,GUI_SIZE)if L.AbsoluteSize.X<GUI_SIZE then L.Size=UDim2_new(0,GUI_SIZE,0,GUI_SIZE)end local G=s.AbsoluteSize.X L.Position=UDim2_new((X:GetScrollPercent()*(G-L.AbsoluteSize.X))/G,0,0,0)end else function b()L.Size=UDim2_new(0,GUI_SIZE,X.VisibleSpace/X.TotalSpace,0)if L.AbsoluteSize.Y<GUI_SIZE then L.Size=UDim2_new(0,GUI_SIZE,0,GUI_SIZE)end local G=s.AbsoluteSize.Y L.Position=UDim2_new(0,0,(X:GetScrollPercent()*(G-L.AbsoluteSize.Y))/G,0)end end local E,Q local R={BackgroundColor3=Color3_new(1,1,1),BackgroundTransparency=0}local V={BackgroundColor3=Color3_new(1,1,1);BackgroundTransparency=.7}local function D()local G,v,S=X.TotalSpace,X.VisibleSpace,X.ScrollIndex if v<=G then if S>0 then if S+v>G then X.ScrollIndex=G-v end else X.ScrollIndex=0 end else X.ScrollIndex=0 end if X.UpdateCallback then if X.UpdateCallback(X)==false then return end end local d=X:CanScrollDown()local u=X:CanScrollUp()if d~=E then E=d g.Active=d g.AutoButtonColor=d local G=GetChildren(h)local v=d and R or V for S=1,#G,1 do Create(G[S],v)end end if u~=Q then Q=u W.Active=u W.AutoButtonColor=u local G=GetChildren(c)local v=u and R or V for S=1,#G,1 do Create(G[S],v)end end L.Visible=d or u b()end X.Update=D SetZIndexOnChanged(u)local I=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 q=0 Connect(g.MouseButton1Down,function()q=tick()local v=q local S S=Connect(I.MouseButton1Up,function()q=tick()I.Parent=nil G(g)Disconnect(S)drag=nil end)I.Parent=GetScreen(u)X:ScrollDown()wait(.2)while q==v do X:ScrollDown()if not X:CanScrollDown()then break end wait()end end)Connect(g.MouseButton1Up,function()q=tick()end)Connect(W.MouseButton1Down,function()q=tick()local v=q local S S=Connect(I.MouseButton1Up,function()q=tick()I.Parent=nil G(W)Disconnect(S)drag=nil end)I.Parent=GetScreen(u)X:ScrollUp()wait(.2)while q==v do X:ScrollUp()if not X:CanScrollUp()then break end wait()end end)Connect(W.MouseButton1Up,function()q=tick()end)if d then Connect(s.MouseButton1Down,function(v,S)q=tick()local d=q local t t=Connect(I.MouseButton1Up,function()q=tick()I.Parent=nil G(W)Disconnect(t)drag=nil end)I.Parent=GetScreen(u)if v>L.AbsolutePosition.X then X:ScrollTo(X.ScrollIndex+X.VisibleSpace)wait(.2)while q==d do if v<L.AbsolutePosition.X+L.AbsoluteSize.X then break end X:ScrollTo(X.ScrollIndex+X.VisibleSpace)wait()end else X:ScrollTo(X.ScrollIndex-X.VisibleSpace)wait(.2)while q==d do if v>L.AbsolutePosition.X then break end X:ScrollTo(X.ScrollIndex-X.VisibleSpace)wait()end end end)else Connect(s.MouseButton1Down,function(v,S)q=tick()local d=q local t t=Connect(I.MouseButton1Up,function()q=tick()I.Parent=nil G(W)Disconnect(t)drag=nil end)I.Parent=GetScreen(u)if S>L.AbsolutePosition.Y then X:ScrollTo(X.ScrollIndex+X.VisibleSpace)wait(.2)while q==d do if S<L.AbsolutePosition.Y+L.AbsoluteSize.Y then break end X:ScrollTo(X.ScrollIndex+X.VisibleSpace)wait()end else X:ScrollTo(X.ScrollIndex-X.VisibleSpace)wait(.2)while q==d do if S>L.AbsolutePosition.Y then break end X:ScrollTo(X.ScrollIndex-X.VisibleSpace)wait()end end end)end if d then Connect(L.MouseButton1Down,function(v,S)q=tick()local d=v-L.AbsolutePosition.X local t local l t=Connect(I.MouseMoved,function(G,v)local S=s.AbsolutePosition.X local u=s.AbsoluteSize.X-L.AbsoluteSize.X local t=S+u G-=d G=G<S and S or G>t and t or G G-=S X:SetScrollPercent(G/u)end)l=Connect(I.MouseButton1Up,function()q=tick()I.Parent=nil G(L)Disconnect(t)t=nil Disconnect(l)drag=nil end)I.Parent=GetScreen(u)end)else Connect(L.MouseButton1Down,function(v,S)q=tick()local d=S-L.AbsolutePosition.Y local t,l t=Connect(I.MouseMoved,function(G,v)local S=s.AbsolutePosition.Y local u=s.AbsoluteSize.Y-L.AbsoluteSize.Y local t=S+u v-=d v=v<S and S or v>t and t or v v-=S X:SetScrollPercent(v/u)end)l=Connect(I.MouseButton1Up,function()q=tick()I.Parent=nil G(L)Disconnect(t)t=nil Disconnect(l)drag=nil end)I.Parent=GetScreen(u)end)end function X.Destroy(G)Destroy(u)Destroy(I)for G in next,X do X[G]=nil end setmetatable(X,nil)end D()return X 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)
		local ScrollFrame = Create('Frame',{
			Name = "ScrollFrame",
			BorderSizePixel = 0,
			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
			}),
			Create('ImageButton',{
				Name = "ScrollUp",
				Size = UDim2_new(0, GUI_SIZE, 0, GUI_SIZE),
				BackgroundColor3 = GuiColor.Button,
				BorderColor3 = GuiColor.Border
			}),
			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(1/4, 1/4, 1/4),
				BorderColor3 = GuiColor.Border,
				Create('ImageButton',{
					Name = "ScrollThumb",
					AutoButtonColor = false,
					Size = UDim2_new(0, GUI_SIZE, 0, GUI_SIZE),
					BackgroundColor3 = GuiColor.Button,
					BorderColor3 = GuiColor.Border
				})
			})
		})

		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(.5,-graphicSize/2,.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(.5,-graphicSize/2,.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(.5,-size/2,.5,-size/2)
			Decal.Parent = ScrollThumbFrame
		end

		local Class = setmetatable({
			GUI = ScrollFrame,
			ScrollIndex = 0,
			VisibleSpace = 0,
			TotalSpace = 0,
			PageIncrement = 1
		},{
			__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,
				CanScrollRight = function(self)
					return self.ScrollIndex + self.VisibleSpace < self.TotalSpace
				end,
				CanScrollLeft = function(self)
					return self.ScrollIndex > 0
				end,
				ScrollDown = function(self)
					self.ScrollIndex += self.PageIncrement
					self:Update()
				end,
				ScrollUp = function(self)
					self.ScrollIndex -= self.PageIncrement
					self:Update()
				end,
				ScrollRight = function(self)
					self.ScrollIndex += self.PageIncrement
					self:Update()
				end,
				ScrollLeft = function(self)
					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 + .5)
					self:Update()
				end
			}
		})

		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, lastUp
		local scrollStyle = {BackgroundColor3=Color3_new(1, 1, 1),BackgroundTransparency=0}
		local scrollStyle_ds = {BackgroundColor3=Color3_new(1, 1, 1),BackgroundTransparency=.7}

		local function Update()
			local t, v, s = Class.TotalSpace, Class.VisibleSpace, 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 = GetChildren(ScrollDownGraphic)
				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 = GetChildren(ScrollUpGraphic)
				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(-.25,0,-.25,0),
			Size = UDim2_new(1.5,0,1.5,0),
			Transparency = 1,
			AutoButtonColor = false,
			Active = true,
			ZIndex = 10
		})

		local scrollEventID = 0
		Connect(ScrollDownFrame.MouseButton1Down, function()
			scrollEventID = tick()
			local current = scrollEventID
			local up_con
			up_con = Connect(MouseDrag.MouseButton1Up, function()
				scrollEventID = tick()
				MouseDrag.Parent = nil
				ResetButtonColor(ScrollDownFrame)
				Disconnect(up_con)
				drag = nil
			end)
			MouseDrag.Parent = GetScreen(ScrollFrame)
			Class:ScrollDown()
			wait(.2)
			while scrollEventID == current do
				Class:ScrollDown()
				if not Class:CanScrollDown() then break end
				wait()
			end
		end)

		Connect(ScrollDownFrame.MouseButton1Up, function()
			scrollEventID = tick()
		end)

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

		Connect(ScrollUpFrame.MouseButton1Up, function()
			scrollEventID = tick()
		end)

		if horizontal then
			Connect(ScrollBarFrame.MouseButton1Down, function(x,y)
				scrollEventID = tick()
				local current = scrollEventID
				local up_con
				up_con = Connect(MouseDrag.MouseButton1Up, function()
					scrollEventID = tick()
					MouseDrag.Parent = nil
					ResetButtonColor(ScrollUpFrame)
					Disconnect(up_con)
					drag = nil
				end)
				MouseDrag.Parent = GetScreen(ScrollFrame)
				if x > ScrollThumbFrame.AbsolutePosition.X then
					Class:ScrollTo(Class.ScrollIndex + Class.VisibleSpace)
					wait(.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(.2)
					while scrollEventID == current do
						if x > ScrollThumbFrame.AbsolutePosition.X then break end
						Class:ScrollTo(Class.ScrollIndex - Class.VisibleSpace)
						wait()
					end
				end
			end)
		else
			Connect(ScrollBarFrame.MouseButton1Down, function(x,y)
				scrollEventID = tick()
				local current = scrollEventID
				local up_con
				up_con = Connect(MouseDrag.MouseButton1Up, function()
					scrollEventID = tick()
					MouseDrag.Parent = nil
					ResetButtonColor(ScrollUpFrame)
					Disconnect(up_con)
					drag = nil
				end)
				MouseDrag.Parent = GetScreen(ScrollFrame)
				if y > ScrollThumbFrame.AbsolutePosition.Y then
					Class:ScrollTo(Class.ScrollIndex + Class.VisibleSpace)
					wait(.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(.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
			Connect(ScrollThumbFrame.MouseButton1Down, function(x,y)
				scrollEventID = tick()
				local mouse_offset = x - ScrollThumbFrame.AbsolutePosition.X
				local drag_con
				local up_con
				drag_con = Connect(MouseDrag.MouseMoved, 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 -= mouse_offset
					x = x < bar_abs_pos and bar_abs_pos or x > bar_abs_one and bar_abs_one or x
					x -= bar_abs_pos
					Class:SetScrollPercent(x/(bar_drag))
				end)
				up_con = Connect(MouseDrag.MouseButton1Up, function()
					scrollEventID = tick()
					MouseDrag.Parent = nil
					ResetButtonColor(ScrollThumbFrame)
					Disconnect(drag_con)
					drag_con = nil
					Disconnect(up_con)
					drag = nil
				end)
				MouseDrag.Parent = GetScreen(ScrollFrame)
			end)
		else
			Connect(ScrollThumbFrame.MouseButton1Down, function(x,y)
				scrollEventID = tick()
				local mouse_offset = y - ScrollThumbFrame.AbsolutePosition.Y
				local drag_con, up_con
				drag_con = Connect(MouseDrag.MouseMoved, 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 -= mouse_offset
					y = y < bar_abs_pos and bar_abs_pos or y > bar_abs_one and bar_abs_one or y
					y -= bar_abs_pos
					Class:SetScrollPercent(y/(bar_drag))
				end)
				up_con = Connect(MouseDrag.MouseButton1Up, function()
					scrollEventID = tick()
					MouseDrag.Parent = nil
					ResetButtonColor(ScrollThumbFrame)
					Disconnect(drag_con)
					drag_con = nil
					Disconnect(up_con)
					drag = nil
				end)
				MouseDrag.Parent = GetScreen(ScrollFrame)
			end)
		end

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