Love2d support is updated to 11.1

May be bugs in supporting libraries, but the multitasking library is fully updated.

The guimanager may have a bug or 2, but I haven't found any ground breaking bugs that haven't been fixed
This commit is contained in:
Ryan Ward 2018-06-08 22:14:21 -04:00
parent a07fe49880
commit 89b4901e06
33 changed files with 515 additions and 470 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
# multi Version: 1.10.0 (Changelog has its own dedicated file now, also bug fixes and a new object)
# multi Version: 1.11.0 (Show me the love, love2d 11.1 support is here see changelog for details. Plus a new threaded object for testing!)
**NOTE: I have been studying a lot about threading for the past few months and have some awesome additions in store! They will take a while to come out though. The goal of the library is still to provide a simple and efficient way to multi task in lua**

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,36 @@
Changes
-------
Update: 1.11.0
--------------
Added:
- SystemThreadedConsole(name) -- Allsow each thread to print without the sync issues that make prints merge and hard to read.
```lua
-- MainThread:
console = multi:newSystemThreadedConsole("console"):init()
-- Thread:
console = THREAD.waitFor("console"):init()
-- using the console
console:print(...)
console:write(...) -- kinda useless for formatting code though. other threads can eaisly mess this up.
```
Fixed/Updated:
- Love2d 11.1 support is now here! Will now require these lines in your main.lua file
```lua
function love.update(dt)
multi:uManager(dt) -- runs the main loop of the multitasking library
end
function love.draw()
multi.dManager() -- If using my guimanager, if not omit this
end
```
Update: 1.10.0
-------------
--------------
**Note:** The library is now considered to be stable!
**Upcoming:** Network parallelism is on the way. It is in the works and should be released soon

5
commit notes.txt Normal file
View File

@ -0,0 +1,5 @@
MAIN: Love2d support is updated to 11.1
May be bugs in supporting libraries, but the multitasking library is fully updated.
The GuiManager may have a bug or 2, but I haven't found any ground breaking bugs that haven't been fixed

View File

@ -1,5 +1,19 @@
local function HSL(h, s, l, a)
if s<=0 then return l,l,l,a end
h, s, l = h/256*6, s/255, l/255
local c = (1-math.abs(2*l-1))*s
local x = (1-math.abs(h%2-1))*c
local m,r,b,g = (l-.5*c), 0,0,0
if h < 1 then r,b,g = c,x,0
elseif h < 2 then r,b,g = x,c,0
elseif h < 3 then r,b,g = 0,c,x
elseif h < 4 then r,b,g = 0,x,c
elseif h < 5 then r,b,g = x,0,c
else r,b,g = c,0,x
end return (r+m)*255,(g+m)*255,(b+m)*255,a
end
Color={
new=function(r,g,b)
new=function(r,b,g)
mt = {
__add = function (c1,c2)
return Color.new(c1[1]+c2[1],c1[2]+c2[2],c1[2]+c2[2])
@ -29,7 +43,7 @@ new=function(r,g,b)
__lt = Color.LT,
__le = Color.LE,
}
local temp = {r,g,b,255}
local temp = {r/255,b/255,g/255,1}
setmetatable(temp, mt)
return temp
end,
@ -57,14 +71,13 @@ Darken=function(color,v)
currentR=color[1]
currentG=color[2]
currentB=color[3]
return Color.new(currentR * (1 - v),currentG * (1 - v),currentB * (1 - v))
return Color.new((currentR*255) * (1 - v),(currentG*255) * (1 - v),(currentB*255) * (1 - v))
end,
Lighten=function(color,v)
currentR=color[1]
currentG=color[2]
currentB=color[3]
return Color.new(currentR + (255 - currentR) * v,currentG + (255 - currentG) * v,currentB + (255 - currentB) * v)
return Color.new(currentR*255 + (255 - (currentR*255)) * v,currentG*255 + (255 - (currentG*255)) * v,currentB*255 + (255 - (currentB*255)) * v)
end
}
Color.IndexColor("Black",20,20,20)

View File

@ -24,15 +24,15 @@ function gui:newBase(tp,name, x, y, w, h, sx ,sy ,sw ,sh)
else
c.Parent=self
end
c.segments=nil
c.ry=nil
c.rx=nil
c.DPI=1
if _GuiPro.DPI_ENABLED then
c.DPI=love.window.getPixelScale()
x, y, w, h=c.DPI*x,c.DPI*y,c.DPI*w,c.DPI*h
end
c.centerFontY=true
c.segments=nil
c.ry=nil
c.rx=nil
c.DPI=1
if _GuiPro.DPI_ENABLED then
c.DPI=love.window.getPixelScale()
x, y, w, h=c.DPI*x,c.DPI*y,c.DPI*w,c.DPI*h
end
c.centerFontY=true
c.FormFactor="rectangle"
c.Type=tp
c.Active=true
@ -42,7 +42,6 @@ function gui:newBase(tp,name, x, y, w, h, sx ,sy ,sw ,sh)
c:SetName(name)
c.BorderSize=1
c.BorderColor={0,0,0}
c.BorderVisibility=1
c.VIS=true
c.Visible=true
c.oV=true
@ -178,6 +177,13 @@ function gui:newBase(tp,name, x, y, w, h, sx ,sy ,sw ,sh)
_GuiPro.self=self
if type(i)=="number" then
loadstring("_GuiPro.self:"..v)()
elseif i:match"__self__" then
local ind=i:match"__self__(.+)"
if not self[ind] then self[ind]={} end
loadstring("_GuiPro.self."..ind.."=_GuiPro.self:"..v)()
elseif i:match"__child__" then
local ind,child = i:match"__child__(%S-)_(.+)"
self[ind][child]=v
else
self[i]=v
end

View File

@ -0,0 +1,40 @@
function gui:toString() -- oh boy this is gonna be painful lol
multi:newThread("saving data: ",function()
local dat=bin.stream("test.dat",false)
function GetAllChildren2(Object)
local Stuff = {}
function Seek(Items)
for i=1,#Items do
--table.insert(Stuff,Items[i])
for a,v in pairs(Items[i]) do
-- dat:tackE(a.."|"..tostring(v))
print(a.."|"..tostring(v))
-- dat.workingfile:flush()
end
thread.skip()
local NItems = Items[i]:getChildren()
if NItems ~= nil then
Seek(NItems)
end
end
end
local Objs = Object:getChildren()
for i=1,#Objs do
-- table.insert(Stuff,Objs[i])
for a,v in pairs(Objs[i]) do
-- dat:tackE(a.."|"..tostring(v))
print(Objs[i].Type..":"..a.."|"..tostring(v))
-- dat.workingfile:flush()
end
thread.skip()
local Items = Objs[i]:getChildren()
if Items ~= nil then
Seek(Items)
end
end
-- dat:tofile("test.dat")
return Stuff
end
GetAllChildren2(self)
end)
end

View File

@ -27,37 +27,37 @@ function gui:drawC()
self.hovering=true
if love.mouse.isDown("l") and _GuiPro.hasDrag==false then
if string.find(self.Type, "Button") then
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254)
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility)
else
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
end
self.lclicked=true
elseif love.mouse.isDown("r") and _GuiPro.hasDrag==false then
if string.find(self.Type, "Button") then
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254)
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility)
else
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
end
self.rclicked=true
elseif love.mouse.isDown("m") and _GuiPro.hasDrag==false then
if string.find(self.Type, "Button") then
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254)
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility)
else
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
end
self.mclicked=true
else
if string.find(self.Type, "Button") and _GuiPro.hasDrag==false then
love.graphics.setColor(self.Color[1]-5, self.Color[2]-5, self.Color[3]-5,self.Visibility*254)
love.graphics.setColor(self.Color[1]-5, self.Color[2]-5, self.Color[3]-5,self.Visibility)
else
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
end
self.rclicked=false
self.lclicked=false
self.mclicked=false
end
else
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
self.hovering=false
self.rclicked=false
self.lclicked=false
@ -71,7 +71,7 @@ function gui:drawC()
love.graphics.setStencilTest("notequal",0)
end
love.graphics.circle("fill",x,y,r,s)
love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],self.BorderVisibility*254)
love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],self.Visibility)
for b=0,self.BorderSize-1 do
love.graphics.circle("line",x,y,r+b,s)
end
@ -80,7 +80,7 @@ function gui:drawC()
if self.AutoScaleText then
self.FontSize=math.floor(self.height/1.45833)
end
love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility*254)
love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility)
love.graphics.setFont(self.Font)
love.graphics.printf(self.text, x-(r/2)+(self.XTween), y-(r/2)+self.Tween, r, self.TextFormat)
end

View File

@ -27,37 +27,37 @@ function gui:drawR()
self.hovering=true
if love.mouse.isDown("l") or self:touchable("r") and _GuiPro.hasDrag==false then
if string.find(self.Type, "Button") then
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254)
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility)
else
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
end
self.lclicked=true
elseif love.mouse.isDown("r") or self:touchable("r") and _GuiPro.hasDrag==false then
if string.find(self.Type, "Button") then
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254)
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility)
else
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
end
self.rclicked=true
elseif love.mouse.isDown("m") or self:touchable("r") and _GuiPro.hasDrag==false then
if string.find(self.Type, "Button") then
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254)
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility)
else
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
end
self.mclicked=true
else
if string.find(self.Type, "Button") or self:touchable("r") and _GuiPro.hasDrag==false then
love.graphics.setColor(self.Color[1]-5, self.Color[2]-5, self.Color[3]-5,self.Visibility*254)
love.graphics.setColor(self.Color[1]-5, self.Color[2]-5, self.Color[3]-5,self.Visibility)
else
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
end
self.rclicked=false
self.lclicked=false
self.mclicked=false
end
else
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
self.hovering=false
self.rclicked=false
self.lclicked=false
@ -67,21 +67,22 @@ function gui:drawR()
_GuiPro.Clips[tostring(self)]=self
love.graphics.setScissor(self.x, self.y, self.width, self.height)
end
if self:hasRoundness() then
love.graphics.stencil(self.stfunc, "replace", 1)
love.graphics.setStencilTest("greater", 0)
end
love.graphics.rectangle("fill", self.x, self.y, self.width, self.height,(self.rx or 1)*self.DPI,(self.ry or 1)*self.DPI,(self.segments or 1)*self.DPI)
if string.find(self.Type, "Image") then
self:ImageRule()
end
if self.Type=="Video" then
self:VideoRule()
end
if self:hasRoundness() then
love.graphics.setStencilTest()
end
love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],self.BorderVisibility*254)
if self:hasRoundness() then
love.graphics.stencil(self.stfunc, "replace", 1)
love.graphics.setStencilTest("greater", 0)
end
love.graphics.rectangle("fill", self.x, self.y, self.width, self.height,(self.rx or 1)*self.DPI,(self.ry or 1)*self.DPI,(self.segments or 1)*self.DPI)
if string.find(self.Type, "Image") then
self:ImageRule()
end
if self.Type=="Video" then
self:VideoRule()
end
if self:hasRoundness() then
love.graphics.setStencilTest()
end
love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],self.Visibility)
for b=0,self.BorderSize-1 do
love.graphics.rectangle("line", self.x-(b/2), self.y-(b/2), self.width+b, self.height+b,(self.rx or 1)*self.DPI,(self.ry or 1)*self.DPI,(self.segments or 1)*self.DPI)
end
@ -90,10 +91,16 @@ function gui:drawR()
if self.AutoScaleText then
self.FontSize=math.floor(self.height/1.45833)
end
love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility*254)
love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility)
if self.Font==_defaultfont then
love.graphics.setFont(self.Font)
love.graphics.printf(self.text, self.x+2+(self.XTween*self.DPI)+((self.marginL or 0)*self.DPI or self.XTween*self.DPI), self.y+(self.FontHeight/2)+self.Tween*self.DPI, self.width+(0 or (self.marginR or 0)*self.DPI), self.TextFormat)
love.graphics.printf(
self.text,
(self.x+2+(self.marginL or 0) or self.XTween)*self.DPI,
(self.y+math.floor((self.FontHeight-self.FontSize)/2)+self.Tween)*self.DPI,
(self.width+(0 or (self.marginR or 0)))*self.DPI,
self.TextFormat,
self.TextRotation)
else
if type(self.Font)=="string" then
self.Font=love.graphics.newFont(self.Font,self.FontSize)
@ -105,7 +112,13 @@ function gui:drawR()
self.FontSize=tonumber(self.FontSize)
love.graphics.setNewFont(self.FontSize)
end
love.graphics.printf(self.text, self.x+2+((self.marginL or 0)*self.DPI or self.XTween*self.DPI), self.y+math.floor((self.FontHeight-self.FontSize)/2)+self.Tween*self.DPI, self.width+(0 or (self.marginR or 0)*self.DPI), self.TextFormat)
love.graphics.printf(
self.text,
(self.x+2+(self.marginL or 0) or self.XTween)*self.DPI,
(self.y+math.floor((self.FontHeight-self.FontSize)/2)+self.Tween)*self.DPI,
(self.width+(0 or (self.marginR or 0)))*self.DPI,
self.TextFormat,
self.TextRotation)
end
end
end

View File

@ -1,10 +1,10 @@
function gui:SetImage(i)
if type(i)=="string" then
if type(i)=="string" or tostring(i):find("ImageData") then
self.Image=love.graphics.newImage(i)
else
self.Image=i
end
if self.Image~=nil then
if self.Image then
self.ImageHeigth=self.Image:getHeight()
self.ImageWidth=self.Image:getWidth()
self.Quad=love.graphics.newQuad(0,0,self.width,self.height,self.ImageWidth,self.ImageHeigth)

View File

@ -1,7 +1,7 @@
function gui:newImageButton(i,name, x, y, w, h, sx ,sy ,sw ,sh)
x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh)
local c=self:newBase("ImageButton",name, x, y, w, h, sx ,sy ,sw ,sh)
if type(i)=="string" then
if type(i)=="string" or type(i):find("ImageData") then
c.Image=love.graphics.newImage(i)
else
c.Image=i

View File

@ -1,7 +1,7 @@
function gui:newImageLabel(i,name, x, y, w, h, sx ,sy ,sw ,sh)
x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh)
local c=self:newBase("ImageLabel",name, x, y, w, h, sx ,sy ,sw ,sh)
if type(i)=="string" then
if type(i)=="string" or type(i):find("ImageData") then
c.Image=love.graphics.newImage(i)
else
c.Image=i
@ -9,7 +9,7 @@ function gui:newImageLabel(i,name, x, y, w, h, sx ,sy ,sw ,sh)
c.Visibility=0
c.ImageVisibility=1
c.rotation=0
if c.Image~=nil then
if c.Image then
c.ImageHeigth=c.Image:getHeight()
c.ImageWidth=c.Image:getWidth()
c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth)

View File

@ -1,7 +1,7 @@
function _GuiPro.gradient(colors)
local direction = colors.direction or "horizontal"
colors.direction=nil
trans = colors.trans or 255
trans = colors.trans or 1
trans=math.floor(trans)
if direction == "horizontal" then
direction = true
@ -10,7 +10,7 @@ function _GuiPro.gradient(colors)
else
error("Invalid direction '" .. tostring(direction) "' for gradient. Horizontal or vertical expected.")
end
local result = love.image.newImageData(direction and 1 or #colors, direction and #colors or 1)
local result = love.image.newImageData(direction and 1 or #colors, direction and #colors or 1,"rgba32f")
for __i, color in ipairs(colors) do
local x, y
if direction then

View File

@ -1,4 +1,4 @@
function gui:Center()
local x,y=self:getFullSize()
self:SetDualDim(-math.floor(x/2),-math.floor(y/2),nil,nil,.5,.5)
function gui:center()
self:centerX()
self:centerY()
end

View File

@ -6,4 +6,5 @@ function gui:Destroy()
table.remove(self.Parent.Children,cc)
end
end
self.Destroyed = true
end

View File

@ -2,9 +2,9 @@ function gui:getFullSize()
local maxx,maxy=-math.huge,-math.huge
local temp = self:GetAllChildren()
for i=1,#temp do
if temp[i].width>maxx then
if temp[i].width+temp[i].offset.pos.x>maxx then
maxx=temp[i].width+temp[i].offset.pos.x
elseif temp[i].height>maxy then
elseif temp[i].height+temp[i].offset.pos.y>maxy then
maxy=temp[i].height+temp[i].offset.pos.y
end
end

View File

@ -1,4 +1,4 @@
if love.filesystem.exists("CheckBoxes.png") then
if love.filesystem.getInfo("CheckBoxes.png") then
_GuiPro.UC=gui:getTile("CheckBoxes.png",0,0,16,16)
_GuiPro.C=gui:getTile("CheckBoxes.png",16,0,16,16)
_GuiPro.UCH=gui:getTile("CheckBoxes.png",0,16,16,16)

View File

@ -1,3 +1,7 @@
function gui:setNewFont(FontSize)
self.Font=love.graphics.setNewFont(tonumber(FontSize))
function gui:setNewFont(FontSize,filename)
if filename then
self.Font = love.graphics.newFont(filename, tonumber(FontSize))
else
self.Font=love.graphics.setNewFont(tonumber(FontSize))
end
end

View File

@ -28,7 +28,7 @@ function gui:newTextBox(t,name, x, y, w, h, sx ,sy ,sw ,sh)
c.mark=nil
c.arrowkeys=false
c.funcF={function()
love.keyboard.setTextInput(true)
love.keyboard.setTextInput(true,0,200,400,200)
end}
c.cooldown=false
c.cooldown2=false
@ -59,6 +59,9 @@ function gui:newTextBox(t,name, x, y, w, h, sx ,sy ,sw ,sh)
table.insert(self.funcE,func)
end
c:OnClicked(function(b,self)
self:focus()
end)
function c:focus()
for cc=1,#self.funcF do
self.funcF[cc](self)
end
@ -74,7 +77,7 @@ function gui:newTextBox(t,name, x, y, w, h, sx ,sy ,sw ,sh)
end
self.Active=true
end
end)
end
c:OnClicked(function(b,self,x,y)
local dwidth, wrappedtext = _defaultfont:getWrap(self.text:sub(1,self.cursor[1]), self.width)
local height = _defaultfont:getHeight()
@ -144,7 +147,7 @@ function gui:newTextBox(t,name, x, y, w, h, sx ,sy ,sw ,sh)
self.ttext=self.ttext.."\n"
self.cooldown2=true
c.Alarm2:Reset()
elseif (love.keyboard.isDown("return") or love.keyboard.isDown("enter") or love.keyboard.isDown("kpenter")) and self.Active and self.Enter and not(love.keyboard.isDown("lshift") or love.keyboard.isDown("rshift")) then
elseif (love.keyboard.isDown("return") or love.keyboard.isDown("kpenter")) and self.Active and self.Enter and not(love.keyboard.isDown("lshift") or love.keyboard.isDown("rshift")) then
if self.LoseFocusOnEnter then
self.Active=false
else

View File

@ -0,0 +1,5 @@
function gui:widthToTextSize(n)
if self.Font then
self:setDualDim(nil,nil,self.Font:getWidth(self.text)+(n or 4),nil,nil,nil,0)
end
end

View File

@ -1,5 +1,4 @@
utf8 = require("utf8")
_defaultfont = love.graphics.getFont()
gui = {}
gui.__index = gui
gui.TB={}
@ -7,14 +6,15 @@ gui.Version="VERSION" -- Is it really ready for release?
_GuiPro={GBoost=true,hasDrag=false,DragItem={},Children={},Visible=true,count=0,x=0,y=0,height=0,width=0,update=function(self) local things=GetAllChildren2(self) UpdateThings(things) end,draw=function(self) local things=GetAllChildren(self) DrawThings(things) end,getChildren=function(self) return self.Children end}
_GuiPro.Clips={}
_GuiPro.rotate=0
_defaultfont = love.graphics.setNewFont(12)
setmetatable(_GuiPro, gui)
function gui:LoadInterface(file)
local add=".int"
if string.find(file,".",1,true) then add="" end
if love.filesystem.exists(file..add) then
if love.filesystem.getInfo(file..add) then
a,b=pcall(love.filesystem.load(file..add))
if a then
print("Loaded: "..file)
--print("Loaded: "..file)
else
print("Error loading file: "..file)
print(a,b)
@ -34,7 +34,6 @@ function gui.LoadAll(dir)
end
-- Start Of Load
--gui.LoadAll("GuiManager/LibCore")
gui.LoadAll("GuiManager/Core")
gui.LoadAll("GuiManager/Image-Animation")
gui.LoadAll("GuiManager/Frame")
@ -42,10 +41,8 @@ gui.LoadAll("GuiManager/Item")
gui.LoadAll("GuiManager/Misc")
gui.LoadAll("GuiManager/Text")
gui.LoadAll("GuiManager/Drawing")
gui.LoadAll("GuiManager/Combos")
--gui.LoadAll("GuiManager/WIP")
multi.boost=2
multi.boost=2
-- End of Load
gui:respectHierarchy()
_GuiPro.width,_GuiPro.height=love.graphics.getDimensions()

View File

@ -23,64 +23,10 @@ SOFTWARE.
]]
require("multi")
os.sleep=love.timer.sleep
function love.run()
if love.math then
love.math.setRandomSeed(os.time())
end
if love.event then
love.event.pump()
end
if love.load then love.load(arg) end
if love.timer then love.timer.step() end
local dt = 0
local breakme=false
multi:newThread("MAIN-RUN",function()
while true do
-- Process events.
if love.event then
love.event.pump()
for name, a,b,c,d,e,f in love.event.poll() do
if name == "quit" then
if not love.quit or not love.quit() then
breakme=true
thread.kill()
break
end
end
love.handlers[name](a,b,c,d,e,f)
end
end
if love.timer then
love.timer.step()
dt = love.timer.getDelta()
end
if love.update then love.update(dt) end
if love.window and love.graphics and love.window.isCreated() then
love.graphics.clear()
love.graphics.origin()
if love.draw then love.draw() end
multi.dManager()
love.graphics.setColor(255,255,255,255)
if multi.draw then multi.draw() end
love.graphics.present()
end
thread.sleep()
end
end)
while not breakme do
love.timer.sleep(.005)
multi:uManager(dt)
if multi.boost then
for i=1,multi.boost-1 do
multi:uManager(dt)
end
end
end
return
end
multi.drawF={}
function multi:dManager()
function multi.dManager()
for ii=1,#multi.drawF do
love.graphics.setColor(255,255,255,255)
multi.drawF[ii]()
end
end
@ -88,34 +34,3 @@ function multi:onDraw(func,i)
i=i or 1
table.insert(self.drawF,i,func)
end
--~ function multi:lManager()
--~ if love.event then
--~ love.event.pump()
--~ for e,a,b,c,d in love.event.poll() do
--~ if e == "quit" then
--~ if not love.quit or not love.quit() then
--~ if love.audio then
--~ love.audio.stop()
--~ end
--~ return nil
--~ end
--~ end
--~ love.handlers[e](a,b,c,d)
--~ end
--~ end
--~ if love.timer then
--~ love.timer.step()
--~ dt = love.timer.getDelta()
--~ end
--~ if love.update then love.update(dt) end
--~ multi:uManager(dt)
--~ if love.window and love.graphics and love.window.isCreated() then
--~ love.graphics.clear()
--~ love.graphics.origin()
--~ if love.draw then love.draw() end
--~ multi.dManager()
--~ love.graphics.setColor(255,255,255,255)
--~ if multi.draw then multi.draw() end
--~ love.graphics.present()
--~ end
--~ end

View File

@ -22,62 +22,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
require("bin")
multi = {}
multi.Version = "1.9.2"
multi._VERSION = "1.9.2"
multi.stage = "mostly-stable"
multi.__index = multi
multi.Mainloop = {}
multi.Tasks = {}
multi.Tasks2 = {}
multi.Garbage = {}
multi.ender = {}
multi.Children = {}
multi.Paused = {}
multi.Active = true
multi.fps = 60
multi.Id = -1
multi.Type = "mainprocess"
multi.Rest = 0
multi._type = type
multi.Jobs = {}
multi.queue = {}
multi.jobUS = 2
multi.clock = os.clock
multi.time = os.time
multi.LinkedPath = multi
multi.isRunning = false
--Do not change these ever...Any other number will not work (Unless you are using enablePriority2())
multi.Priority_Core = 1
multi.Priority_High = 4
multi.Priority_Above_Normal = 16
multi.Priority_Normal = 64
multi.Priority_Below_Normal = 256
multi.Priority_Low = 1024
multi.Priority_Idle = 4096
multi.PStep = 1
multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle}
--^^^^
multi.PriorityTick=1 -- Between 1, 2 and 4
multi.Priority=multi.Priority_Core
multi.threshold=256
multi.threstimed=.001
function multi.queuefinal(self)
self:Destroy()
if self.Parent.Mainloop[#self.Parent.Mainloop] then
if self.Parent.Mainloop[#self.Parent.Mainloop].Type=="alarm" then
self.Parent.Mainloop[#self.Parent.Mainloop]:Reset()
self.Parent.Mainloop[#self.Parent.Mainloop].Active=true
else
self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
end
else
for i=1,#self.Parent.funcE do
self.Parent.funcE[i](self)
end
self.Parent:Remove()
end
end
if table.unpack then
unpack=table.unpack
end
@ -107,13 +51,83 @@ function io.write(...)
_write(...)
end
end
multi = {}
multi.Version="1.9.2"
multi._VERSION="1.9.2"
multi.stage='mostly-stable'
multi.__index = multi
multi.Mainloop={}
multi.Tasks={}
multi.Tasks2={}
multi.Garbage={}
multi.ender={}
multi.Children={}
multi.Paused={}
multi.Active=true
multi.fps=60
multi.Id=-1
multi.Type='mainprocess'
multi.Rest=0
multi._type=type
multi.Jobs={}
multi.queue={}
multi.jobUS=2
multi.clock=os.clock
multi.time=os.time
multi.LinkedPath=multi
multi.isRunning=false
multi.queuefinal=function(self)
self:Destroy()
if self.Parent.Mainloop[#self.Parent.Mainloop] then
if self.Parent.Mainloop[#self.Parent.Mainloop].Type=="alarm" then
self.Parent.Mainloop[#self.Parent.Mainloop]:Reset()
self.Parent.Mainloop[#self.Parent.Mainloop].Active=true
else
self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
end
else
for i=1,#self.Parent.funcE do
self.Parent.funcE[i](self)
end
self.Parent:Remove()
end
end
--Do not change these ever...Any other number will not work (Unless you are using enablePriority2())
multi.Priority_Core=1
multi.Priority_High=4
multi.Priority_Above_Normal=16
multi.Priority_Normal=64
multi.Priority_Below_Normal=256
multi.Priority_Low=1024
multi.Priority_Idle=4096
multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle}
multi.PStep=1
--^^^^
multi.PriorityTick=1 -- Between 1,2 and 4
multi.Priority=multi.Priority_Core
multi.threshold=256
multi.threstimed=.001
function multi:setThreshold(n)
self.threshold=n or 120
end
function multi:setThrestimed(n)
self.deltaTarget=n or .1
self.threstimed=n or .001
end
function multi:getLoad()
if multi.load_updater:isPaused() then multi.load_updater:Resume() return 0 end
local val = math.abs(self.dStepA-self.dStepB)/multi.deltaTarget*100
if val > 100 then return 100 else return val end
return multi:newFunction(function(self)
multi.scheduler:Pause()
local sample=#multi.Mainloop
local FFloadtest=0
multi:benchMark(multi.threstimed):OnBench(function(_,l3) FFloadtest=l3*(1/multi.threstimed) end)
self:hold(function() return FFloadtest~=0 end)
local val=FFloadtest/sample
multi.scheduler:Resume()
if val>multi.threshold then
return 0
else
return 100-((val/multi.threshold)*100)
end
end)()
end
function multi:setDomainName(name)
self[name]={}
@ -162,14 +176,6 @@ else
os.execute('sleep ' .. tonumber(n))
end
end
function multi.randomString(n)
local str = ''
local strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}
for i=1,n do
str = str..''..strings[math.random(1,#strings)]
end
return str
end
function multi:getParentProcess()
return self.Mainloop[self.CID]
end
@ -599,15 +605,7 @@ function multi:hold(task)
local env=self.Parent:newEvent(task)
env:OnEvent(function(envt) envt:Pause() envt.Active=false end)
while env.Active do
if love then
if love.graphics then
self.Parent:lManager()
else
self.Parent:Do_Order()
end
else
self.Parent:Do_Order()
end
self.Parent:Do_Order()
end
env:Destroy()
self:Resume()
@ -806,32 +804,25 @@ function multi:newConnection(protect)
c.connections={}
c.fconnections={}
c.FC=0
function c:holdUT(n)
local n=n or 0
function c:holdUT()
self.waiting=true
local count=0
local id=self:connect(function()
count = count + 1
if n<=count then
self.waiting=false
end
self.waiting=false
end)
repeat
self.Parent:uManager()
until self.waiting==false
id:Destroy()
end
c.HoldUT=c.holdUT
function c:fConnect(func)
local temp=self:connect(func)
table.insert(self.fconnections,temp)
self.FC=self.FC+1
end
c.FConnect=c.fConnect
function c:getConnection(name,ingore)
if ingore then
return self.connections[name] or {
Fire=function() end -- if the connection doesn't exist lets call all of them or silently ignore
Fire=function() end -- if the connection doesn't exist lets call all of them or silently ingore
}
else
return self.connections[name] or self
@ -904,7 +895,6 @@ function multi:newConnection(protect)
return temp
end
c.Connect=c.connect
c.GetConnection=c.getConnection
function c:tofile(path)
local m=bin.new()
m:addBlock(self.Type)
@ -1421,112 +1411,6 @@ function multi:newTStep(start,reset,count,set)
self:create(c)
return c
end
function multi:newTimeStamper()
local c=self:newBase()
c.Type='timestamper'
c.Priority=self.Priority_Idle
c.hour = {}
c.minute = {}
c.second = {}
c.time = {}
c.day = {}
c.month = {}
c.year = {}
function c:Act()
for i=1,#self.hour do
if self.hour[i][1]==os.date("%H") and self.hour[i][3] then
self.hour[i][2](self)
self.hour[i][3]=false
elseif self.hour[i][1]~=os.date("%H") and not self.hour[i][3] then
self.hour[i][3]=true
end
end
for i=1,#self.minute do
if self.minute[i][1]==os.date("%M") and self.minute[i][3] then
self.minute[i][2](self)
self.minute[i][3]=false
elseif self.minute[i][1]~=os.date("%M") and not self.minute[i][3] then
self.minute[i][3]=true
end
end
for i=1,#self.second do
if self.second[i][1]==os.date("%S") and self.second[i][3] then
self.second[i][2](self)
self.second[i][3]=false
elseif self.second[i][1]~=os.date("%S") and not self.second[i][3] then
self.second[i][3]=true
end
end
for i=1,#self.day do
if type(self.day[i][1])=="string" then
if self.day[i][1]==os.date("%a") and self.day[i][3] then
self.day[i][2](self)
self.day[i][3]=false
elseif self.day[i][1]~=os.date("%a") and not self.day[i][3] then
self.day[i][3]=true
end
else
if string.format("%02d",self.day[i][1])==os.date("%d") and self.day[i][3] then
self.day[i][2](self)
self.day[i][3]=false
elseif string.format("%02d",self.day[i][1])~=os.date("%d") and not self.day[i][3] then
self.day[i][3]=true
end
end
end
for i=1,#self.month do
if self.month[i][1]==os.date("%m") and self.month[i][3] then
self.month[i][2](self)
self.month[i][3]=false
elseif self.month[i][1]~=os.date("%m") and not self.month[i][3] then
self.month[i][3]=true
end
end
for i=1,#self.time do
if self.time[i][1]==os.date("%X") and self.time[i][3] then
self.time[i][2](self)
self.time[i][3]=false
elseif self.time[i][1]~=os.date("%X") and not self.time[i][3] then
self.time[i][3]=true
end
end
for i=1,#self.year do
if self.year[i][1]==os.date("%y") and self.year[i][3] then
self.year[i][2](self)
self.year[i][3]=false
elseif self.year[i][1]~=os.date("%y") and not self.year[i][3] then
self.year[i][3]=true
end
end
end
function c:OnTime(hour,minute,second,func)
if type(hour)=="number" then
self.time[#self.time+1]={string.format("%02d:%02d:%02d",hour,minute,second),func,true}
else
self.time[#self.time+1]={hour,minute,true}
end
end
function c:OnHour(hour,func)
self.hour[#self.hour+1]={string.format("%02d",hour),func,true}
end
function c:OnMinute(minute,func)
self.minute[#self.minute+1]={string.format("%02d",minute),func,true}
end
function c:OnSecond(second,func)
self.second[#self.second+1]={string.format("%02d",second),func,true}
end
function c:OnDay(day,func)
self.day[#self.day+1]={day,func,true}
end
function c:OnMonth(month,func)
self.month[#self.month+1]={string.format("%02d",month),func,true}
end
function c:OnYear(year,func)
self.year[#self.year+1]={string.format("%02d",year),func,true}
end
self:create(c)
return c
end
function multi:newWatcher(namespace,name)
local function WatcherObj(ns,n)
if self.Type=='queue' then
@ -1572,7 +1456,9 @@ function thread.sleep(n)
coroutine.yield({"_sleep_",n or 0})
end
function thread.hold(n)
if n then if n() then return false end end
coroutine.yield({"_hold_",n or function() return true end})
return true
end
function thread.skip(n)
coroutine.yield({"_skip_",n or 0})
@ -2100,7 +1986,7 @@ function multi:newThreadedLoop(name,func)
thread.sleep(c.restRate) -- rest a bit more when a thread is paused
else
for i=1,#c.func do
c.func[i](os.clock()-self.Start,c)
c.func[i](c,os.clock()-self.Start)
end
thread.sleep(c.updaterate) -- lets rest a bit
end
@ -2384,18 +2270,3 @@ end
function multi:setDefualtStateFlag(opt)
--
end
multi.dStepA = 0
multi.dStepB = 0
multi.dSwap = 0
multi.deltaTarget = .05
multi.load_updater = multi:newUpdater(2)
multi.load_updater:Pause()
multi.load_updater:OnUpdate(function(self)
if self.Parent.dSwap == 0 then
self.Parent.dStepA = os.clock()
self.Parent.dSwap = 1
else
self.Parent.dSwap = 0
self.Parent.dStepB = os.clock()
end
end)

View File

@ -249,6 +249,56 @@ function multi:systemThreadedBenchmark(n,p)
end)
return c
end
function multi:newSystemThreadedConsole(name)
local c={}
c.name = name
local sThread=multi.integration.THREAD
local GLOBAL=multi.integration.GLOBAL
function c:init()
require("multi")
if multi:getPlatform()=="love2d" then
GLOBAL=_G.GLOBAL
sThread=_G.sThread
end
local cc={}
if isMainThread then
if GLOBAL["__SYSTEM_CONSLOE__"] then
cc.stream = sThread.waitFor("__SYSTEM_CONSLOE__"):init()
else
cc.stream = multi:newSystemThreadedQueue("__SYSTEM_CONSLOE__"):init()
multi:newThread("Threaded_Console",function()
while true do
thread.sleep(.001)
local data = cc.stream:pop()
if data then
local dat = table.remove(data,1)
if dat=="w" then
io.write(unpack(data))
elseif dat=="p" then
print(unpack(data))
end
end
end
end)
end
else
cc.stream = sThread.waitFor("__SYSTEM_CONSLOE__"):init()
end
function cc:write(msg)
self.stream:push({"w",tostring(msg)})
end
function cc:print(...)
local tab = {...}
for i=1,#tab do
tab[i]=tostring(tab[i])
end
self.stream:push({"p",unpack(tab)})
end
return cc
end
GLOBAL[c.name]=c
return c
end
function multi:newSystemThreadedTable(name)
local c={}
c.name=name -- set the name this is important for identifying what is what

View File

@ -23,64 +23,10 @@ SOFTWARE.
]]
require("multi")
os.sleep=love.timer.sleep
function love.run()
if love.math then
love.math.setRandomSeed(os.time())
end
if love.event then
love.event.pump()
end
if love.load then love.load(arg) end
if love.timer then love.timer.step() end
local dt = 0
local breakme=false
multi:newThread("MAIN-RUN",function()
while true do
-- Process events.
if love.event then
love.event.pump()
for name, a,b,c,d,e,f in love.event.poll() do
if name == "quit" then
if not love.quit or not love.quit() then
breakme=true
thread.kill()
break
end
end
love.handlers[name](a,b,c,d,e,f)
end
end
if love.timer then
love.timer.step()
dt = love.timer.getDelta()
end
if love.update then love.update(dt) end
if love.window and love.graphics and love.window.isCreated() then
love.graphics.clear()
love.graphics.origin()
if love.draw then love.draw() end
multi.dManager()
love.graphics.setColor(255,255,255,255)
if multi.draw then multi.draw() end
love.graphics.present()
end
thread.sleep()
end
end)
while not breakme do
love.timer.sleep(.005)
multi:uManager(dt)
if multi.boost then
for i=1,multi.boost-1 do
multi:uManager(dt)
end
end
end
return
end
multi.drawF={}
function multi:dManager()
function multi.dManager()
for ii=1,#multi.drawF do
love.graphics.setColor(255,255,255,255)
multi.drawF[ii]()
end
end
@ -88,34 +34,3 @@ function multi:onDraw(func,i)
i=i or 1
table.insert(self.drawF,i,func)
end
--~ function multi:lManager()
--~ if love.event then
--~ love.event.pump()
--~ for e,a,b,c,d in love.event.poll() do
--~ if e == "quit" then
--~ if not love.quit or not love.quit() then
--~ if love.audio then
--~ love.audio.stop()
--~ end
--~ return nil
--~ end
--~ end
--~ love.handlers[e](a,b,c,d)
--~ end
--~ end
--~ if love.timer then
--~ love.timer.step()
--~ dt = love.timer.getDelta()
--~ end
--~ if love.update then love.update(dt) end
--~ multi:uManager(dt)
--~ if love.window and love.graphics and love.window.isCreated() then
--~ love.graphics.clear()
--~ love.graphics.origin()
--~ if love.draw then love.draw() end
--~ multi.dManager()
--~ love.graphics.setColor(255,255,255,255)
--~ if multi.draw then multi.draw() end
--~ love.graphics.present()
--~ end
--~ end

View File

@ -23,8 +23,8 @@ SOFTWARE.
]]
require("bin")
multi = {}
multi.Version = "1.10.0"
multi._VERSION = "1.10.0"
multi.Version = "1.11.0"
multi._VERSION = "1.11.0"
multi.stage = "stable"
multi.__index = multi
multi.Mainloop = {}

View File

@ -249,6 +249,56 @@ function multi:systemThreadedBenchmark(n,p)
end)
return c
end
function multi:newSystemThreadedConsole(name)
local c={}
c.name = name
local sThread=multi.integration.THREAD
local GLOBAL=multi.integration.GLOBAL
function c:init()
require("multi")
if multi:getPlatform()=="love2d" then
GLOBAL=_G.GLOBAL
sThread=_G.sThread
end
local cc={}
if isMainThread then
if GLOBAL["__SYSTEM_CONSLOE__"] then
cc.stream = sThread.waitFor("__SYSTEM_CONSLOE__"):init()
else
cc.stream = multi:newSystemThreadedQueue("__SYSTEM_CONSLOE__"):init()
multi:newThread("Threaded_Console",function()
while true do
thread.sleep(.001)
local data = cc.stream:pop()
if data then
local dat = table.remove(data,1)
if dat=="w" then
io.write(unpack(data))
elseif dat=="p" then
print(unpack(data))
end
end
end
end)
end
else
cc.stream = sThread.waitFor("__SYSTEM_CONSLOE__"):init()
end
function cc:write(msg)
self.stream:push({"w",tostring(msg)})
end
function cc:print(...)
local tab = {...}
for i=1,#tab do
tab[i]=tostring(tab[i])
end
self.stream:push({"p",unpack(tab)})
end
return cc
end
GLOBAL[c.name]=c
return c
end
function multi:newSystemThreadedTable(name)
local c={}
c.name=name -- set the name this is important for identifying what is what

View File

@ -0,0 +1,33 @@
package = "multi"
version = "1.10.0"
source = {
url = "git://github.com/rayaman/multi.git",
tag = "v1.10.0",
}
description = {
summary = "Lua Multi tasking library",
detailed = [[
This library contains many methods for multi tasking. From simple side by side code using multiobjs, to using coroutine based Threads and System threads(When you have lua lanes installed or are using love2d. Optional) The core of the library works on lua 5.1+ however the systemthreading features are limited to 5.1 due to love2d and lua lanes and now luvit (See ReadMe on gotchas) being lua 5.1 only!
]],
homepage = "https://github.com/rayaman/multi",
license = "MIT"
}
dependencies = {
"lua >= 5.1",
"bin",
"lanes"
}
build = {
type = "builtin",
modules = {
-- Note the required Lua syntax when listing submodules as keys
["multi.init"] = "multi/init.lua",
["multi.all"] = "multi/all.lua",
["multi.compat.backwards[1,5,0]"] = "multi/compat/backwards[1,5,0].lua",
["multi.compat.love2d"] = "multi/compat/love2d.lua",
["multi.integration.lanesManager"] = "multi/integration/lanesManager.lua",
["multi.integration.loveManager"] = "multi/integration/loveManager.lua",
["multi.integration.luvitManager"] = "multi/integration/luvitManager.lua",
["multi.integration.shared"] = "multi/integration/shared.lua"
}
}

View File

@ -0,0 +1,32 @@
package = "multi"
version = "1.11.0"
source = {
url = "git://github.com/rayaman/multi.git",
tag = "v1.11.0",
}
description = {
summary = "Lua Multi tasking library",
detailed = [[
This library contains many methods for multi tasking. From simple side by side code using multi-objs, to using coroutine based Threads and System threads(When you have lua lanes installed or are using love2d)
]],
homepage = "https://github.com/rayaman/multi",
license = "MIT"
}
dependencies = {
"lua >= 5.1",
"bin",
"lanes"
}
build = {
type = "builtin",
modules = {
["multi.init"] = "multi/init.lua",
["multi.all"] = "multi/all.lua",
["multi.compat.backwards[1,5,0]"] = "multi/compat/backwards[1,5,0].lua",
["multi.compat.love2d"] = "multi/compat/love2d.lua",
["multi.integration.lanesManager"] = "multi/integration/lanesManager.lua",
["multi.integration.loveManager"] = "multi/integration/loveManager.lua",
["multi.integration.luvitManager"] = "multi/integration/luvitManager.lua",
["multi.integration.shared"] = "multi/integration/shared.lua"
}
}

View File

@ -2,7 +2,7 @@ package = "multi"
version = "1.9-2"
source = {
url = "git://github.com/rayaman/multi.git",
tag = "v1.9.1",
tag = "v1.9.2",
}
description = {
summary = "Lua Multi tasking library",

View File

@ -0,0 +1,33 @@
package = "multi"
version = "1.9-3"
source = {
url = "git://github.com/rayaman/multi.git",
tag = "v1.9.3",
}
description = {
summary = "Lua Multi tasking library",
detailed = [[
This library contains many methods for multi tasking. From simple side by side code using multiobjs, to using coroutine based Threads and System threads(When you have lua lanes installed or are using love2d. Optional) The core of the library works on lua 5.1+ however the systemthreading features are limited to 5.1 due to love2d and lua lanes and now luvit (See ReadMe on gotchas) being lua 5.1 only!
]],
homepage = "https://github.com/rayaman/multi",
license = "MIT"
}
dependencies = {
"lua >= 5.1",
"bin",
"lanes"
}
build = {
type = "builtin",
modules = {
-- Note the required Lua syntax when listing submodules as keys
["multi.init"] = "multi/init.lua",
["multi.all"] = "multi/all.lua",
["multi.compat.backwards[1,5,0]"] = "multi/compat/backwards[1,5,0].lua",
["multi.compat.love2d"] = "multi/compat/love2d.lua",
["multi.integration.lanesManager"] = "multi/integration/lanesManager.lua",
["multi.integration.loveManager"] = "multi/integration/loveManager.lua",
["multi.integration.luvitManager"] = "multi/integration/luvitManager.lua",
["multi.integration.shared"] = "multi/integration/shared.lua"
}
}