Fix stage 2 Installer
This commit is contained in:
3
installer/LevelOS_Custom.lua
Normal file
3
installer/LevelOS_Custom.lua
Normal file
@@ -0,0 +1,3 @@
|
||||
self.package = {
|
||||
["name"] = "Custom",
|
||||
}
|
||||
3
installer/LevelOS_Full.lua
Normal file
3
installer/LevelOS_Full.lua
Normal file
@@ -0,0 +1,3 @@
|
||||
self.package = {
|
||||
["name"] = "Full"
|
||||
}
|
||||
14
installer/LevelOS_Minimal.lua
Normal file
14
installer/LevelOS_Minimal.lua
Normal file
@@ -0,0 +1,14 @@
|
||||
self.package = {
|
||||
["name"] = "Minimal",
|
||||
"startup.lua",
|
||||
"LevelOS/desktop.lua",
|
||||
"LevelOS/system.lua",
|
||||
"LevelOS/assets/loading.limg",
|
||||
"LevelOS/Clock.lua",
|
||||
"LevelOS/SystemUI.lua",
|
||||
"LevelOS/explorer.lua",
|
||||
"LevelOS/settings.lua",
|
||||
"LevelOS/Task_Manager.lua",
|
||||
"LevelOS/startup/lUtils.lua",
|
||||
"LevelOS/startup/MwMRender",
|
||||
}
|
||||
6
installer/Package_Click.lua
Normal file
6
installer/Package_Click.lua
Normal file
@@ -0,0 +1,6 @@
|
||||
local s = shapescape.getSlide()
|
||||
if s.var.package and s.var.package == self.package then
|
||||
s.var.package = nil
|
||||
else
|
||||
s.var.package = self.package
|
||||
end
|
||||
6
installer/Package_Update.lua
Normal file
6
installer/Package_Update.lua
Normal file
@@ -0,0 +1,6 @@
|
||||
local s = shapescape.getSlide()
|
||||
if s.var.package == self.package then
|
||||
self.border.color = colors.blue
|
||||
else
|
||||
self.border.color = colors.cyan
|
||||
end
|
||||
12
installer/back.lua
Normal file
12
installer/back.lua
Normal file
@@ -0,0 +1,12 @@
|
||||
local slides = shapescape.getSlides()
|
||||
if self.txt == " Back" and slides.cSlide > 1 then
|
||||
shapescape.setSlide(slides.cSlide-1)
|
||||
else
|
||||
a = {lUtils.popup("LevelOS Setup","Are you sure you want to exit the LevelOS installer?",27,9,{"Cancel","Confirm"})}
|
||||
if a[1] and a[3] == "Confirm" then
|
||||
term.setBackgroundColor(colors.black)
|
||||
term.clear()
|
||||
term.setCursorPos(1,1)
|
||||
shapescape.exit()
|
||||
end
|
||||
end
|
||||
5
installer/changecolor.lua
Normal file
5
installer/changecolor.lua
Normal file
@@ -0,0 +1,5 @@
|
||||
term.setPaletteColor(colors.cyan,26/255,6/255,85/255)
|
||||
local s = shapescape.getSlide()
|
||||
if not s.var then
|
||||
s.var = {}
|
||||
end
|
||||
30
installer/checkbox.lua
Normal file
30
installer/checkbox.lua
Normal file
@@ -0,0 +1,30 @@
|
||||
local function redraw()
|
||||
local bl = {
|
||||
{
|
||||
"",
|
||||
"990",
|
||||
"009",
|
||||
},
|
||||
{
|
||||
"",
|
||||
"900",
|
||||
"099",
|
||||
},
|
||||
{
|
||||
"",
|
||||
"000",
|
||||
"999",
|
||||
},
|
||||
}
|
||||
if self.value then
|
||||
bl[2][1] = "x"
|
||||
end
|
||||
for t=1,3 do
|
||||
term.setCursorPos(1,t)
|
||||
term.blit(unpack(bl[t]))
|
||||
end
|
||||
end
|
||||
while true do
|
||||
os.pullEvent()
|
||||
redraw()
|
||||
end
|
||||
11
installer/corclicky.lua
Normal file
11
installer/corclicky.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
while true do
|
||||
local e = {os.pullEvent()}
|
||||
if e[1] == "mouse_click" and e[3] >= self.x1 and e[4] >= self.y1 and e[3] <= self.x2 and e[4] <= self.y2 then
|
||||
self.oldcolor = self.color
|
||||
self.color = self.border.color
|
||||
elseif e[1] == "mouse_up" and self.oldcolor then
|
||||
self.color = self.oldcolor
|
||||
self.oldcolor = nil
|
||||
end
|
||||
self.render()
|
||||
end
|
||||
8
installer/install.lua
Normal file
8
installer/install.lua
Normal file
@@ -0,0 +1,8 @@
|
||||
local win = window.create(term.current(),1,1,term.getSize())
|
||||
local function render()
|
||||
term.setBackgroundColor(colors.cyan)
|
||||
term.clear()
|
||||
local x = 2
|
||||
local w,h = term.getSize()
|
||||
if w <
|
||||
win.reposition(
|
||||
216
installer/installer.lua
Normal file
216
installer/installer.lua
Normal file
@@ -0,0 +1,216 @@
|
||||
local function dothething()
|
||||
local function wordwrap(str)
|
||||
local x,y = term.getCursorPos()
|
||||
local tW,tH = term.getSize()
|
||||
for w in str:gmatch("%S+") do
|
||||
local x1,y1 = term.getCursorPos()
|
||||
if x1+(#w*3) >= tW then
|
||||
bigfont.bigPrint(" ")
|
||||
local x2,y2 = term.getCursorPos()
|
||||
term.setCursorPos(x,y2)
|
||||
end
|
||||
bigfont.bigWrite(w.." ")
|
||||
end
|
||||
end
|
||||
--local ico = lUtils.asset.load("User/Cloud/Images/New_Loading.limg") -- replace with actual filepath later
|
||||
local f = http.post("https://os.leveloper.cc/sGet.php","path="..textutils.urlEncode("LevelOS/assets/loading.limg").."&code="..textutils.urlEncode("lSlb8kZq"),nil).readAll()
|
||||
local ico = textutils.unserialize(f)
|
||||
for t=1,#ico do
|
||||
for l=1,#ico[t] do
|
||||
ico[t][l][2] = string.gsub(ico[t][l][2],"T","9")
|
||||
ico[t][l][3] = string.gsub(ico[t][l][3],"T","9")
|
||||
end
|
||||
end
|
||||
local frame = 1
|
||||
local prog = 0
|
||||
local icoX,icoY
|
||||
local function renderIco(frame)
|
||||
local f = ico[frame]
|
||||
for l=1,#f do
|
||||
term.setCursorPos(icoX,icoY+(l-1))
|
||||
term.blit(unpack(f[l]))
|
||||
end
|
||||
end
|
||||
local function progress()
|
||||
while true do
|
||||
renderIco(frame)
|
||||
term.setCursorPos(icoX+5,icoY+1)
|
||||
term.write(math.floor(prog + 0.5).."% complete")
|
||||
if badConn then
|
||||
term.setCursorPos(x, icoY+5)
|
||||
print("Having trouble connecting, please hang on...")
|
||||
end
|
||||
os.sleep(0.1)
|
||||
frame = frame+1
|
||||
if frame > #ico then
|
||||
frame = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function fread(file)
|
||||
local f = fs.open(file,"r")
|
||||
local o = f.readAll()
|
||||
f.close()
|
||||
return o
|
||||
end
|
||||
|
||||
local function fwrite(file,content)
|
||||
local f = fs.open(file,"w")
|
||||
f.write(content)
|
||||
f.close()
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
local badConn = false
|
||||
local function render()
|
||||
term.setBackgroundColor(colors.cyan)
|
||||
term.setTextColor(colors.white)
|
||||
term.clear()
|
||||
local w,h = term.getSize()
|
||||
local x = 2
|
||||
if w > 51 then
|
||||
x = math.floor(x+((w-51)/4))
|
||||
end
|
||||
term.setCursorPos(x,3)
|
||||
wordwrap("Installing LevelOS")
|
||||
bigfont.bigPrint(" ")
|
||||
local x1,y1 = term.getCursorPos()
|
||||
term.setCursorPos(x,y1+2)
|
||||
print("This might take a while. Don't turn off your computer.")
|
||||
local x1,y1 = term.getCursorPos()
|
||||
icoX,icoY = x,y1+1
|
||||
-- perhaps a cancel button if i ever feel like it
|
||||
end
|
||||
render()
|
||||
local function events()
|
||||
while true do
|
||||
local e = {os.pullEvent()}
|
||||
-- process things if buttons
|
||||
if e[1] == "term_resize" then
|
||||
render()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local hpost = function(...)
|
||||
while true do
|
||||
local ret = table.pack(http.post(...))
|
||||
if not ret[1] then
|
||||
badConn = true
|
||||
render()
|
||||
os.sleep(0.5)
|
||||
else
|
||||
badConn = false
|
||||
return table.unpack(ret, 1, ret.n)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function getField(thing,fieldname)
|
||||
if string.find(thing,"<"..fieldname..">",1,true) ~= nil and string.find(thing,"</"..fieldname..">",1,true) ~= nil then
|
||||
begin = nil
|
||||
ending = nil
|
||||
trash,begin = string.find(thing,"<"..fieldname..">",1,true)
|
||||
ending,ending2 = string.find(thing,"</"..fieldname..">",begin+1,true)
|
||||
if begin ~= nil and ending ~= nil then
|
||||
return string.sub(thing,begin+1,ending-1),string.sub(thing,1,trash-1)..string.sub(thing,ending2+1,string.len(thing))
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function download(pth)
|
||||
local f = hpost("https://os.leveloper.cc/sGet.php","path="..textutils.urlEncode(pth).."&code="..textutils.urlEncode("lSlb8kZq"),{Cookie=userID}).readAll()
|
||||
if f ~= "409" and f ~= "403" and f ~= "401" then
|
||||
fwrite(pth,f)
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function downloader()
|
||||
local package = shapescape.getSlides().package
|
||||
|
||||
local tFiles = 0
|
||||
local pack = package.name
|
||||
if fs.exists("LevelOS/data/settings.lconf") then
|
||||
local set = textutils.unserialize(fread("LevelOS/data/settings.lconf"))
|
||||
if set.package then
|
||||
pack = set.package
|
||||
end
|
||||
end
|
||||
|
||||
local tree = {}
|
||||
local folders = {}
|
||||
local function searchFolder(folder)
|
||||
--print("Searching folder root/"..folder)
|
||||
local f = hpost("https://os.leveloper.cc/sGet.php","path="..textutils.urlEncode(folder).."&code="..textutils.urlEncode("lSlb8kZq"),nil).readAll()
|
||||
--print(f)
|
||||
local f2 = f
|
||||
while true do
|
||||
local file = nil
|
||||
file,f = getField(f,"file")
|
||||
if not file then
|
||||
break
|
||||
else
|
||||
local name = getField(file,"name")
|
||||
local timestamp = getField(file,"timestamp")
|
||||
timestamp = tonumber(timestamp)
|
||||
if pack == "Full" or fs.exists(fs.combine(folder,name)) then
|
||||
tree[fs.combine(folder,name)] = {timestamp=timestamp}
|
||||
tFiles = tFiles+1
|
||||
end
|
||||
--print("Found "..fs.combine(folder,name))
|
||||
end
|
||||
end
|
||||
f = f2
|
||||
while true do
|
||||
local file = nil
|
||||
file,f = getField(f,"folder")
|
||||
if not file then
|
||||
break
|
||||
else
|
||||
local name = getField(file,"name")
|
||||
if not fs.exists(fs.combine(folder,name)) then
|
||||
fs.makeDir(fs.combine(folder,name))
|
||||
end
|
||||
folders[fs.combine(folder,name)] = ""
|
||||
searchFolder(fs.combine(folder,name))
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
if not searchFolder("") then return false end
|
||||
|
||||
if pack == "Full" then
|
||||
for k,v in pairs(tree) do
|
||||
table.insert(package,k)
|
||||
end
|
||||
end
|
||||
|
||||
-- check if name is full, if it is then first list the dir then add all the files to the package
|
||||
for p=1,#package do
|
||||
prog = ((p-1)/#package)*100
|
||||
download(package[p])
|
||||
prog = ((p)/#package)*100
|
||||
end
|
||||
local temp = hpost("https://os.leveloper.cc/sGet.php","path="..textutils.urlEncode("").."&code="..textutils.urlEncode("lSlb8kZq"),{Cookie=userID}).readAll()
|
||||
local ver = getField(temp,"version")
|
||||
fwrite("LevelOS/data/version.txt",ver)
|
||||
fwrite("LevelOS/data/settings.lconf",textutils.serialize({package=pack}))
|
||||
os.sleep(2)
|
||||
os.reboot()
|
||||
end
|
||||
parallel.waitForAny(events,progress,downloader)
|
||||
end
|
||||
local ok,err = pcall(dothething)
|
||||
if not ok then
|
||||
term.setCursorPos(1,1)
|
||||
term.setTextColor(colors.red)
|
||||
term.write(err)
|
||||
end
|
||||
133
installer/license.lua
Normal file
133
installer/license.lua
Normal file
@@ -0,0 +1,133 @@
|
||||
local license = http.get("https://pastebin.com/raw/ZbDMa42Q").readAll()
|
||||
local lWin = window.create(term.current(),1,1,term.getSize())
|
||||
local oterm = term.current()
|
||||
local scr = 0 -- scroll
|
||||
local function renderWin()
|
||||
local w,h = term.getSize()
|
||||
lWin.reposition(1,1-scr,w-1,60)
|
||||
term.redirect(lWin)
|
||||
term.setBackgroundColor(colors.white)
|
||||
term.setTextColor(colors.black)
|
||||
term.clear()
|
||||
term.setCursorPos(1,1)
|
||||
print(license)
|
||||
lWin.reposition(1,1-scr,w-1,({term.getCursorPos()})[2])
|
||||
term.redirect(oterm)
|
||||
end
|
||||
|
||||
local scrDrag
|
||||
local calc
|
||||
|
||||
local function scrollbar(e)
|
||||
local w,h = term.getSize()
|
||||
term.setBackgroundColor(colors.lightGray)
|
||||
term.setTextColor(colors.gray)
|
||||
for y=1,h do
|
||||
term.setCursorPos(w,y)
|
||||
if y == 1 then
|
||||
term.write("30")
|
||||
elseif y == h then
|
||||
term.write("31")
|
||||
else
|
||||
term.write(" ")
|
||||
end
|
||||
end
|
||||
local w1,h1 = lWin.getSize()
|
||||
if h1 > h then
|
||||
local sH = h/h1 * (h-2) -- scrollbar height
|
||||
local sY
|
||||
local sYmax
|
||||
if sH < 1 then
|
||||
sY = 2 + (h-2.333)*(scr/(h1-h))
|
||||
sYmax = 2+(h-2.333)*(h1-h)
|
||||
else
|
||||
sY = 2 + (h-1-sH)*(scr/(h1-h))
|
||||
sYmax = 2+(h-1-sH)*(h1-h)
|
||||
end
|
||||
if e then
|
||||
if e[1] == "mouse_click" and e[4] >= sY and e[4] <= sY+(sH-1) then
|
||||
scrDrag = e[4]
|
||||
elseif e[1] == "mouse_drag" and scrDrag then
|
||||
local sYnew = sY+(e[4]-scrDrag)
|
||||
calc = sY.."+("..e[4].."-"..scrDrag..")"
|
||||
if sYnew <= sYmax then
|
||||
sY = sYnew
|
||||
scrDrag = e[4]
|
||||
--calc = "("..sY.."/"..sYmax..") * ("..h1.."-"..h..")"
|
||||
scr = (sY/sYmax) * (h1-h)
|
||||
end
|
||||
elseif e[1] == "mouse_up" then
|
||||
scrDrag = nil
|
||||
end
|
||||
term.setCursorPos(1,1)
|
||||
term.setTextColor(colors.red)
|
||||
lUtils.transWrite("")
|
||||
--os.sleep(0.5)
|
||||
end
|
||||
local bg = colors.gray
|
||||
if scrDrag then
|
||||
bg = colors.black
|
||||
end
|
||||
term.setBackgroundColor(bg)
|
||||
for y=sY,sY+(sH-1) do
|
||||
term.setCursorPos(w,y)
|
||||
term.write(" ")
|
||||
end
|
||||
if sH < 1 then
|
||||
term.setCursorPos(w,math.floor(sY))
|
||||
if math.mod(sY,1) > 0.66 then
|
||||
term.setBackgroundColor(bg)
|
||||
term.setTextColor(colors.lightGray)
|
||||
term.write("143")
|
||||
elseif math.mod(sY,1) > 0.33 then
|
||||
term.setBackgroundColor(bg)
|
||||
term.setTextColor(colors.gray)
|
||||
term.write("140")
|
||||
else
|
||||
term.setBackgroundColor(colors.lightGray)
|
||||
term.setTextColor(bg)
|
||||
term.write("131")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
renderWin()
|
||||
scrollbar()
|
||||
while true do
|
||||
local e = {os.pullEvent()}
|
||||
local w,h = term.getSize()
|
||||
if e[1] == "mouse_scroll" then
|
||||
--local w,h = term.getSize()
|
||||
local w1,h1 = lWin.getSize()
|
||||
if h1 > h and e[3] >= 1 and e[4] >= 1 and e[3] <= self.x2-(self.x1-1) and e[4] <= self.y2-(self.y1-1) then
|
||||
scr = scr+e[2]
|
||||
--local w,h = term.getSize()
|
||||
--local w1,h1 = lWin.getSize()
|
||||
if scr < 0 then
|
||||
scr = 0
|
||||
elseif scr > h1-h then
|
||||
scr = h1-h
|
||||
end
|
||||
renderWin()
|
||||
scrollbar()
|
||||
elseif h1 <= h and scr ~= 0 then
|
||||
scr = 0
|
||||
renderWin()
|
||||
scrollbar()
|
||||
end
|
||||
elseif e[1] == "term_resize" then
|
||||
renderWin()
|
||||
scrollbar()
|
||||
elseif string.find(e[1],"mouse") and e[3] == w and enabledcuznowitsdisabled then
|
||||
scrollbar(e)
|
||||
renderWin()
|
||||
term.setCursorPos(1,1)
|
||||
term.setTextColor(colors.red)
|
||||
lUtils.transWrite(tostring(scrDrag)..", "..tostring(scr))
|
||||
term.setCursorPos(1,2)
|
||||
lUtils.transWrite(tostring(calc))
|
||||
elseif e[1] == "mouse_up" then
|
||||
scrDrag = nil
|
||||
end
|
||||
end
|
||||
2
installer/license_checkbox.lua
Normal file
2
installer/license_checkbox.lua
Normal file
@@ -0,0 +1,2 @@
|
||||
self.value = not self.value
|
||||
shapescape.getSlide().var.license = self.value
|
||||
5
installer/licensenext.lua
Normal file
5
installer/licensenext.lua
Normal file
@@ -0,0 +1,5 @@
|
||||
local slides = shapescape.getSlides()
|
||||
local s = shapescape.getSlide()
|
||||
if s.var.license and slides.cSlide < #slides then
|
||||
shapescape.setSlide(slides.cSlide+1)
|
||||
end
|
||||
22
installer/licensenextclicky.lua
Normal file
22
installer/licensenextclicky.lua
Normal file
@@ -0,0 +1,22 @@
|
||||
local s = shapescape.getSlide()
|
||||
if not s.var then
|
||||
s.var = {}
|
||||
end
|
||||
while true do
|
||||
local e = {os.pullEvent()}
|
||||
if s.var.license then
|
||||
self.border.color = colors.blue
|
||||
self.txtcolor = colors.black
|
||||
if e[1] == "mouse_click" and e[3] >= self.x1 and e[4] >= self.y1 and e[3] <= self.x2 and e[4] <= self.y2 then
|
||||
self.oldcolor = self.color
|
||||
self.color = self.border.color
|
||||
elseif e[1] == "mouse_up" and self.oldcolor then
|
||||
self.color = self.oldcolor
|
||||
self.oldcolor = nil
|
||||
end
|
||||
else
|
||||
self.border.color = colors.lightGray
|
||||
self.txtcolor = colors.lightGray
|
||||
end
|
||||
self.render()
|
||||
end
|
||||
23
installer/loadingicon.lua
Normal file
23
installer/loadingicon.lua
Normal file
@@ -0,0 +1,23 @@
|
||||
local ico = lUtils.asset.load("User/Cloud/Images/New_Loading.limg") -- replace with actual filepath later
|
||||
for t=1,#ico do
|
||||
for l=1,#ico[t] do
|
||||
ico[t][l][2] = string.gsub(ico[t][l][2],"T","9")
|
||||
ico[t][l][3] = string.gsub(ico[t][l][3],"T","9")
|
||||
end
|
||||
end
|
||||
local frame = 1
|
||||
function render(frame)
|
||||
local f = ico[frame]
|
||||
for l=1,#f do
|
||||
term.setCursorPos(1,l)
|
||||
term.blit(unpack(f[l]))
|
||||
end
|
||||
end
|
||||
while true do
|
||||
render(frame)
|
||||
os.sleep(0.1)
|
||||
frame = frame+1
|
||||
if frame > #ico then
|
||||
frame = 1
|
||||
end
|
||||
end
|
||||
19
installer/makebig.lua
Normal file
19
installer/makebig.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
function wordwrap(str)
|
||||
local x,y = term.getCursorPos()
|
||||
local tW,tH = term.getSize()
|
||||
for w in str:gmatch("%S+") do
|
||||
local x1,y1 = term.getCursorPos()
|
||||
if x1+(#w*3) >= tW then
|
||||
bigfont.bigPrint(" ")
|
||||
local x2,y2 = term.getCursorPos()
|
||||
term.setCursorPos(x,y2)
|
||||
end
|
||||
bigfont.bigWrite(w.." ")
|
||||
end
|
||||
end
|
||||
function self.render()
|
||||
term.setCursorPos(self.x1,self.y1)
|
||||
term.setBackgroundColor(colors.cyan)
|
||||
term.setTextColor(self.txtcolor)
|
||||
wordwrap(self.txt)
|
||||
end
|
||||
4
installer/next.lua
Normal file
4
installer/next.lua
Normal file
@@ -0,0 +1,4 @@
|
||||
local slides = shapescape.getSlides()
|
||||
if slides.cSlide < #slides then
|
||||
shapescape.setSlide(slides.cSlide+1)
|
||||
end
|
||||
10
installer/packagenext.lua
Normal file
10
installer/packagenext.lua
Normal file
@@ -0,0 +1,10 @@
|
||||
local slides = shapescape.getSlides()
|
||||
local s = shapescape.getSlide()
|
||||
if s.var.package and slides.cSlide < #slides then
|
||||
slides.package = s.var.package
|
||||
if s.var.package.name == "Custom" then
|
||||
shapescape.setSlide(slides.cSlide+1)
|
||||
else
|
||||
shapescape.setSlide(slides.cSlide+2)
|
||||
end
|
||||
end
|
||||
22
installer/packagenextclicky.lua
Normal file
22
installer/packagenextclicky.lua
Normal file
@@ -0,0 +1,22 @@
|
||||
local s = shapescape.getSlide()
|
||||
if not s.var then
|
||||
s.var = {}
|
||||
end
|
||||
while true do
|
||||
local e = {os.pullEvent()}
|
||||
if s.var.package then
|
||||
self.border.color = colors.blue
|
||||
self.txtcolor = colors.black
|
||||
if e[1] == "mouse_click" and e[3] >= self.x1 and e[4] >= self.y1 and e[3] <= self.x2 and e[4] <= self.y2 then
|
||||
self.oldcolor = self.color
|
||||
self.color = self.border.color
|
||||
elseif e[1] == "mouse_up" and self.oldcolor then
|
||||
self.color = self.oldcolor
|
||||
self.oldcolor = nil
|
||||
end
|
||||
else
|
||||
self.border.color = colors.lightGray
|
||||
self.txtcolor = colors.lightGray
|
||||
end
|
||||
self.render()
|
||||
end
|
||||
Reference in New Issue
Block a user