diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/.prop b/640cd89f-8e29-4b66-a0eb-7680c33760b4/.prop new file mode 100755 index 00000000..5cf0ed07 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/.prop @@ -0,0 +1 @@ +{label = "OpenOS", reboot=true, setlabel=true, setboot=true} diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/1.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/1.pic new file mode 100644 index 00000000..303d57d1 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/1.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/.icons b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/.icons new file mode 100644 index 00000000..ecbf4cc5 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/.icons @@ -0,0 +1 @@ +{["HoloEdit.app"]={["y"]=9,["x"]=87},["Calendar.app"]={["y"]=2,["x"]=73},["ChristmasTree.app"]={["y"]=2,["x"]=101},[".DS_Store"]={["y"]=16,["x"]=143},["RayWalk.app"]={["y"]=16,["x"]=45},["Graph.app"]={["y"]=9,["x"]=31},["InfoPanel.app"]={["y"]=9,["x"]=101},["VK.app"]={["y"]=16,["x"]=115},["Shooting.app"]={["y"]=16,["x"]=73},["Palette.app"]={["y"]=9,["x"]=129},["FlappyBird.app"]={["y"]=2,["x"]=129},["MineCode IDE.app"]={["y"]=9,["x"]=115},["Stargate.app"]={["y"]=16,["x"]=87},["PrintImage.app"]={["y"]=16,["x"]=3},["HoloClock.app"]={["y"]=9,["x"]=73},["GeoScan2.app"]={["y"]=9,["x"]=17},["Photoshop.app"]={["y"]=9,["x"]=143},["RunningString.app"]={["y"]=16,["x"]=59},["Radio.app"]={["y"]=16,["x"]=31},["GuessWord.app"]={["y"]=9,["x"]=45},["3DPrint.app"]={["y"]=2,["x"]=3},["FuckTheRain.app"]={["y"]=9,["x"]=3},["HEX.app"]={["y"]=9,["x"]=59},["ForceAdmin.app"]={["y"]=2,["x"]=143},["BufferDemo.app"]={["y"]=2,["x"]=59},["CodeDoor.app"]={["y"]=2,["x"]=115},["QuantumCube.app"]={["y"]=16,["x"]=17},["TurretControl.app"]={["y"]=16,["x"]=101},["3DTest.app"]={["y"]=2,["x"]=17},["AppMarket.app"]={["y"]=2,["x"]=31},["Weather.app"]={["y"]=16,["x"]=129},["Camera.app"]={["y"]=2,["x"]=87},["Battleship.app"]={["y"]=2,["x"]=45}} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DPrint.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DPrint.app/Main.lua new file mode 100755 index 00000000..80a24a05 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DPrint.app/Main.lua @@ -0,0 +1,764 @@ + +local component = require("component") +local event = require("event") +local unicode = require("unicode") +local serialization = require("serialization") +local fs = require("filesystem") + +local color = require("color") +local buffer = require("doubleBuffering") +local context = require("context") +local bigLetters = require("bigLetters") +local ecs = require("ECSAPI") + +local printer +local gpu = component.gpu +local hologramAvailable = component.isAvailable("hologram") + +------------------------------------------------------------------------------------------------------------------------ + +if component.isAvailable("printer3d") then + printer = component.printer3d +else + ecs.error("Этой программе требуется 3D-принтер для работы.") + return +end + +------------------------------------------------------------------------------------------------------------------------ + +local colors = { + drawingZoneCYKA = 0xCCCCCC, + drawingZoneBackground = 0xFFFFFF, + drawingZoneStartPoint = 0x262626, + drawingZoneEndPoint = 0x555555, + drawingZoneSelection = 0xFF5555, + toolbarBackground = 0xEEEEEE, + toolbarText = 0x262626, + toolbarKeyText = 0x000000, + toolbarValueText = 0x666666, + toolbarBigLetters = 0x262626, + shapeNumbersText = 0xFFFFFF, + shapeNumbersBackground = 0xAAAAAA, + shapeNumbersActiveBackground = ecs.colors.blue, + shapeNumbersActiveText = 0xFFFFFF, + toolbarInfoBackground = 0x262626, + toolbarInfoText = 0xFFFFFF, + toolbarButtonBackground = 0xCCCCCC, + toolbarButtonText = 0x262626, +} + +local xOld, yOld = gpu.getResolution() +local xSize, ySize = 160, 50 +gpu.setResolution(160, 50) +buffer.flush() + +local widthOfToolbar = 33 +local xToolbar = xSize - widthOfToolbar + 1 +local widthOfDrawingCYKA = xSize - widthOfToolbar + +local currentLayer = 1 +local currentShape = 1 +local maxShapeCount = printer.getMaxShapeCount() +if maxShapeCount > 24 then maxShapeCount = 24 end +local currentMode = 1 +local modes = { + "неактивная", + "активная" +} +local currentTexture = "planks_oak" +local currentTint = ecs.colors.orange +local useTint = false +local showLayerOnHologram = true + +local pixelWidth = 6 +local pixelHeight = 3 +local drawingZoneWidth = pixelWidth * 16 +local drawingZoneHeight = pixelHeight * 16 +local xDrawingZone = math.floor(widthOfDrawingCYKA / 2 - drawingZoneWidth / 2) +local yDrawingZone = 3 + +local shapeColors = {} +local HUE = 0 +local HUEAdder = math.floor(360 / maxShapeCount) +for i = 1, maxShapeCount do + shapeColors[i] = color.HSBToInteger(HUE, 1, 1) + HUE = HUE + HUEAdder +end +HUE, HUEAdder = nil, nil + +local model = {} + +------------------------------------------------------------------------------------------------------------------------ + +local function swap(a, b) + return b, a +end + +local function correctShapeCoords(shapeNumber) + if model.shapes[shapeNumber] then + if model.shapes[shapeNumber][1] >= model.shapes[currentShape][4] then + model.shapes[shapeNumber][1], model.shapes[currentShape][4] = swap(model.shapes[currentShape][1], model.shapes[currentShape][4]) + model.shapes[shapeNumber][1] = model.shapes[shapeNumber][1] - 1 + model.shapes[shapeNumber][4] = model.shapes[shapeNumber][4] + 1 + -- ecs.error("СУКА") + end + if model.shapes[shapeNumber][2] >= model.shapes[currentShape][5] then + model.shapes[shapeNumber][2], model.shapes[currentShape][5] = swap(model.shapes[currentShape][2], model.shapes[currentShape][5]) + model.shapes[shapeNumber][2] = model.shapes[shapeNumber][2] - 1 + model.shapes[shapeNumber][5] = model.shapes[shapeNumber][5] + 1 + -- ecs.error("СУКА2") + end + if model.shapes[shapeNumber][3] >= model.shapes[currentShape][6] then + model.shapes[shapeNumber][3], model.shapes[currentShape][6] = swap(model.shapes[currentShape][3], model.shapes[currentShape][6]) + model.shapes[shapeNumber][3] = model.shapes[shapeNumber][3] - 1 + model.shapes[shapeNumber][6] = model.shapes[shapeNumber][6] + 1 + -- ecs.error("СУКА3") + end + end +end + +local function loadShapeParameters() + if model.shapes[currentShape] then + currentTexture = model.shapes[currentShape].texture + if model.shapes[currentShape].tint then + currentTint = model.shapes[currentShape].tint + useTint = true + else + useTint = false + end + end +end + +local function fixModelArray() + model.label = model.label or "Sample label" + model.tooltip = model.tooltip or "Sample tooltip" + model.lightLevel = model.lightLevel or 0 + model.emitRedstone = model.emitRedstone or false + model.buttonMode = model.buttonMode or false + model.collidable = model.collidable or {true, true} + model.shapes = model.shapes or {} + + currentLayer = 1 + currentShape = 1 + currentMode = 1 + loadShapeParameters() +end + +--Объекты для тача +local obj = {} +local function newObj(class, name, ...) + obj[class] = obj[class] or {} + obj[class][name] = {...} +end + +local function drawShapeNumbers(x, y) + local counter = 1 + local xStart = x + + for j = 1, 4 do + for i = 1, 6 do + if currentShape == counter then + newObj("ShapeNumbers", counter, buffer.button(x, y, 4, 1, shapeColors[counter], 0xFFFFFF - shapeColors[counter], tostring(counter))) + -- newObj("ShapeNumbers", counter, buffer.button(x, y, 4, 1, colors.shapeNumbersActiveBackground, colors.shapeNumbersActiveText, tostring(counter))) + else + newObj("ShapeNumbers", counter, buffer.button(x, y, 4, 1, colors.shapeNumbersBackground, colors.shapeNumbersText, tostring(counter))) + end + + x = x + 5 + counter = counter + 1 + if counter > maxShapeCount then return end + end + x = xStart + y = y + 2 + end +end + +local function toolBarInfoLine(y, text) + buffer.square(xToolbar, y, widthOfToolbar, 1, colors.toolbarInfoBackground, 0xFFFFFF, " ") + buffer.text(xToolbar + 1, y, colors.toolbarInfoText, text) +end + +local function centerText(y, color, text) + local x = math.floor(xToolbar + widthOfToolbar / 2 - unicode.len(text) / 2) + buffer.text(x, y, color, text) +end + +local function addButton(y, back, fore, text) + newObj("ToolbarButtons", text, buffer.button(xToolbar + 2, y, widthOfToolbar - 4, 3, back, fore, text)) +end + +local function printKeyValue(x, y, keyColor, valueColor, key, value, limit) + local totalLength = unicode.len(key .. ": " .. value) + if totalLength > limit then + value = unicode.sub(value, 1, limit - unicode.len(key .. ": ") - 1) .. "…" + end + buffer.text(x, y, keyColor, key .. ":") + buffer.text(x + unicode.len(key) + 2, y, valueColor, value) +end + +local function getShapeCoords() + local coords = "элемент не создан" + if model.shapes[currentShape] then + coords = "(" .. model.shapes[currentShape][1] .. "," .. model.shapes[currentShape][2] .. "," .. model.shapes[currentShape][3] .. ");(" .. model.shapes[currentShape][4] .. "," .. model.shapes[currentShape][5] .. "," .. model.shapes[currentShape][6] .. ")" + end + return coords +end + +local function fixNumber(number) + if number < 10 then number = "0" .. number end + return tostring(number) +end + +local function drawToolbar() + buffer.square(xToolbar, 1, widthOfToolbar, ySize, colors.toolbarBackground, 0xFFFFFF, " ") + + local x = xToolbar + 8 + local y = 3 + + --Текущий слой + bigLetters.drawText(x, y, colors.toolbarBigLetters, fixNumber(currentLayer)) + y = y + 6 + centerText(y, colors.toolbarText, "Текущий слой") + + --Управление элементом + y = y + 2 + x = xToolbar + 2 + toolBarInfoLine(y, "Управление моделью"); y = y + 2 + printKeyValue(x, y, colors.toolbarKeyText, colors.toolbarValueText, "Имя", model.label, widthOfToolbar - 4); y = y + 1 + printKeyValue(x, y, colors.toolbarKeyText, colors.toolbarValueText, "Описание", model.tooltip, widthOfToolbar - 4); y = y + 1 + printKeyValue(x, y, colors.toolbarKeyText, colors.toolbarValueText, "Как кнопка", tostring(model.buttonMode), widthOfToolbar - 4); y = y + 1 + printKeyValue(x, y, colors.toolbarKeyText, colors.toolbarValueText, "Редстоун-сигнал", tostring(model.emitRedstone), widthOfToolbar - 4); y = y + 1 + printKeyValue(x, y, colors.toolbarKeyText, colors.toolbarValueText, "Коллизия", tostring(model.collidable[currentMode]), widthOfToolbar - 4); y = y + 1 + printKeyValue(x, y, colors.toolbarKeyText, colors.toolbarValueText, "Уровень света", tostring(model.lightLevel), widthOfToolbar - 4); y = y + 1 + y = y + 1 + printKeyValue(x, y, ecs.colors.blue, colors.toolbarValueText, "Состояние", modes[currentMode], widthOfToolbar - 4); y = y + 1 + y = y + 1 + addButton(y, colors.toolbarButtonBackground, colors.toolbarButtonText, "Изменить параметры"); y = y + 4 + addButton(y, colors.toolbarButtonBackground, colors.toolbarButtonText, "Напечатать"); y = y + 4 + toolBarInfoLine(y, "Управление элементом " .. currentShape); y = y + 2 + printKeyValue(x, y, colors.toolbarKeyText, colors.toolbarValueText, "Текстура", tostring(currentTexture), widthOfToolbar - 4); y = y + 1 + printKeyValue(x, y, colors.toolbarKeyText, colors.toolbarValueText, "Оттенок", ecs.HEXtoString(currentTint, 6, true), widthOfToolbar - 4); y = y + 1 + printKeyValue(x, y, colors.toolbarKeyText, colors.toolbarValueText, "Использовать оттенок", tostring(useTint), widthOfToolbar - 4); y = y + 1 + printKeyValue(x, y, colors.toolbarKeyText, colors.toolbarValueText, "Позиция", getShapeCoords(), widthOfToolbar - 4); y = y + 2 + addButton(y, colors.toolbarButtonBackground, colors.toolbarButtonText, "Изменить параметры "); y = y + 4 + + --Элементы + toolBarInfoLine(y, "Выбор элемента"); y = y + 2 + drawShapeNumbers(x, y) + y = y + 8 +end + +local function drawTopMenu(selected) + obj["TopMenu"] = ecs.drawTopMenu(1, 1, xSize - widthOfToolbar, colors.toolbarBackground, selected, {"Файл", 0x262626}, {"Проектор", 0x262626}, {"О программе", 0x262626}) +end + +local function renderCurrentLayerOnHologram(xStart, yStart, zStart) + if showLayerOnHologram then + for i = yStart, yStart + 16 do + component.hologram.set(xStart - 1, i, zStart + (16 - currentLayer), 3) + component.hologram.set(xStart + 16, i, zStart + (16 - currentLayer), 3) + end + + for i = (xStart-1), (xStart + 16) do + component.hologram.set(i, yStart - 1, zStart + (16 - currentLayer), 3) + component.hologram.set(i, yStart + 16, zStart + (16 - currentLayer), 3) + end + end +end + +local function drawModelOnHologram() + if hologramAvailable then + local xStart, yStart, zStart = 16,4,16 + component.hologram.clear() + + for shape in pairs(model.shapes) do + if (currentMode == 2 and model.shapes[shape].state) or (currentMode == 1 and not model.shapes[shape].state) then + if model.shapes[shape] then + for x = model.shapes[shape][1], model.shapes[shape][4] - 1 do + for y = model.shapes[shape][2], model.shapes[shape][5] - 1 do + for z = model.shapes[shape][3], model.shapes[shape][6] - 1 do + --Эта хуйня для того, чтобы в разных режимах не ебало мозг + if (model.shapes[shape].state and currentMode == 2) or (not model.shapes[shape].state and currentMode == 1) then + if shape == currentShape then + component.hologram.set(xStart + x, yStart + y, zStart + 15 - z, 2) + else + component.hologram.set(xStart + x, yStart + y, zStart + 15 - z, 1) + end + end + end + end + end + end + end + end + + renderCurrentLayerOnHologram(xStart, yStart, zStart) + end +end + +local function printModel(count) + printer.reset() + printer.setLabel(model.label) + printer.setTooltip(model.tooltip) + printer.setCollidable(model.collidable[1], model.collidable[2]) + printer.setLightLevel(model.lightLevel) + printer.setRedstoneEmitter(model.emitRedstone) + printer.setButtonMode(model.buttonMode) + + for i in pairs(model.shapes) do + printer.addShape( + model.shapes[i][1], + (model.shapes[i][2]), + (model.shapes[i][3]), + + model.shapes[i][4], + (model.shapes[i][5]), + (model.shapes[i][6]), + + model.shapes[i].texture, + model.shapes[i].state, + model.shapes[i].tint + ) + end + + local success, reason = printer.commit(count) + if not success then + ecs.error("Ошибка печати: " .. reason) + end +end + +local function drawPixel(x, y, width, height, color, trasparency) + buffer.square(xDrawingZone + x * pixelWidth - pixelWidth, yDrawingZone + y * pixelHeight - pixelHeight, width * pixelWidth, height * pixelHeight, color, 0xFFFFFF, " ", trasparency) +end + +local function setka() + drawPixel(1, 1, 16, 16, colors.drawingZoneBackground) + local shade = colors.drawingZoneBackground - 0x111111 + + for j = 1, 16 do + for i = 1, 16 do + if j % 2 == 0 then + if i % 2 == 0 then + drawPixel(i, j, 1, 1, shade) + end + else + if i % 2 ~= 0 then + drawPixel(i, j, 1, 1, shade) + end + end + end + end +end + +local function drawDrawingZone() + + setka() + + local selectionStartPoint = {} + local selectionEndPoint = {} + local trasparency = 70 + + for shape in pairs(model.shapes) do + + --Если по состояниям все заебок + if ((model.shapes[shape].state and currentMode == 2) or (not model.shapes[shape].state and currentMode == 1)) then + + selectionStartPoint.x = model.shapes[shape][1] + 1 + selectionStartPoint.y = model.shapes[shape][2] + 1 + selectionStartPoint.z = model.shapes[shape][3] + 1 + selectionEndPoint.x = model.shapes[shape][4] + selectionEndPoint.y = model.shapes[shape][5] + selectionEndPoint.z = model.shapes[shape][6] + local yDifference = selectionEndPoint.y - selectionStartPoint.y + 1 + + if currentLayer >= selectionStartPoint.z and currentLayer <= selectionEndPoint.z then + if shape ~= currentShape then + local h, s, b = color.IntegerToHSB(shapeColors[shape]) + s = 0.3 + -- ecs.error("РИСУЮ") + drawPixel(selectionStartPoint.x, 18 - selectionStartPoint.y - yDifference, selectionEndPoint.x - selectionStartPoint.x + 1, yDifference, color.HSBToInteger(h, s, b)) + -- drawPixel(selectionStartPoint.x, selectionStartPoint.z, selectionEndPoint.x - selectionStartPoint.x + 1, selectionEndPoint.z - selectionStartPoint.z + 1, shapeColors[shape], trasparency) + else + drawPixel(selectionStartPoint.x, 18 - selectionStartPoint.y - yDifference, selectionEndPoint.x - selectionStartPoint.x + 1, yDifference, shapeColors[shape]) + + --Точки + if selectionStartPoint.z == currentLayer then + drawPixel(selectionStartPoint.x, 17 - selectionStartPoint.y, 1, 1, colors.drawingZoneStartPoint) + end + + if selectionEndPoint.z == currentLayer then + drawPixel(selectionEndPoint.x, 17 - selectionEndPoint.y, 1, 1, colors.drawingZoneEndPoint) + end + end + end + end + end +end + +local function drawAll() + buffer.square(1, 2, xSize, ySize, colors.drawingZoneCYKA, 0xFFFFFF, " ") + drawDrawingZone() + drawToolbar() + buffer.draw() + drawTopMenu(0) +end + +local function save(path) + fs.makeDirectory(fs.path(path) or "") + local file = io.open(path, "w") + file:write(serialization.serialize(model)) + file:close() +end + +local function open(path) + if fs.exists(path) then + if ecs.getFileFormat(path) == ".3dm" then + local file = io.open(path, "r") + model = serialization.unserialize(file:read("*a")) + fixModelArray() + file:close() + drawAll() + drawModelOnHologram() + else + ecs.error("Файл имеет неизвестный формат. Поддерживаются только модели в формате .3dm.") + end + else + ecs.error("Файл \"" .. path .. "\" не существует") + end +end + +------------------------------------------------------------------------------------------------------------------------ + +model = {} +fixModelArray() + +local args = {...} +if args[1] and fs.exists(args[1]) then + open(args[1]) +end + +drawAll() +drawModelOnHologram() + +------------------------------------------------------------------------------------------------------------------------ + +local startPointSelected = false +local xShapeStart, yShapeStart, zShapeStart, xShapeEnd, yShapeEnd, zShapeEnd + +while true do + local e = { event.pull() } + if e[1] == "touch" then + --Если кликнули в зону рисования + if ecs.clickedAtArea(e[3], e[4], xDrawingZone, yDrawingZone, xDrawingZone + drawingZoneWidth - 1, yDrawingZone + drawingZoneHeight - 1) then + if not startPointSelected then + xShapeStart = math.ceil((e[3] - xDrawingZone + 1) / pixelWidth) + yShapeStart = math.ceil((e[4] - yDrawingZone + 1) / pixelHeight) + zShapeStart = currentLayer + + startPointSelected = true + model.shapes[currentShape] = nil + -- buffer.square(xDrawingZone, yDrawingZone, drawingZoneWidth, drawingZoneHeight, colors.drawingZoneBackground, 0xFFFFFF, " ") + + drawPixel(xShapeStart, yShapeStart, 1, 1, colors.drawingZoneStartPoint) + + buffer.draw() + else + xShapeEnd = math.ceil((e[3] - xDrawingZone + 1) / pixelWidth) + yShapeEnd = math.ceil((e[4] - yDrawingZone + 1) / pixelHeight) + zShapeEnd = currentLayer + + drawPixel(xShapeEnd, yShapeEnd, 1, 1, colors.drawingZoneEndPoint) + startPointSelected = false + + model.shapes[currentShape] = { + xShapeStart - 1, + 17 - yShapeStart - 1, + zShapeStart - 1, + + xShapeEnd, + 17 - yShapeEnd, + zShapeEnd, + + texture = currentTexture, + } + + model.shapes[currentShape].state = nil + model.shapes[currentShape].tint = nil + if currentMode == 2 then model.shapes[currentShape].state = true end + if useTint then model.shapes[currentShape].tint = currentTint end + + correctShapeCoords(currentShape) + + drawAll() + drawModelOnHologram() + end + else + for key in pairs(obj.ShapeNumbers) do + if ecs.clickedAtArea(e[3], e[4], obj.ShapeNumbers[key][1], obj.ShapeNumbers[key][2], obj.ShapeNumbers[key][3], obj.ShapeNumbers[key][4]) then + currentShape = key + loadShapeParameters() + drawAll() + drawModelOnHologram() + break + end + end + + for key in pairs(obj.ToolbarButtons) do + if ecs.clickedAtArea(e[3], e[4], obj.ToolbarButtons[key][1], obj.ToolbarButtons[key][2], obj.ToolbarButtons[key][3], obj.ToolbarButtons[key][4]) then + buffer.button(obj.ToolbarButtons[key][1], obj.ToolbarButtons[key][2], widthOfToolbar - 4, 3, ecs.colors.blue, 0xFFFFFF, key) + buffer.draw() + os.sleep(0.2) + + if key == "Напечатать" then + local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "Напечатать"}, + {"EmptyLine"}, + {"Slider", 0xFFFFFF, ecs.colors.orange, 1, 64, 1, "", " штук"}, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0xffffff, "OK"}, {0x999999, 0xffffff, "Отмена"}} + ) + + if data[2] == "OK" then + printModel(data[1]) + end + + elseif key == "Изменить параметры" then + local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "Параметры модели"}, + {"EmptyLine"}, + {"Input", 0xFFFFFF, ecs.colors.orange, model.label}, + {"Input", 0xFFFFFF, ecs.colors.orange, model.tooltip}, + {"Selector", 0xFFFFFF, ecs.colors.orange, "Неактивная", "Активная"}, + {"EmptyLine"}, + {"Switch", ecs.colors.orange, 0xffffff, 0xFFFFFF, "Как кнопка", model.buttonMode}, + {"EmptyLine"}, + {"Switch", ecs.colors.orange, 0xffffff, 0xFFFFFF, "Редстоун-сигнал", model.emitRedstone}, + {"EmptyLine"}, + {"Switch", ecs.colors.orange, 0xffffff, 0xFFFFFF, "Коллизия", model.collidable[currentMode]}, + {"EmptyLine"}, + {"Slider", 0xFFFFFF, ecs.colors.orange, 0, 15, model.lightLevel, "Уровень света: ", ""}, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0xffffff, "OK"}, {0x999999, 0xffffff, "Отмена"}} + ) + + if data[8] == "OK" then + model.label = data[1] or "Sample label" + model.tooltip = data[2] or "Sample tooltip" + if data[3] == "Активная" then + currentMode = 2 + else + currentMode = 1 + end + model.buttonMode = data[4] + model.emitRedstone = data[5] + model.collidable[currentMode] = data[6] + model.lightLevel = data[7] + end + + elseif key == "Изменить параметры " then + local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "Параметры элемента"}, + {"EmptyLine"}, + {"Input", 0xFFFFFF, ecs.colors.orange, currentTexture}, + {"Color", "Оттенок", currentTint}, + {"EmptyLine"}, + {"Switch", ecs.colors.orange, 0xffffff, 0xFFFFFF, "Использовать оттенок", useTint}, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0xffffff, "OK"}, {0x999999, 0xffffff, "Отмена"}} + ) + + if data[4] == "OK" then + currentTexture = data[1] + currentTint = data[2] + useTint = data[3] + + if model.shapes[currentShape] then + model.shapes[currentShape].texture = currentTexture + if useTint then + model.shapes[currentShape].tint = currentTint + else + model.shapes[currentShape].tint = nil + end + end + end + end + + drawAll() + drawModelOnHologram() + break + end + end + + for key in pairs(obj.TopMenu) do + if ecs.clickedAtArea(e[3], e[4], obj.TopMenu[key][1], obj.TopMenu[key][2], obj.TopMenu[key][3], obj.TopMenu[key][4]) then + drawTopMenu(obj.TopMenu[key][5]) + -- buffer.button(obj.TopMenu[key][1] - 1, obj.TopMenu[key][2], unicode.len(key) + 2, 1, ecs.colors.blue, 0xFFFFFF, key) + -- buffer.draw() + + local action + if key == "Файл" then + action = context.menu(obj.TopMenu[key][1] - 1, obj.TopMenu[key][2] + 1, {"Новый"}, "-", {"Открыть"}, {"Сохранить"}, "-", {"Выход"}) + elseif key == "Проектор" then + action = context.menu(obj.TopMenu[key][1] - 1, obj.TopMenu[key][2] + 1, {"Масштаб", not hologramAvailable}, {"Отступ проекции", not hologramAvailable}, {"Изменить палитру", not hologramAvailable}, "-", {"Включить показ слоя", not hologramAvailable}, {"Отключить показ слоя", not hologramAvailable}, "-", {"Включить вращение", not hologramAvailable}, {"Отключить вращение", not hologramAvailable}) + elseif key == "О программе" then + ecs.universalWindow("auto", "auto", 36, 0x262626, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "3DPrint v3.0"}, + {"EmptyLine"}, + {"CenterText", 0xFFFFFF, "Автор:"}, + {"CenterText", 0xBBBBBB, "Тимофеев Игорь"}, + {"CenterText", 0xBBBBBB, "vk.com/id7799889"}, + {"EmptyLine"}, + {"CenterText", 0xFFFFFF, "Тестеры:"}, + {"CenterText", 0xBBBBBB, "Семёнов Сeмён"}, + {"CenterText", 0xBBBBBB, "vk.com/day_z_utes"}, + {"CenterText", 0xBBBBBB, "Бесфамильный Яков"}, + {"CenterText", 0xBBBBBB, "vk.com/mathem"}, + {"CenterText", 0xBBBBBB, "Егор Палиев"}, + {"CenterText", 0xBBBBBB, "vk.com/mrherobrine"}, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0xffffff, "OK"}} + ) + end + + if action == "Сохранить" then + local data = ecs.universalWindow("auto", "auto", 30, 0x262626, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "Сохранить как"}, + {"EmptyLine"}, + {"Input", 0xFFFFFF, ecs.colors.orange, "Путь"}, + {"Selector", 0xFFFFFF, ecs.colors.orange, ".3dm"}, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0xffffff, "OK"}, {0x999999, 0xffffff, "Отмена"}} + ) + if data[3] == "OK" then + data[1] = data[1] or "Untitled" + local filename = data[1] .. data[2] + save(filename) + end + elseif action == "Открыть" then + local data = ecs.universalWindow("auto", "auto", 30, 0x262626, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "Открыть"}, + {"EmptyLine"}, + {"Input", 0xFFFFFF, ecs.colors.orange, "Путь"}, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0xffffff, "OK"}, {0x999999, 0xffffff, "Отмена"}} + ) + if data[2] == "OK" then + open(data[1]) + end + elseif action == "Новый" then + model = {} + fixModelArray() + drawAll() + drawModelOnHologram() + elseif action == "Выход" then + gpu.setResolution(xOld, yOld) + buffer.flush() + buffer.draw(true) + if hologramAvailable then component.hologram.clear() end + return + elseif action == "Масштаб" then + local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "Изменить масштаб"}, + {"EmptyLine"}, + {"Slider", ecs.colors.white, ecs.colors.orange, 1, 100, math.ceil(component.hologram.getScale() * 100 / 4), "", "%"}, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0xffffff, "OK"}, {0x999999, 0xffffff, "Отмена"}} + ) + + if data[2] == "OK" then + component.hologram.setScale(data[1] * 4 / 100) + end + elseif action == "Отступ проекции" then + local translation = { component.hologram.getTranslation() } + local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "Отступ проекции"}, + {"EmptyLine"}, + {"CenterText", 0xFFFFFF, "Эти параметры позволяют проецировать"}, + {"CenterText", 0xFFFFFF, "голограмму на некотором расстоянии от"}, + {"CenterText", 0xFFFFFF, "проектора. Удобно, если вы хотите спрятать"}, + {"CenterText", 0xFFFFFF, "проектор от чужих глаз."}, + {"EmptyLine"}, + {"Slider", 0xFFFFFF, ecs.colors.orange, 1, 100, translation[1] * 100, "Ось X: ", "%"}, + {"Slider", 0xFFFFFF, ecs.colors.orange, 1, 100, translation[2] * 100, "Ось Y: ", "%"}, + {"Slider", 0xFFFFFF, ecs.colors.orange, 1, 100, translation[3] * 100, "Ось Z: ", "%"}, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0xffffff, "OK"}, {0x999999, 0xffffff, "Отмена"}} + ) + + if data[4] == "OK" then + component.hologram.setTranslation(data[1] / 100, data[2] / 100, data[3] / 100) + end + elseif action == "Изменить палитру" then + local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "Палитра проектора"}, + {"EmptyLine"}, + {"Color", "Цвет активного элемента", component.hologram.getPaletteColor(2)}, + {"Color", "Цвет других элементов", component.hologram.getPaletteColor(1)}, + {"Color", "Цвет рамки высоты", component.hologram.getPaletteColor(3)}, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0xffffff, "OK"}, {0x999999, 0xffffff, "Отмена"}} + ) + + if data[4] == "OK" then + component.hologram.setPaletteColor(2, data[1]) + component.hologram.setPaletteColor(1, data[2]) + component.hologram.setPaletteColor(3, data[3]) + end + elseif action == "Включить показ слоя" then + showLayerOnHologram = true + drawModelOnHologram() + elseif action == "Отключить показ слоя" then + showLayerOnHologram = false + drawModelOnHologram() + elseif action == "Включить вращение" then + component.hologram.setRotationSpeed(15, 0, 23, 0) + elseif action == "Отключить вращение" then + component.hologram.setRotationSpeed(0, 0, 0, 0) + end + + drawTopMenu(0) + end + end + end + elseif e[1] == "scroll" then + if e[5] == 1 then + if currentLayer < 16 then + currentLayer = currentLayer + 1 + drawAll() + drawModelOnHologram() + end + else + if currentLayer > 1 then + currentLayer = currentLayer - 1 + drawAll() + drawModelOnHologram() + end + end + end +end + + + + + + + + + + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DPrint.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DPrint.app/Resources/About/Russian.txt new file mode 100755 index 00000000..26c56000 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DPrint.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Это профессиональный инструмент для создания и распечатки моделей на 3D-принтере. Поддерживает все возможные функции принтера без исключения. Для работы требуется сам принтер и, по желанию, голографический проектор 2 уровня. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DPrint.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DPrint.app/Resources/Icon.pic new file mode 100755 index 00000000..a95c7813 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DPrint.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DTest.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DTest.app/Main.lua new file mode 100755 index 00000000..66d43c37 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DTest.app/Main.lua @@ -0,0 +1,539 @@ + +-------------------------------------------------------- Libraries -------------------------------------------------------- + +-- package.loaded["GUI"] = nil +-- package.loaded["doubleBuffering"] = nil +-- package.loaded["vector"] = nil +-- package.loaded["OpenComputersGL/Main"] = nil +-- package.loaded["OpenComputersGL/Materials"] = nil +-- package.loaded["OpenComputersGL/Renderer"] = nil +-- package.loaded["MeowEngine/Main"] = nil + +local color = require("color") +local computer = require("computer") +local buffer = require("doubleBuffering") +local event = require("event") +local GUI = require("GUI") +local vector = require("vector") +local materials = require("OpenComputersGL/Materials") +local renderer = require("OpenComputersGL/Renderer") +local OCGL = require("OpenComputersGL/Main") +local meowEngine = require("MeowEngine/Main") + +---------------------------------------------- Anus preparing ---------------------------------------------- + +-- /MineOS/Desktop/3DTest.app/3DTest.lua + +buffer.flush() +meowEngine.intro(vector.newVector3(0, 0, 0), 20) + +local mainContainer = GUI.fullScreenContainer() +local scene = meowEngine.newScene(0x1D1D1D) + +scene.renderMode = OCGL.renderModes.flatShading +scene.auxiliaryMode = OCGL.auxiliaryModes.disabled + +scene.camera:translate(-2.5, 8.11, -19.57) +scene.camera:rotate(math.rad(30), 0, 0) +scene:addLight(meowEngine.newLight(vector.newVector3(0, 20, 0), 1.0, 200)) + +---------------------------------------------- Constants ---------------------------------------------- + +local blockSize = 5 +local rotationAngle = math.rad(5) +local translationOffset = 1 + +---------------------------------------------- Voxel-world system ---------------------------------------------- + +local world = {{{}}} + +local worldMesh = scene:addObject( + meowEngine.newMesh( + vector.newVector3(0, 0, 0), { }, { }, + materials.newSolidMaterial(0xFF00FF) + ) +) + +local function checkBlock(x, y, z) + if world[z] and world[z][y] and world[z][y][x] then + return true + end + return false +end + +local function setBlock(x, y, z, value) + world[z] = world[z] or {} + world[z][y] = world[z][y] or {} + world[z][y][x] = value +end + +local blockSides = { + front = 1, + left = 2, + back = 3, + right = 4, + up = 5, + down = 6 +} + +local function renderWorld() + worldMesh.vertices = {} + worldMesh.triangles = {} + + for z in pairs(world) do + for y in pairs(world[z]) do + for x in pairs(world[z][y]) do + local firstVertexIndex = #worldMesh.vertices + 1 + local xBlock, yBlock, zBlock = (x - 1) * blockSize, (y - 1) * blockSize, (z - 1) * blockSize + local material = materials.newSolidMaterial(world[z][y][x]) + + table.insert(worldMesh.vertices, vector.newVector3(xBlock, yBlock, zBlock)) + table.insert(worldMesh.vertices, vector.newVector3(xBlock, yBlock + blockSize, zBlock)) + table.insert(worldMesh.vertices, vector.newVector3(xBlock + blockSize, yBlock + blockSize, zBlock)) + table.insert(worldMesh.vertices, vector.newVector3(xBlock + blockSize, yBlock, zBlock)) + table.insert(worldMesh.vertices, vector.newVector3(xBlock, yBlock, zBlock + blockSize)) + table.insert(worldMesh.vertices, vector.newVector3(xBlock, yBlock + blockSize, zBlock + blockSize)) + table.insert(worldMesh.vertices, vector.newVector3(xBlock + blockSize, yBlock + blockSize, zBlock + blockSize)) + table.insert(worldMesh.vertices, vector.newVector3(xBlock + blockSize, yBlock, zBlock + blockSize)) + + -- Front (1, 2) + if not checkBlock(x, y, z - 1) then + table.insert(worldMesh.triangles, OCGL.newIndexedTriangle(firstVertexIndex, firstVertexIndex + 1, firstVertexIndex + 2, material)) + table.insert(worldMesh.triangles, OCGL.newIndexedTriangle(firstVertexIndex + 3, firstVertexIndex, firstVertexIndex + 2, material)) + end + + -- Left (3, 4) + if not checkBlock(x - 1, y, z) then + table.insert(worldMesh.triangles, OCGL.newIndexedTriangle(firstVertexIndex + 5, firstVertexIndex + 1, firstVertexIndex + 4, material)) + table.insert(worldMesh.triangles, OCGL.newIndexedTriangle(firstVertexIndex + 1, firstVertexIndex, firstVertexIndex + 4, material)) + end + + -- Back (5, 6) + if not checkBlock(x, y, z + 1) then + table.insert(worldMesh.triangles, OCGL.newIndexedTriangle(firstVertexIndex + 6, firstVertexIndex + 5, firstVertexIndex + 7, material)) + table.insert(worldMesh.triangles, OCGL.newIndexedTriangle(firstVertexIndex + 5, firstVertexIndex + 4, firstVertexIndex + 7, material)) + end + + -- Right (7, 8) + if not checkBlock(x + 1, y, z) then + table.insert(worldMesh.triangles, OCGL.newIndexedTriangle(firstVertexIndex + 3, firstVertexIndex + 2, firstVertexIndex + 6, material)) + table.insert(worldMesh.triangles, OCGL.newIndexedTriangle(firstVertexIndex + 7, firstVertexIndex + 3, firstVertexIndex + 6, material)) + end + + -- Up (9, 10) + if not checkBlock(x, y + 1, z) then + table.insert(worldMesh.triangles, OCGL.newIndexedTriangle(firstVertexIndex + 1, firstVertexIndex + 5, firstVertexIndex + 6, material)) + table.insert(worldMesh.triangles, OCGL.newIndexedTriangle(firstVertexIndex + 2, firstVertexIndex + 1, firstVertexIndex + 6, material)) + end + + -- Down (11, 12) + if not checkBlock(x, y - 1, z) then + table.insert(worldMesh.triangles, OCGL.newIndexedTriangle(firstVertexIndex + 4, firstVertexIndex, firstVertexIndex + 7, material)) + table.insert(worldMesh.triangles, OCGL.newIndexedTriangle(firstVertexIndex, firstVertexIndex + 3, firstVertexIndex + 7, material)) + end + end + end + end +end + +-- Mode 1 +local hue, hueStep = 0, 360 / 9 +for z = -1, 1 do + for x = -1, 1 do + if not (x == 0 and z == 0) then + setBlock(x, 0, z, color.HSBToInteger(hue, 1, 1)) + hue = hue + hueStep + end + end +end + +-- -- Mode 2 +-- for z = 1, 7 do +-- for x = -3, 3 do +-- setBlock(x, 0, z, 0xFFFFFF) +-- end +-- end + +---------------------------------------------- Cat ---------------------------------------------- + +-- scene:addObject(meowEngine.newPolyCatMesh(vector.newVector3(0, 5, 0), 5)) +-- scene:addObject(meowEngine.newFloatingText(vector.newVector3(0, -2, 0), 0xEEEEEE, "Тест плавающего текста")) + +---------------------------------------------- Texture ---------------------------------------------- + +-- scene.camera:translate(0, 20, 0) +-- scene.camera:rotate(math.rad(90), 0, 0) +-- local texturedPlane = scene:addObject(meowEngine.newTexturedPlane(vector.newVector3(0, 0, 0), 20, 20, materials.newDebugTexture(16, 16, 40))) + +---------------------------------------------- Wave ---------------------------------------------- + +-- local xCells, yCells = 4, 1 +-- local plane = meowEngine.newPlane(vector.newVector3(0, 0, 0), 40, 15, xCells, yCells, materials.newSolidMaterial(0xFFFFFF)) +-- plane.nextWave = function(mesh) +-- for xCell = 1, xCells do +-- for yCell = 1, yCells do + +-- end +-- end +-- end + +---------------------------------------------- Fractal field ---------------------------------------------- + +-- local function createField(vector3Position, xCellCount, yCellCount, cellSize) +-- local totalWidth, totalHeight = xCellCount * cellSize, yCellCount * cellSize +-- local halfWidth, halfHeight = totalWidth / 2, totalHeight / 2 +-- xCellCount, yCellCount = xCellCount + 1, yCellCount + 1 +-- local vertices, triangles = {}, {} + +-- local vertexIndex = 1 +-- for yCell = 1, yCellCount do +-- for xCell = 1, xCellCount do +-- table.insert(vertices, vector.newVector3(xCell * cellSize - cellSize - halfWidth, yCell * cellSize - cellSize - halfHeight, 0)) + +-- if xCell < xCellCount and yCell < yCellCount then +-- table.insert(triangles, +-- OCGL.newIndexedTriangle( +-- vertexIndex, +-- vertexIndex + 1, +-- vertexIndex + xCellCount +-- ) +-- ) +-- table.insert(triangles, +-- OCGL.newIndexedTriangle( +-- vertexIndex + 1, +-- vertexIndex + xCellCount + 1, +-- vertexIndex + xCellCount +-- ) +-- ) +-- end + +-- vertexIndex = vertexIndex + 1 +-- end +-- end + +-- local mesh = meowEngine.newMesh(vector3Position, vertices, triangles,materials.newSolidMaterial(0xFF8888)) + +-- local function getRandomSignedInt(from, to) +-- return (math.random(0, 1) == 1 and 1 or -1) * (math.random(from, to)) +-- end + +-- local function getRandomDirection() +-- return getRandomSignedInt(5, 100) / 100 +-- end + +-- mesh.randomizeTrianglesColor = function(mesh, hueChangeSpeed, brightnessChangeSpeed, minimumBrightness) +-- mesh.hue = mesh.hue and mesh.hue + hueChangeSpeed or math.random(0, 360) +-- if mesh.hue > 359 then mesh.hue = 0 end + +-- for triangleIndex = 1, #mesh.triangles do +-- mesh.triangles[triangleIndex].brightness = mesh.triangles[triangleIndex].brightness and mesh.triangles[triangleIndex].brightness + getRandomSignedInt(1, brightnessChangeSpeed) or math.random(minimumBrightness, 100) +-- if mesh.triangles[triangleIndex].brightness > 100 then +-- mesh.triangles[triangleIndex].brightness = 100 +-- elseif mesh.triangles[triangleIndex].brightness < minimumBrightness then +-- mesh.triangles[triangleIndex].brightness = minimumBrightness +-- end +-- mesh.triangles[triangleIndex][4] = materials.newSolidMaterial(color.HSBToInteger(mesh.hue, 1, mesh.triangles[triangleIndex].brightness)) +-- end +-- end + +-- mesh.randomizeVerticesPosition = function(mesh, speed) +-- local vertexIndex = 1 +-- for yCell = 1, yCellCount do +-- for xCell = 1, xCellCount do +-- if xCell > 1 and xCell < xCellCount and yCell > 1 and yCell < yCellCount then +-- mesh.vertices[vertexIndex].offset = mesh.vertices[vertexIndex].offset or {0, 0} +-- mesh.vertices[vertexIndex].direction = mesh.vertices[vertexIndex].direction or {getRandomDirection(), getRandomDirection()} + +-- local newOffset = { +-- mesh.vertices[vertexIndex].direction[1] * (speed * cellSize), +-- mesh.vertices[vertexIndex].direction[1] * (speed * cellSize) +-- } + +-- for i = 1, 2 do +-- if math.abs(mesh.vertices[vertexIndex].offset[i] + newOffset[i]) < cellSize / 2 then +-- mesh.vertices[vertexIndex].offset[i] = mesh.vertices[vertexIndex].offset[i] + newOffset[i] +-- mesh.vertices[vertexIndex][i] = mesh.vertices[vertexIndex][i] + newOffset[i] +-- else +-- mesh.vertices[vertexIndex].direction[i] = getRandomDirection() +-- end +-- end +-- end +-- vertexIndex = vertexIndex + 1 +-- end +-- end +-- end + +-- return mesh +-- end + +-- local plane = createField(vector.newVector3(0, 0, 0), 8, 4, 4) +-- scene:addObject(plane) +-- plane:randomizeTrianglesColor(10, 10, 50) + +-------------------------------------------------------- Controls -------------------------------------------------------- + +local function move(x, y, z) + local moveVector = vector.newVector3(x, y, z) + OCGL.rotateVectorRelativeToXAxis(moveVector, scene.camera.rotation[1]) + OCGL.rotateVectorRelativeToYAxis(moveVector, scene.camera.rotation[2]) + scene.camera:translate(moveVector[1], moveVector[2], moveVector[3]) +end + +local function moveLight(x, y, z) + scene.lights[mainContainer.toolbar.lightSelectComboBox.selectedItem].position[1] = scene.lights[mainContainer.toolbar.lightSelectComboBox.selectedItem].position[1] + x + scene.lights[mainContainer.toolbar.lightSelectComboBox.selectedItem].position[2] = scene.lights[mainContainer.toolbar.lightSelectComboBox.selectedItem].position[2] + y + scene.lights[mainContainer.toolbar.lightSelectComboBox.selectedItem].position[3] = scene.lights[mainContainer.toolbar.lightSelectComboBox.selectedItem].position[3] + z +end + +local controls = { + -- F1 + [59 ] = function() mainContainer.toolbar.hidden = not mainContainer.toolbar.hidden; mainContainer.infoTextBox.hidden = not mainContainer.infoTextBox.hidden end, + -- Arrows + [200] = function() scene.camera:rotate(-rotationAngle, 0, 0) end, + [208] = function() scene.camera:rotate(rotationAngle, 0, 0) end, + [203] = function() scene.camera:rotate(0, -rotationAngle, 0) end, + [205] = function() scene.camera:rotate(0, rotationAngle, 0) end, + [16 ] = function() scene.camera:rotate(0, 0, rotationAngle) end, + [18 ] = function() scene.camera:rotate(0, 0, -rotationAngle) end, + -- WASD + [17 ] = function() move(0, 0, translationOffset) end, + [31 ] = function() move(0, 0, -translationOffset) end, + [30 ] = function() move(-translationOffset, 0, 0) end, + [32 ] = function() move(translationOffset, 0, 0) end, + -- RSHIFT, SPACE + [42 ] = function() move(0, -translationOffset, 0) end, + [57 ] = function() move(0, translationOffset, 0) end, + -- NUM 4 6 8 5 1 3 + [75 ] = function() moveLight(-translationOffset, 0, 0) end, + [77 ] = function() moveLight(translationOffset, 0, 0) end, + [72 ] = function() moveLight(0, 0, translationOffset) end, + [80 ] = function() moveLight(0, 0, -translationOffset) end, + [79 ] = function() moveLight(0, -translationOffset, 0) end, + [81 ] = function() moveLight(0, translationOffset, 0) end, +} + +-------------------------------------------------------- GUI -------------------------------------------------------- + +local OCGLView = GUI.object(1, 1, mainContainer.width, mainContainer.height) + +local function drawInvertedText(x, y, text) + local index = buffer.getIndex(x, y) + local background, foreground = buffer.rawGet(index) + buffer.rawSet(index, background, 0xFFFFFF - foreground, text) +end + +local function drawCross(x, y) + drawInvertedText(x - 2, y, "━") + drawInvertedText(x - 1, y, "━") + drawInvertedText(x + 2, y, "━") + drawInvertedText(x + 1, y, "━") + drawInvertedText(x, y - 1, "┃") + drawInvertedText(x, y + 1, "┃") +end + +OCGLView.draw = function(object) + mainContainer.oldClock = os.clock() + if world then renderWorld() end + scene:render() + if mainContainer.toolbar.zBufferSwitch.state then + renderer.visualizeDepthBuffer() + end + drawCross(renderer.viewport.xCenter, math.floor(renderer.viewport.yCenter / 2)) +end + +OCGLView.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + local targetVector = vector.newVector3(scene.camera.position[1], scene.camera.position[2], scene.camera.position[3] + 1000) + OCGL.rotateVectorRelativeToXAxis(targetVector, scene.camera.rotation[1]) + OCGL.rotateVectorRelativeToYAxis(targetVector, scene.camera.rotation[2]) + local objectIndex, triangleIndex, distance = meowEngine.sceneRaycast(scene, scene.camera.position, targetVector) + + if objectIndex then + local triangle = scene.objects[objectIndex].triangles[triangleIndex] + local xWorld = math.floor(((scene.objects[objectIndex].vertices[scene.objects[objectIndex].triangles[triangleIndex][1]][1] + scene.objects[objectIndex].vertices[scene.objects[objectIndex].triangles[triangleIndex][2]][1] + scene.objects[objectIndex].vertices[scene.objects[objectIndex].triangles[triangleIndex][3]][1]) / 3) / blockSize) + 1 + local yWorld = math.floor(((scene.objects[objectIndex].vertices[triangle[1]][2] + scene.objects[objectIndex].vertices[triangle[2]][2] + scene.objects[objectIndex].vertices[triangle[3]][2]) / 3) / blockSize) + 1 + local zWorld = math.floor(((scene.objects[objectIndex].vertices[triangle[1]][3] + scene.objects[objectIndex].vertices[triangle[2]][3] + scene.objects[objectIndex].vertices[triangle[3]][3]) / 3) / blockSize) + 1 + + local normalVector = vector.getSurfaceNormal( + scene.objects[objectIndex].vertices[triangle[1]], + scene.objects[objectIndex].vertices[triangle[2]], + scene.objects[objectIndex].vertices[triangle[3]] + ) + + if normalVector[1] > 0 and eventData[5] ~= 1 or normalVector[1] < 0 and eventData[5] == 1 then + xWorld = xWorld - 1 + elseif normalVector[2] > 0 and eventData[5] ~= 1 or normalVector[2] < 0 and eventData[5] == 1 then + yWorld = yWorld - 1 + elseif normalVector[3] > 0 and eventData[5] ~= 1 or normalVector[3] < 0 and eventData[5] == 1 then + zWorld = zWorld - 1 + end + + setBlock(xWorld, yWorld, zWorld, eventData[5] == 1 and mainContainer.toolbar.blockColorSelector.color or nil) + end + end +end + +mainContainer:addChild(OCGLView) + +mainContainer.infoTextBox = mainContainer:addChild(GUI.textBox(2, 4, 45, mainContainer.height, nil, 0xEEEEEE, {}, 1, 0, 0)) +local lines = { + "Copyright © 2016-2017 - Developed by ECS Inc.", + "Timofeef Igor (vk.com/id7799889), Trifonov Gleb (vk.com/id88323331), Verevkin Yakov (vk.com/id60991376), Bogushevich Victoria (vk.com/id171497518)", + "All rights reserved", +} +mainContainer:addChild(GUI.textBox(1, mainContainer.height - #lines + 1, mainContainer.width, #lines, nil, 0x3C3C3C, lines, 1)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + +local elementY = 2 +mainContainer.toolbar = mainContainer:addChild(GUI.container(mainContainer.width - 31, 1, 32, mainContainer.height)) +local elementWidth = mainContainer.toolbar.width - 2 +mainContainer.toolbar:addChild(GUI.panel(1, 1, mainContainer.toolbar.width, mainContainer.toolbar.height, 0x0, 0.5)) + +mainContainer.toolbar:addChild(GUI.label(2, elementY, elementWidth, 1, 0xEEEEEE, "Render mode")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); elementY = elementY + 2 +mainContainer.toolbar.renderModeComboBox = mainContainer.toolbar:addChild(GUI.comboBox(2, elementY, elementWidth, 1, 0x2D2D2D, 0xAAAAAA, 0x555555, 0x888888)); elementY = elementY + mainContainer.toolbar.renderModeComboBox.height + 1 +mainContainer.toolbar.renderModeComboBox:addItem("disabled") +mainContainer.toolbar.renderModeComboBox:addItem("constantShading") +mainContainer.toolbar.renderModeComboBox:addItem("flatShading") +mainContainer.toolbar.renderModeComboBox.selectedItem = scene.renderMode +mainContainer.toolbar.renderModeComboBox.onItemSelected = function() + scene.renderMode = mainContainer.toolbar.renderModeComboBox.selectedItem +end + +mainContainer.toolbar.auxiliaryModeComboBox = mainContainer.toolbar:addChild(GUI.comboBox(2, elementY, elementWidth, 1, 0x2D2D2D, 0xAAAAAA, 0x555555, 0x888888)); elementY = elementY + mainContainer.toolbar.auxiliaryModeComboBox.height + 1 +mainContainer.toolbar.auxiliaryModeComboBox:addItem("disabled") +mainContainer.toolbar.auxiliaryModeComboBox:addItem("wireframe") +mainContainer.toolbar.auxiliaryModeComboBox:addItem("vertices") +mainContainer.toolbar.auxiliaryModeComboBox.selectedItem = scene.auxiliaryMode +mainContainer.toolbar.auxiliaryModeComboBox.onItemSelected = function() + scene.auxiliaryMode = mainContainer.toolbar.auxiliaryModeComboBox.selectedItem +end + +mainContainer.toolbar:addChild(GUI.label(2, elementY, elementWidth, 1, 0xAAAAAA, "Perspective proj:")) +mainContainer.toolbar.perspectiveSwitch = mainContainer.toolbar:addChild(GUI.switch(mainContainer.toolbar.width - 8, elementY, 8, 0x66DB80, 0x2D2D2D, 0xEEEEEE, scene.camera.projectionEnabled)); elementY = elementY + 2 +mainContainer.toolbar.perspectiveSwitch.onStateChanged = function() + scene.camera.projectionEnabled = mainContainer.toolbar.perspectiveSwitch.state +end + +mainContainer.toolbar:addChild(GUI.label(2, elementY, elementWidth, 1, 0xAAAAAA, "Z-buffer visualize:")) +mainContainer.toolbar.zBufferSwitch = mainContainer.toolbar:addChild(GUI.switch(mainContainer.toolbar.width - 8, elementY, 8, 0x66DB80, 0x2D2D2D, 0xEEEEEE, false)); elementY = elementY + 2 + + +local function calculateLightComboBox() + mainContainer.toolbar.lightSelectComboBox.dropDownMenu.itemsContainer.children = {} + for i = 1, #scene.lights do + mainContainer.toolbar.lightSelectComboBox:addItem(tostring(i)) + end + mainContainer.toolbar.lightSelectComboBox.selectedItem = #mainContainer.toolbar.lightSelectComboBox.dropDownMenu.itemsContainer.children + mainContainer.toolbar.lightIntensitySlider.value = scene.lights[mainContainer.toolbar.lightSelectComboBox.selectedItem].intensity * 100 + mainContainer.toolbar.lightEmissionSlider.value = scene.lights[mainContainer.toolbar.lightSelectComboBox.selectedItem].emissionDistance +end + +mainContainer.toolbar:addChild(GUI.label(2, elementY, elementWidth, 1, 0xEEEEEE, "Light control")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); elementY = elementY + 2 +mainContainer.toolbar.lightSelectComboBox = mainContainer.toolbar:addChild(GUI.comboBox(2, elementY, elementWidth, 1, 0x2D2D2D, 0xAAAAAA, 0x555555, 0x888888)); elementY = elementY + mainContainer.toolbar.lightSelectComboBox.height + 1 + +mainContainer.toolbar.addLightButton = mainContainer.toolbar:addChild(GUI.button(2, elementY, elementWidth, 1, 0x2D2D2D, 0xAAAAAA, 0x555555, 0xAAAAAA, "Add light")); elementY = elementY + 2 +mainContainer.toolbar.addLightButton.onTouch = function() + scene:addLight(meowEngine.newLight(vector.newVector3(0, 10, 0), mainContainer.toolbar.lightIntensitySlider.value / 100, mainContainer.toolbar.lightEmissionSlider.value)) + calculateLightComboBox() +end + +mainContainer.toolbar.removeLightButton = mainContainer.toolbar:addChild(GUI.button(2, elementY, elementWidth, 1, 0x2D2D2D, 0xAAAAAA, 0x555555, 0xAAAAAA, "Remove light")); elementY = elementY + 2 +mainContainer.toolbar.removeLightButton.onTouch = function() + if #scene.lights > 1 then + table.remove(scene.lights, mainContainer.toolbar.lightSelectComboBox.selectedItem) + calculateLightComboBox() + end +end + +mainContainer.toolbar.lightIntensitySlider = mainContainer.toolbar:addChild(GUI.slider(2, elementY, elementWidth, 0xCCCCCC, 0x2D2D2D, 0xEEEEEE, 0xAAAAAA, 0, 500, 100, false, "Intensity: ", "")); elementY = elementY + 3 +mainContainer.toolbar.lightIntensitySlider.onValueChanged = function() + scene.lights[mainContainer.toolbar.lightSelectComboBox.selectedItem].intensity = mainContainer.toolbar.lightIntensitySlider.value / 100 +end +mainContainer.toolbar.lightEmissionSlider = mainContainer.toolbar:addChild(GUI.slider(2, elementY, elementWidth, 0xCCCCCC, 0x2D2D2D, 0xEEEEEE, 0xAAAAAA, 0, scene.lights[mainContainer.toolbar.lightSelectComboBox.selectedItem].emissionDistance, scene.lights[mainContainer.toolbar.lightSelectComboBox.selectedItem].emissionDistance, false, "Distance: ", "")); elementY = elementY + 3 +mainContainer.toolbar.lightEmissionSlider.onValueChanged = function() + scene.lights[mainContainer.toolbar.lightSelectComboBox.selectedItem].emissionDistance = mainContainer.toolbar.lightEmissionSlider.value +end +calculateLightComboBox() + +mainContainer.toolbar.blockColorSelector = mainContainer.toolbar:addChild(GUI.colorSelector(2, elementY, elementWidth, 1, 0xEEEEEE, "Block color")); elementY = elementY + mainContainer.toolbar.blockColorSelector.height + 1 +mainContainer.toolbar.backgroundColorSelector = mainContainer.toolbar:addChild(GUI.colorSelector(2, elementY, elementWidth, 1, scene.backgroundColor, "Background color")); elementY = elementY + mainContainer.toolbar.blockColorSelector.height + 1 +mainContainer.toolbar.backgroundColorSelector.onTouch = function() + scene.backgroundColor = mainContainer.toolbar.backgroundColorSelector.color +end + +mainContainer.toolbar:addChild(GUI.label(2, elementY, elementWidth, 1, 0xEEEEEE, "RAM monitoring")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); elementY = elementY + 2 +mainContainer.toolbar.RAMChart = mainContainer.toolbar:addChild(GUI.chart(2, elementY, elementWidth, mainContainer.toolbar.height - elementY - 3, 0xEEEEEE, 0xAAAAAA, 0x555555, 0x66DB80, 0.35, 0.25, "s", "%", true, {})); elementY = elementY + mainContainer.toolbar.RAMChart.height + 1 +mainContainer.toolbar.RAMChart.roundValues = true +-- mainContainer.toolbar.RAMChart.showXAxisValues = false +mainContainer.toolbar.RAMChart.counter = 1 + +mainContainer.toolbar:addChild(GUI.button(1, mainContainer.toolbar.height - 2, mainContainer.toolbar.width, 3, 0x2D2D2D, 0xEEEEEE, 0x444444, 0xEEEEEE, "Exit")).onTouch = function() + mainContainer:stopEventHandling() +end + +local FPSCounter = GUI.object(2, 2, 8, 3) +FPSCounter.draw = function(FPSCounter) + renderer.renderFPSCounter(FPSCounter.x, FPSCounter.y, tostring(math.ceil(1 / (os.clock() - mainContainer.oldClock) / 10)), 0xFFFF00) +end +mainContainer:addChild(FPSCounter) + +mainContainer.eventHandler = function(mainContainer, object, eventData) + if not mainContainer.toolbar.hidden then + local totalMemory = computer.totalMemory() + table.insert(mainContainer.toolbar.RAMChart.values, {mainContainer.toolbar.RAMChart.counter, math.ceil((totalMemory - computer.freeMemory()) / totalMemory * 100)}) + mainContainer.toolbar.RAMChart.counter = mainContainer.toolbar.RAMChart.counter + 1 + if #mainContainer.toolbar.RAMChart.values > 20 then table.remove(mainContainer.toolbar.RAMChart.values, 1) end + + mainContainer.infoTextBox.lines = { + " ", + "SceneObjects: " .. #scene.objects, + " ", + "OCGLVertices: " .. #OCGL.vertices, + "OCGLTriangles: " .. #OCGL.triangles, + "OCGLLines: " .. #OCGL.lines, + "OCGLFloatingTexts: " .. #OCGL.floatingTexts, + "OCGLLights: " .. #OCGL.lights, + " ", + "CameraFOV: " .. string.format("%.2f", math.deg(scene.camera.FOV)), + "СameraPosition: " .. string.format("%.2f", scene.camera.position[1]) .. " x " .. string.format("%.2f", scene.camera.position[2]) .. " x " .. string.format("%.2f", scene.camera.position[3]), + "СameraRotation: " .. string.format("%.2f", math.deg(scene.camera.rotation[1])) .. " x " .. string.format("%.2f", math.deg(scene.camera.rotation[2])) .. " x " .. string.format("%.2f", math.deg(scene.camera.rotation[3])), + "CameraNearClippingSurface: " .. string.format("%.2f", scene.camera.nearClippingSurface), + "CameraFarClippingSurface: " .. string.format("%.2f", scene.camera.farClippingSurface), + "CameraProjectionSurface: " .. string.format("%.2f", scene.camera.projectionSurface), + "CameraPerspectiveProjection: " .. tostring(scene.camera.projectionEnabled), + " ", + "Controls:", + " ", + "Arrows - camera rotation", + "WASD/Shift/Space - camera movement", + "LMB/RMB - destroy/place block", + "NUM 8/2/4/6/1/3 - selected light movement", + "F1 - toggle GUI overlay", + } + + mainContainer.infoTextBox.height = #mainContainer.infoTextBox.lines + end + + if eventData[1] == "key_down" then + if controls[eventData[4]] then controls[eventData[4]]() end + elseif eventData[1] == "scroll" then + if eventData[5] == 1 then + if scene.camera.FOV < math.rad(170) then + scene.camera:setFOV(scene.camera.FOV + math.rad(5)) + end + else + if scene.camera.FOV > math.rad(5) then + scene.camera:setFOV(scene.camera.FOV - math.rad(5)) + end + end + end + + mainContainer:draw() + buffer.draw() +end + +-------------------------------------------------------- Ebat-kopat -------------------------------------------------------- + +mainContainer:startEventHandling(0) + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DTest.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DTest.app/Resources/About/Russian.txt new file mode 100755 index 00000000..86e147be --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DTest.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Программа-демонстратор возможностей 3D-движка, созданного специально для низкопроизводительных компьютеров. В ней воплощены практически все наработки нашей команды: от отрисовки сложных трехмерных объектов и динамического освещения до текстурирования и пользовательского интерфейса на мощной GUI-библиотеке. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DTest.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DTest.app/Resources/Icon.pic new file mode 100755 index 00000000..358e8b8d Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/3DTest.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Main.lua new file mode 100755 index 00000000..c259e806 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Main.lua @@ -0,0 +1,246 @@ + +require("advancedLua") +local component = require("component") +local computer = require("computer") +local image = require("image") +local buffer = require("doubleBuffering") +local GUI = require("GUI") +local fs = require("filesystem") +local unicode = require("unicode") +local web = require("web") +local MineOSPaths = require("MineOSPaths") +local MineOSCore = require("MineOSCore") +local MineOSInterface = require("MineOSInterface") + +---------------------------------------------------------------------------------------------------------------- + +local applicationListURL = "https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications.cfg" +local applicationList +local localization = MineOSCore.getCurrentApplicationLocalization() +local resources = MineOSCore.getCurrentApplicationResourcesDirectory() +local updateImage = image.load(resources .. "Update.pic") +local appsPerPage = 6 + +local mainContainer, window = MineOSInterface.addWindow(MineOSInterface.tabbedWindow(1, 1, 80, 32)) + +---------------------------------------------------------------------------------------------------------------- + +local function newApp(x, y, width, applicationListElement, hideDownloadButton) + local app = GUI.container(x, y, width, 4) + + app.icon = app:addChild(GUI.image(1, 1, MineOSInterface.iconsCache.script)) + if applicationListElement.icon then + app.icon.image = MineOSCore.loadImageFromString(web.request(applicationListElement.icon)) + end + + app.downloadButton = app:addChild(GUI.roundedButton(1, 1, 13, 1, 0x66DB80, 0xFFFFFF, 0x339240, 0xFFFFFF, localization.download)) + app.downloadButton.localX = app.width - app.downloadButton.width + app.downloadButton.onTouch = function() + app.downloadButton.disabled = true + app.downloadButton.colors.disabled.background, app.downloadButton.colors.disabled.text = 0xBBBBBB, 0xFFFFFF + app.downloadButton.text = localization.downloading + mainContainer:draw() + buffer.draw() + + MineOSCore.downloadApplication(applicationListElement, MineOSCore.properties.language) + + app.downloadButton.text = localization.downloaded + computer.pushSignal("MineOSCore", "updateFileList") + end + app.downloadButton.hidden = hideDownloadButton + + app.pathLabel = app:addChild(GUI.label(app.icon.width + 3, 1, width - app.icon.width - app.downloadButton.width - 5, 1, 0x0, fs.name(applicationListElement.path))) + app.versionLabel = app:addChild(GUI.label(app.icon.width + 3, 2, app.pathLabel.width, 1, 0x555555, localization.version .. applicationListElement.version)) + if applicationListElement.about then + local lines = string.wrap({web.request(applicationListElement.about .. MineOSCore.properties.language .. ".txt")}, app.pathLabel.width) + app.aboutTextBox = app:addChild(GUI.textBox(app.icon.width + 3, 3, app.pathLabel.width, #lines, nil, 0x999999, lines, 1, 0, 0)) + app.aboutTextBox.eventHandler = nil + if #lines > 2 then + app.height = #lines + 2 + end + end + + return app +end + +local function addUpdateImage() + window.contentContainer:deleteChildren() + local cyka = window.contentContainer:addChild(GUI.image(math.floor(window.contentContainer.width / 2 - image.getWidth(updateImage) / 2), math.floor(window.contentContainer.height / 2 - image.getHeight(updateImage) / 2) - 1, updateImage)) + return cyka.localY + cyka.height + 2 +end + +local function updateApplicationList() + local y = addUpdateImage() + window.contentContainer:addChild(GUI.label(1, y, window.contentContainer.width, 1, 0x888888, localization.checkingForUpdates)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + mainContainer:draw() + buffer.draw() + + applicationList = table.fromString(web.request(applicationListURL)) +end + + +local function displayApps(fromPage, typeFilter, nameFilter, updateCheck) + window.contentContainer:deleteChildren() + + local y = 2 + local finalApplicationList = {} + + if updateCheck then + local oldApplicationList = table.fromFile(MineOSPaths.applicationList) + + for j = 1, #applicationList do + local pathFound = false + + for i = 1, #oldApplicationList do + if oldApplicationList[i].path == applicationList[j].path then + if oldApplicationList[i].version < applicationList[j].version then + table.insert(finalApplicationList, applicationList[j]) + end + + pathFound = true + break + end + end + + if not pathFound then + table.insert(finalApplicationList, applicationList[j]) + end + end + + if #finalApplicationList == 0 then + window.contentContainer:addChild(GUI.label(1, 1, window.contentContainer.width, window.contentContainer.height, 0x888888, localization.youHaveNewestApps)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.center) + mainContainer:draw() + buffer.draw() + return + else + window.contentContainer:addChild(GUI.roundedButton(math.floor(window.contentContainer.width / 2 - 9), y, 18, 1, 0xBBBBBB, 0xFFFFFF, 0x999999, 0xFFFFFF, localization.updateAll)).onTouch = function() + y = addUpdateImage() + + local progressBarWidth = math.floor(window.contentContainer.width * 0.65) + local progressBar = window.contentContainer:addChild(GUI.progressBar(math.floor(window.contentContainer.width / 2 - progressBarWidth / 2), y, progressBarWidth, 0x33B6FF, 0xDDDDDD, 0x0, 0, true, false)) + local label = window.contentContainer:addChild(GUI.label(1, y + 1, window.contentContainer.width, 1, 0x888888, "")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + + for i = 1, #finalApplicationList do + progressBar.value = math.floor(i / #finalApplicationList * 100) + label.text = localization.updating .. fs.name(finalApplicationList[i].path) + + mainContainer:draw() + buffer.draw() + + MineOSCore.downloadApplication(finalApplicationList[i], MineOSCore.properties.language) + end + + mainContainer:draw() + buffer.draw() + + table.toFile(MineOSPaths.applicationList, applicationList) + + computer.shutdown(true) + end + end + else + window.contentContainer.searchInputTextBox = window.contentContainer:addChild(GUI.input(math.floor(window.contentContainer.width / 2 - 10), y, 20, 1, 0xFFFFFF, 0x444444, 0xAAAAAA, 0xFFFFFF, 0x2D2D2D, "", localization.search, true)) + window.contentContainer.searchInputTextBox.onInputFinished = function() + if window.contentContainer.searchInputTextBox.text then + displayApps(1, typeFilter, window.contentContainer.searchInputTextBox.text) + end + end + + for i = 1, #applicationList do + if (not typeFilter or typeFilter == applicationList[i].type) and (not nameFilter or string.unicodeFind(unicode.lower(fs.name(applicationList[i].path)), unicode.lower(nameFilter))) then + table.insert(finalApplicationList, applicationList[i]) + end + end + end + + y = y + 2 + + mainContainer:draw() + buffer.draw() + + local appOnPageCounter, fromAppCounter, fromApp = 1, 1, (fromPage - 1) * appsPerPage + 1 + for i = 1, #finalApplicationList do + if fromAppCounter >= fromApp then + y, appOnPageCounter = y + window.contentContainer:addChild(newApp(1, y, window.contentContainer.width, finalApplicationList[i])).height + 1, appOnPageCounter + 1 + + mainContainer:draw() + buffer.draw() + + if appOnPageCounter > appsPerPage then + break + end + end + + fromAppCounter = fromAppCounter + 1 + end + + -- Pages buttons CYKA + local buttonWidth, text = 5, localization.page .. fromPage + local textLength = unicode.len(text) + local x = math.floor(window.contentContainer.width / 2 - (buttonWidth * 2 + textLength + 4) / 2) + window.contentContainer:addChild(GUI.roundedButton(x, y, buttonWidth, 1, 0xBBBBBB, 0xFFFFFF, 0x999999, 0xFFFFFF, "<")).onTouch = function() + if fromPage > 1 then + displayApps(fromPage - 1, typeFilter, nameFilter) + end + end + x = x + buttonWidth + 2 + + window.contentContainer:addChild(GUI.label(x, y, textLength, 1, 0x3C3C3C, text)) + x = x + textLength + 2 + + window.contentContainer:addChild(GUI.roundedButton(x, y, buttonWidth, 1, 0xBBBBBB, 0xFFFFFF, 0x999999, 0xFFFFFF, ">")).onTouch = function() + displayApps(fromPage + 1, typeFilter, nameFilter) + end + + mainContainer:draw() + buffer.draw() +end + +window.contentContainer = window:addChild(GUI.container(3, 4, window.width - 4, window.height - 3)) +window.contentContainer.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "scroll" and (eventData[5] == -1 or window.contentContainer.children[1].localY <= 1) then + for i = 1, #window.contentContainer.children do + window.contentContainer.children[i].localY = window.contentContainer.children[i].localY + eventData[5] + end + mainContainer:draw() + buffer.draw() + end +end + +local tabs = { + window.tabBar:addItem(localization.applications), + window.tabBar:addItem(localization.libraries), + window.tabBar:addItem(localization.wallpapers), + window.tabBar:addItem(localization.other), + window.tabBar:addItem(localization.updates) +} + +window.onResize = function(width, height) + window.contentContainer.width, window.contentContainer.height = width - 4, height - 3 + window.tabBar.width = width + window.backgroundPanel.width = width + window.backgroundPanel.height = height - window.tabBar.height + tabs[window.tabBar.selectedItem].onTouch() +end + +tabs[1].onTouch = function() displayApps(1, "Application") end +tabs[2].onTouch = function() displayApps(1, "Library") end +tabs[3].onTouch = function() displayApps(1, "Wallpaper") end +tabs[4].onTouch = function() displayApps(1, "Script") end +tabs[5].onTouch = function() displayApps(1, nil, nil, true) end + +---------------------------------------------------------------------------------------------------------------- + +if select(1, ...) == "updates" then + window.tabBar.selectedItem = 5 +end + +updateApplicationList() +tabs[window.tabBar.selectedItem].onTouch() + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/About/Russian.txt new file mode 100755 index 00000000..3f93c646 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Одно из главных системных приложений, позволяющее проверять наличие необходимых обновлений, а также загружать красивейшие программы, созданные специально для MineOS. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/Icon.pic new file mode 100755 index 00000000..1e0deecf Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/Localization/English.lang b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/Localization/English.lang new file mode 100755 index 00000000..f667b67f --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/Localization/English.lang @@ -0,0 +1,17 @@ +{ + applications = "Applications", + libraries = "Libraries", + wallpapers = "Wallpapers", + other = "Other", + updates = "Updates", + checkingForUpdates = "Checking for updates", + version = "Version: ", + updateAll = "Update all", + download = "Install", + downloading = "Installing", + downloaded = "Installed", + search = "Search", + page = "Page ", + youHaveNewestApps = "You have no updates.", + updating = "Installing ", +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/Localization/Russian.lang b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/Localization/Russian.lang new file mode 100755 index 00000000..ab152772 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/Localization/Russian.lang @@ -0,0 +1,17 @@ +{ + applications = "Приложения", + libraries = "Библиотеки", + wallpapers = "Обои", + other = "Другое", + updates = "Обновления", + checkingForUpdates = "Проверка наличия обновлений", + version = "Версия: ", + updateAll = "Обновить все", + download = "Загрузить", + downloading = "Загрузка", + downloaded = "Установлено", + search = "Поиск", + page = "Страница ", + youHaveNewestApps = "У вас самое новое ПО", + updating = "Обновление ", +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/TempIcon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/TempIcon.pic new file mode 100644 index 00000000..026f5a0c Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/TempIcon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/Update.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/Update.pic new file mode 100644 index 00000000..aea30fe0 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/AppMarket.app/Resources/Update.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Battleship.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Battleship.app/Main.lua new file mode 100755 index 00000000..1f64f0a6 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Battleship.app/Main.lua @@ -0,0 +1,339 @@ +--Реквайрики +local g = require("component").gpu +local term = require("term") +local event = require("event") + +local colors = { + white = 0xffffff, + orange = 0xF2B233, + magenta = 0xE57FD8, + lightBlue = 0x99B2F2, + yellow = 0xDEDE6C, + lime = 0x7FCC19, + pink = 0xF2B2CC, + gray = 0x4C4C4C, + lightGray = 0x999999, + cyan = 0x4C99B2, + purple = 0xB266E5, + blue = 0x3366CC, + brown = 0x7F664C, + green = 0x57A64E, + red = 0xCC4C4C, + black = 0x000000, +} + + +--Настройка экрана +local w, h = 46, 14 +g.setResolution(w,h) + +--Аргументы +args = {...} + +--Очищаем экран +g.setBackground(colors.lightGray) +term.clear() + +--Переменные для кораблей +local ships = {{3, 3, 8}, + {3, 5, 6}, + {11, 5, 6}, + {3, 7, 4}, + {9, 7, 4}, + {15, 7, 4}, + {3, 9, 2}, + {7, 9, 2}, + {11, 9, 2}, + {15, 9, 2}} +local shipsE = {{0, 0, 8}, + {0, 0, 6}, + {0, 0, 6}, + {0, 0, 4}, + {0, 0, 4}, + {0, 0, 4}, + {0, 0, 2}, + {0, 0, 2}, + {0, 0, 2}, + {0, 0, 2}} + +--Переменные попаданий +local shots = 0 +local shotsE = {{0, 0}} +local shotsE2 = 0 + +--Пишем заголовок +g.setBackground(colors.gray) +g.fill(1,1,w,1," ") +term.setCursor(math.floor(w/2-6),1) +g.setForeground(colors.white) +term.write("Морской Бой") +g.setBackground(colors.black) +term.setCursor(w-3,1) +term.write(" ") + +--Функция определения координаты для поля +function makePixelX(x, b) + return b+math.floor((x-b)/2)*2 +end + +--Рисуем кораблики +function drawShips() + for i=1,10 do + g.setBackground(colors.brown) + g.fill(ships[i][1], ships[i][2], ships[i][3], 1, " ") + end +end + +--Автоматически установить кораблики +function setShipsAuto(var) + local s = ships + if var ~= 25 then + s = shipsE + end + for i=1,10 do + local x, y = 0, 0 + local yes = true + while yes do + x = math.random(var, var+19) + y = math.random(3, 12) + if x+s[i][3]-1 < var+20 then + for j=1,10 do + if i ~= j and (x < s[j][1]+s[j][3]+2 and x+s[i][3] > s[j][1]-2 and y > s[j][2]-2 and y < s[j][2]+2) then + x = math.random(var, var+19) + y = math.random(3, 12) + break + elseif i ~= j and (j == 10 or (i == 10 and j == 9)) then + s[i][1] = makePixelX(x, var) + s[i][2] = y + yes = false + end + end + end + end + end + if var == 25 then + ships = s + else + shipsE = s + end +end + +--Рисуем поле +function drawField() + g.setBackground(0xffffff) + g.fill(25,3,20,10," ") + g.setBackground(0xDDDDDD) + if args[1] ~= "fast" then + for i=1,10 do + local delta = math.fmod(i,2) + for j=1,5 do + g.fill(23+4*j-2*delta, i+2, 2, 1, " ") + end + end + end +end + +--Рисуем поле врага +function drawFieldE() + g.setBackground(0xffffff) + g.fill(3,3,20,10," ") + g.setBackground(0xDDDDDD) + if args[1] ~= "fast" then + for i=1,10 do + local delta = math.fmod(i,2) + for j=1,5 do + g.fill(1+4*j-2*delta, i+2, 2, 1, " ") + end + end + end +end + +--Кнопка готово после рандома +function drawButton2() + g.setBackground(colors.pink) + term.setCursor(13, 11) + term.write(" Готово ") +end + +--Кнопка рандома своих кораблей +function drawButton() + g.setBackground(colors.lime) + term.setCursor(3, 11) + term.write(" Авто ") +end + +--Очищаем пустое место +function clearShipsField() + g.setBackground(colors.lightGray) + g.fill(3,3,22,10," ") +end + +--Гуишечка +drawField() +drawShips() +drawButton() +g.setBackground(colors.lightGray) +g.setForeground(colors.black) +term.setCursor(3,13) +term.write("Установите корабли") + +--Цикл для установки своих корабликов вручную +local ship = 0 +local prevX = 0 +local shipCoords = {0,0} +local setting = true +local playing = true +local button2 = false +while setting do + local event, _, x, y = event.pull() + if event == "touch" then + if x > 2 and x < 13 and y == 11 then + setShipsAuto(25) + drawField() + clearShipsField() + drawShips() + drawButton() + drawButton2() + button2 = true + elseif button2 and x > 12 and x < 24 and y == 11 then + setting = false + break + elseif x > w-4 and x < w and y == 1 then + setting = false + playing = false + break + end + elseif event == "drag" then + if ship == 0 then + for i=1,10 do + if x > ships[i][1] and x < ships[i][1]+ships[i][3] and y == ships[i][2] then + ship = i + shipCoords[1] = ships[i][1] + shipCoords[2] = ships[i][2] + break + end + end + else + ships[ship][1] = ships[ship][1] + x - prevX + ships[ship][2] = y + if ships[ship][1] > 2 and ships[ship][1]+ships[ship][3]-1 < 45 and y > 2 and y < 13 then + drawField() + clearShipsField() + drawShips() + drawButton() + end + end + prevX = x + elseif event == "drop" then + if ship > 0 then + if ships[ship][1] < 25 or ships[ship][1]+ships[ship][3]-1 > 45 or y < 3 or y > 13then + ships[ship][1] = shipCoords[1] + ships[ship][2] = shipCoords[2] + end + for i=1,10 do + if i ~= ship and (ships[ship][1] < ships[i][1]+ships[i][3]+1 and ships[ship][1]+ships[ship][3]-1 > ships[i][1]-2 and ships[ship][2] > ships[i][2]-2 and ships[ship][2] < ships[i][2]+2) then + ships[ship][1] = shipCoords[1] + ships[ship][2] = shipCoords[2] + break + end + end + ships[ship][1] = makePixelX(ships[ship][1], 25) + end + ship = 0 + drawField() + clearShipsField() + drawShips() + drawButton() + for i=1,10 do + if ships[i][1] < 25 then + break + elseif i == 10 then + setting = false + break + end + end + end +end + +--Следующий цикл для игры +setShipsAuto(3) +drawFieldE() +g.setBackground(colors.lightGray) +g.setForeground(colors.black) +term.setCursor(3,13) +term.write("Противник ") +term.setCursor(25,13) +term.write("Вы") +g.setBackground(colors.magenta) +g.fill(23, 3, 2, 10, " ") +while playing do + local event, _, x, y = event.pull() + if event == "touch" then + if shots < 20 and shotsE2 < 20 and x > 2 and x < 23 and y > 2 and y < 13 then + x = makePixelX(x, 3) + for i=1,10 do + if x > shipsE[i][1]-1 and x < shipsE[i][1]+shipsE[i][3] and y == shipsE[i][2] then + shots = shots + 1 + g.setBackground(colors.red) + break + end + g.setBackground(colors.blue) + end + g.fill(x, y, 2, 1, " ") + local yes = true + local xE, yE = 0, 0 + while yes do + xE = makePixelX(math.random(25,44), 3) + yE = math.random(3,12) + for i=1,#shotsE do + if xE == shotsE[i][1] and yE == shotsE[i][2] then + break + elseif i == #shotsE then + yes = false + break + end + end + end + table.insert(shotsE, {makePixelX(xE, 3), yE}) + if args[2] ~= "notime" then + g.setBackground(colors.purple) + g.fill(23, 3, 2, 10, " ") + os.sleep(math.floor(math.random(2))-0.5) + g.setBackground(colors.magenta) + g.fill(23, 3, 2, 10, " ") + end + for i=1,10 do + if xE > ships[i][1]-1 and xE < ships[i][1]+ships[i][3] and yE == ships[i][2] then + shotsE2 = shotsE2 + 1 + g.setBackground(colors.red) + break + end + g.setBackground(colors.blue) + end + g.fill(xE, yE, 2, 1, " ") + if shots == 20 or shotsE2 == 20 then + g.setBackground(colors.lightGray) + g.fill(2, 3, 43, 12, " ") + g.setBackground(colors.white) + g.fill(15, 5, 16, 3, " ") + + if shots == 20 then + term.setCursor(20, 6) + term.write("Победа") + elseif shotsE2 == 20 then + term.setCursor(18, 6) + term.write("Поражение") + end + end + elseif x > w-4 and x < w and y == 1 then + playing = false + break + end + end +end + +--При выходе +g.setForeground(colors.white) +g.setBackground(colors.black) +term.clear() +g.setResolution(g.maxResolution()) \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Battleship.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Battleship.app/Resources/About/Russian.txt new file mode 100755 index 00000000..76fbd88d --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Battleship.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Популярная игра "Морской бой", написанная товарищем Nezn с форума ComputerCraft.ru. Рассчитана на одного игрока, вам предстоит захватывающее сражение с флотом противника, контролируемым ИИ на Lua. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Battleship.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Battleship.app/Resources/Icon.pic new file mode 100755 index 00000000..c7304d27 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Battleship.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/BufferDemo.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/BufferDemo.app/Main.lua new file mode 100755 index 00000000..e0b0f2a9 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/BufferDemo.app/Main.lua @@ -0,0 +1,160 @@ + +local buffer = require("doubleBuffering") +local event = require("event") +local image = require("image") + +local currentBackground = 0x990000 +local risovatKartinku = true +local showPanel = true +local transparency = 0.25 +local xWindow, yWindow = 5, 5 + +local fon = image.load("MineOS/Applications/BufferDemo.app/Resources/Wallpaper.pic") + +buffer.flush() +local bufferWidth, bufferHeight = buffer.getResolution() + +local function drawBackground() + --Заполним весь наш экран цветом фона 0x262626, цветом текста 0xFFFFFF и символом " " + if not risovatKartinku then + buffer.square(1, 1, bufferWidth, bufferHeight, currentBackground, 0xFFFFFF, " ") + else + buffer.image(1, 1, fon) + end +end + +--Создаем переменные с координатами начала и размерами нашего окна +local width, height = 82, 25 + +-- local cykaPicture = image.load("System/OS/Icons/Steve.pic") +-- local cykaPicture2 = image.load("System/OS/Icons/Love.pic") + +local function drawWindow(x, y) + + --Тени + local shadowTransparency = 0.6 + buffer.square(x + width, y + 1, 2, height, 0x000000, 0xFFFFFF, " ", shadowTransparency) + buffer.square(x + 2, y + height, width - 2, 1, 0x000000, 0xFFFFFF, " ", shadowTransparency) + + --Создаем прозрачную часть окна, где отображается "Избранное" + buffer.square(x, y, 20, height, 0xFFFFFF, 0xFFFFFF, " ", transparency) + + --Создаем непрозрачную часть окна для отображения всяких файлов и т.п. + buffer.square(x + 20, y, width - 20, height, 0xFFFFFF, 0xFFFFFF, " ") + + --Создаем три более темных полоски вверху окна, имитируя объем + buffer.square(x, y, width, 1, 0xDDDDDD, 0xFFFFFF, " ") + buffer.square(x, y + 1, width, 1, 0xCCCCCC, 0xFFFFFF, " ") + buffer.square(x, y + 2, width, 1, 0xBBBBBB, 0xFFFFFF, " ") + + --Рисуем заголовок нашего окошка + buffer.text(x + 30, y, 0x000000, "Тестовое окно") + + --Создаем три кнопки в левом верхнем углу для закрытия, разворачивания и сворачивания окна + buffer.set(x + 1, y, 0xDDDDDD, 0xFF4940, "⬤") + buffer.set(x + 3, y, 0xDDDDDD, 0xFFB640, "⬤") + buffer.set(x + 5, y, 0xDDDDDD, 0x00B640, "⬤") + + --Рисуем элементы "Избранного" чисто для демонстрации + buffer.text(x + 1, y + 3, 0x000000, "Избранное") + for i = 1, 6 do buffer.text(x + 2, y + 3 + i, 0x555555, "Вариант " .. i) end + + --Рисуем "Файлы" в виде желтых квадратиков. Нам без разницы, а выглядит красиво + for j = 1, 3 do + for i = 1, 5 do + local xPos, yPos = x + 22 + i*12 - 12, y + 4 + j*7 - 7 + buffer.square(xPos, yPos, 8, 4, 0xFFFF80, 0xFFFFFF, " ") + buffer.text(xPos, yPos + 5, 0x262626, "Файл " .. i .. "x" .. j) + end + end + + --Ну, и наконец рисуем голубой скроллбар справа + buffer.square(x + width - 1, y + 3, 1, height - 3, 0xBBBBBB, 0xFFFFFF, " ") + buffer.square(x + width - 1, y + 3, 1, 4, 0x3366CC, 0xFFFFFF, " ") + + --Изображения! + -- buffer.image(x + 23, y + 6, cykaPicture) + -- buffer.image(x + 33, y + 12, cykaPicture2) + + if showPanel then + xPos, yPos = x, y + height + 2 + buffer.square(xPos, yPos, width, 10, 0xFFFFFF, 0xFFFFFF, " ", transparency) + + --Тень + buffer.square(xPos + width, yPos + 1, 2, 10, 0x000000, 0xFFFFFF, " ", shadowTransparency) + buffer.square(xPos + 2, yPos + 10, width - 2, 1, 0x000000, 0xFFFFFF, " ", shadowTransparency) + + yPos = yPos + 1 + xPos = xPos + 2 + buffer.text(xPos + 2, yPos, 0x262626, "Клик левой кнопкой мыши: изменить позицию окошка"); yPos = yPos + 1 + buffer.text(xPos + 2, yPos, 0x262626, "Клик правой кнопкой: нарисовать еще одно такое же окошко"); yPos = yPos + 1 + buffer.text(xPos + 2, yPos, 0x262626, "Колесо мыши: изменить прозрачность окна"); yPos = yPos + 2 + buffer.text(xPos + 2, yPos, 0x262626, "Space: переключить фон между картинкой и статичным цветом"); yPos = yPos + 1 + buffer.text(xPos + 2, yPos, 0x262626, "Shift: изменить цвет фона на рандомный"); yPos = yPos + 1 + buffer.text(xPos + 2, yPos, 0x262626, "Tab: включить или отключить данную информационную панель"); yPos = yPos + 1 + buffer.text(xPos + 2, yPos, 0x262626, "Enter: выйти отсудова на хер"); yPos = yPos + 1 + end +end + +drawBackground() +drawWindow(xWindow, yWindow) +buffer.draw() + +while true do + local e = {event.pull()} + if e[1] == "touch" or e[1] == "drag" then + if e[5] == 0 then + drawBackground() + xWindow, yWindow = e[3], e[4] + drawWindow(xWindow, yWindow) + buffer.draw() + else + xWindow, yWindow = e[3], e[4] + drawWindow(xWindow, yWindow) + buffer.draw() + end + elseif e[1] == "key_down" then + if e[4] == 42 then + currentBackground = math.random(0x000000, 0xFFFFFF) + drawBackground() + drawWindow(xWindow, yWindow) + buffer.draw() + elseif e[4] == 28 then + buffer.square(1, 1, bufferWidth, bufferHeight, 0x262626, 0xFFFFFF, " ") + buffer.draw() + return + elseif e[4] == 57 then + risovatKartinku = not risovatKartinku + drawBackground() + drawWindow(xWindow, yWindow) + buffer.draw() + elseif e[4] == 15 then + showPanel = not showPanel + drawBackground() + drawWindow(xWindow, yWindow) + buffer.draw() + end + elseif e[1] == "scroll" then + if e[5] == 1 then + if transparency > 0.05 then + transparency = transparency - 0.05 + drawBackground() + drawWindow(xWindow, yWindow) + buffer.draw() + end + else + if transparency < 1 then + transparency = transparency + 0.05 + drawBackground() + drawWindow(xWindow, yWindow) + buffer.draw() + end + end + end +end + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/BufferDemo.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/BufferDemo.app/Resources/About/Russian.txt new file mode 100755 index 00000000..1d721885 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/BufferDemo.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Программа-демонстратор возможностей нашей библиотеки двойной буферизации изображения. Вся ОС работает именно на этой библиотеке. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/BufferDemo.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/BufferDemo.app/Resources/Icon.pic new file mode 100755 index 00000000..aa3c658a Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/BufferDemo.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/BufferDemo.app/Resources/Wallpaper.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/BufferDemo.app/Resources/Wallpaper.pic new file mode 100755 index 00000000..75a0427e Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/BufferDemo.app/Resources/Wallpaper.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Calendar.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Calendar.app/Main.lua new file mode 100755 index 00000000..0477130f --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Calendar.app/Main.lua @@ -0,0 +1,379 @@ +local ecs = require("ECSAPI") +local fs = require("filesystem") +local event = require("event") +local component = require("component") +local gpu = component.gpu + +--Список месяцев +local months = { + "Январь", + "Февраль", + "Март", + "Апрель", + "Май", + "Июнь", + "Июль", + "Август", + "Сентябрь", + "Октябрь", + "Ноябрь", + "Декабрь", +} + +--Количество дней в месяцах +local countOfDays = { + 31, + 28, + 31, + 30, + 31, + 30, + 31, + 31, + 30, + 31, + 30, + 31, +} + +--Сдвиг дня недели по дате в каждом месяце +local monthDateMove = { + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 3, + 2, + 3, + 2, + 3, +} + +--Графика +local numbers = { + ["1"] = { + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + }, + ["2"] = { + {1, 1, 1}, + {0, 0, 1}, + {1, 1, 1}, + {1, 0, 0}, + {1, 1, 1}, + }, + ["3"] = { + {1, 1, 1}, + {0, 0, 1}, + {1, 1, 1}, + {0, 0, 1}, + {1, 1, 1}, + }, + ["4"] = { + {1, 0, 1}, + {1, 0, 1}, + {1, 1, 1}, + {0, 0, 1}, + {0, 0, 1}, + }, + ["5"] = { + {1, 1, 1}, + {1, 0, 0}, + {1, 1, 1}, + {0, 0, 1}, + {1, 1, 1}, + }, + ["6"] = { + {1, 1, 1}, + {1, 0, 0}, + {1, 1, 1}, + {1, 0, 1}, + {1, 1, 1}, + }, + ["7"] = { + {1, 1, 1}, + {0, 0, 1}, + {0, 0, 1}, + {0, 0, 1}, + {0, 0, 1}, + }, + ["8"] = { + {1, 1, 1}, + {1, 0, 1}, + {1, 1, 1}, + {1, 0, 1}, + {1, 1, 1}, + }, + ["9"] = { + {1, 1, 1}, + {1, 0, 1}, + {1, 1, 1}, + {0, 0, 1}, + {1, 1, 1}, + }, + ["0"] = { + {1, 1, 1}, + {1, 0, 1}, + {1, 0, 1}, + {1, 0, 1}, + {1, 1, 1}, + }, +} + +--Всякие переменные +local constants = { + xSpaceBetweenNumbers = 2, + ySpaceBetweenNumbers = 1, + xSpaceBetweenMonths = 4, + ySpaceBetweenMonths = 1, + currentYear = 2015, + currentMonth = 9, + currentDay = 26, + programYear = 2015, + programMonth = 1, + proramDay = 1, + usualDayColor = 0x262626, + weekendColor = 0x880000, + backgroundColor = 0xEEEEEE, + dayNamesColor = 0x888888, + monthsColor = 0xCC0000, + currentDayColor = 0xFFFFFF, + bigNumberColor = 0x262626, +} + +local xMax, yMax = gpu.maxResolution() + +--Объекты для тача +local obj = {} +local function newObj(class, name, ...) + obj[class] = obj[class] or {} + obj[class][name] = {...} +end + +--Проверка года на "високосность" +local function visokosniy(year) + if year % 4 == 0 or year % 400 == 0 then return true else return false end +end + +--Отрисовать месяц +local function drawMonth(x, y, firstDay, countOfDays, year, month) + + local xPos, yPos = x, y + 4 + local counter = 1 + local startDrawing = false + local separator = string.rep(" ", constants.xSpaceBetweenNumbers) + ecs.colorText(x, y, constants.monthsColor, months[month]) + ecs.colorText(x, y + 2, constants.dayNamesColor,"Пн"..separator.."Вт"..separator.."Ср"..separator.."Чт"..separator.."Пт"..separator.."Сб"..separator.."Вс") + for j = 1, 6 do + xPos = x + for i = 1, 7 do + if i < 6 then gpu.setForeground(constants.usualDayColor) else gpu.setForeground(constants.weekendColor) end + if counter == constants.currentDay and year == constants.currentYear and month == constants.currentMonth then ecs.square(xPos-1, yPos, 4, 1, constants.weekendColor); gpu.setForeground(constants.currentDayColor) else gpu.setBackground(constants.backgroundColor) end + if counter > countOfDays then break end + if i >= firstDay then startDrawing = true end + if startDrawing then gpu.set(xPos, yPos, tostring(counter)); counter = counter + 1 end + xPos = xPos + constants.xSpaceBetweenNumbers + 2 + end + yPos = yPos + constants.ySpaceBetweenNumbers + 1 + end +end + +--Получить номер следующего дня +local function getNextDay(day) + if day < 7 then + return (day + 1) + else + return 1 + end +end + +--Просчитать данные о годе +local function calculateYear(year, dayOf1Jan) + local massivGoda = {} + local visokosniy = visokosniy(year) + + local firstDayPosition = dayOf1Jan + + --Получаем количество дней в каждом месяце + for month = 1, 12 do + --Создаем подмассив месяца в массиве года + massivGoda[month] = {} + --Если это февраль + if month == 2 then + --Если год високосный + if visokosniy then + massivGoda[month].countOfDays = 29 + massivGoda[month].firstDayPosition = firstDayPosition + firstDayPosition = getNextDay(firstDayPosition) + --Если не високосный + else + massivGoda[month].countOfDays = 28 + massivGoda[month].firstDayPosition = firstDayPosition + end + --Если не февраль + else + massivGoda[month].countOfDays = countOfDays[month] + massivGoda[month].firstDayPosition = firstDayPosition + for i = 1, monthDateMove[month] do + firstDayPosition = getNextDay(firstDayPosition) + end + end + end + + return massivGoda +end + +--Получить день недели первого января указанного года +local function polu4itDenNedeliPervogoJanvarja(year, debug) + local den = 0 + + local difference = math.abs(year - 1010) + local koli4estvoVisokosnih + + if difference % 4 == 0 then + koli4estvoVisokosnih = difference / 4 + elseif difference % 4 == 1 then + koli4estvoVisokosnih = math.floor(difference / 4) + elseif difference % 4 == 2 then + koli4estvoVisokosnih = math.floor(difference / 4) + elseif difference % 4 == 3 then + koli4estvoVisokosnih = math.floor(difference / 4) + 1 + end + + local sdvig = difference + koli4estvoVisokosnih + + if sdvig % 7 == 0 then + den = 1 + else + den = sdvig % 7 + 1 + end + + if debug then + print("Год: "..year) + print("Разница в годах: "..difference) + print("Кол-во високосных: "..koli4estvoVisokosnih) + print("Сдвиг по дням: "..sdvig) + print("День недели: "..den) + print(" ") + end + + return den +end + +--Нарисовать календарь +local function drawCalendar(xPos, yPos, year) + ecs.square(xPos, yPos, 120, 48, constants.backgroundColor) + --Получаем позицию первого января указанного года + local janFirst = polu4itDenNedeliPervogoJanvarja(year) + --Получаем массив года + local massivGoda = calculateYear(year, janFirst) + + --Перебираем массив года + for i = 1, #massivGoda do + --Рисуем месяц + drawMonth(xPos, yPos, massivGoda[i].firstDayPosition, massivGoda[i].countOfDays, year, i) + --Корректируем коорды + xPos = xPos + constants.xSpaceBetweenMonths + 27 + if i % 4 == 0 then xPos = 3; yPos = yPos + constants.ySpaceBetweenMonths + 15 end + end +end + +local function drawSymbol(x, y, symbol) + local xPos, yPos = x, y + for j = 1, #numbers[symbol] do + xPos = x + for i = 1, #numbers[symbol][j] do + if numbers[symbol][j][i] ~= 0 then + gpu.set(xPos, yPos, " ") + end + xPos = xPos + 2 + end + yPos = yPos + 1 + end +end + +local function drawYear(x, y, year) + year = tostring(year) + for i = 1, #year do + drawSymbol(x, y, string.sub(year, i, i)) + x = x + 8 + end +end + +local next, prev + +local function drawInfo() + local xPos, yPos = 127, 4 + ecs.square(xPos, yPos, 30, 5, constants.backgroundColor) + gpu.setBackground(constants.bigNumberColor) + drawYear(xPos, yPos, constants.programYear) + yPos = yPos + 6 + + local name = "Следующий год"; newObj("Buttons", name, ecs.drawButton(xPos, yPos, 30, 3, name, 0xDDDDDD, 0x262626)); yPos = yPos + 4 + name = "Предыдущий год"; newObj("Buttons", name, ecs.drawButton(xPos, yPos, 30, 3, name, 0xDDDDDD, 0x262626)); yPos = yPos + 4 + name = "Выйти"; newObj("Buttons", name, ecs.drawButton(xPos, yPos, 30, 3, name, 0xDDDDDD, 0x262626)); yPos = yPos + 4 + +end + +local function drawAll() + --Очищаем экран + ecs.square(1, 1, xMax, yMax, constants.backgroundColor) + --Рисуем календарик + drawCalendar(3, 2, constants.programYear) + --Рисуем парашу + drawInfo() +end + +-------------------------------------------------------------------------------------------------------------------- + +if xMax < 150 then error("This program requires Tier 3 GPU and Tier 3 Screen.") end +--Запоминаем старое разрешение экрана +local xOld, yOld = gpu.getResolution() +--Ставим максимальное +gpu.setResolution(xMax, yMax) +--Получаем данные о текущей дате (os.date выдает неверную дату и месяц, забавно) +constants.currentDay, constants.currentMonth, constants.currentYear = ecs.getHostTime(2) +constants.programDay, constants.programMonth, constants.programYear = constants.currentDay, constants.currentMonth, constants.currentYear +--Рисуем все +drawAll() + +while true do + local e = {event.pull()} + if e[1] == "touch" then + for key in pairs(obj["Buttons"]) do + if ecs.clickedAtArea(e[3], e[4], obj["Buttons"][key][1], obj["Buttons"][key][2], obj["Buttons"][key][3], obj["Buttons"][key][4]) then + ecs.drawButton(obj["Buttons"][key][1], obj["Buttons"][key][2], 30, 3, key, constants.weekendColor, constants.currentDayColor) + os.sleep(0.2) + + if key == "Следующий год" then + constants.programYear = constants.programYear + 1 + elseif key == "Предыдущий год" then + constants.programYear = constants.programYear - 1 + elseif key == "Выйти" then + gpu.setResolution(xOld, yOld) + ecs.prepareToExit() + return + end + + drawInfo() + drawCalendar(3, 2, constants.programYear) + + break + end + end + end +end + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Calendar.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Calendar.app/Resources/About/Russian.txt new file mode 100755 index 00000000..f29f8362 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Calendar.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Calendar - простая программа, не нуждающаяся в особом представлении. Красивый интерфейс позволяет легко узнать день недели конкретной даты любого года. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Calendar.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Calendar.app/Resources/Icon.pic new file mode 100755 index 00000000..fe793466 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Calendar.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Camera.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Camera.app/Main.lua new file mode 100755 index 00000000..03cab6da --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Camera.app/Main.lua @@ -0,0 +1,229 @@ +local component = require("component") +local ecs = require("ECSAPI") +local buffer = require("doubleBuffering") +local event = require("event") +local context = require("context") +local gpu = component.gpu +local camera + +if not component.isAvailable("camera") then + ecs.error("Этой программе требуется камера из мода Computronix.") + return +else + camera = component.camera +end + +local step = 0.04 +local from = step * 25 +local distanceLimit = 36 + +local widthOfImage, heightOfImage = 100, 50 + +local grayScale = { + 0x000000, + 0x111111, + 0x111111, + 0x222222, + 0x333333, + 0x333333, + 0x444444, + 0x555555, + 0x666666, + 0x777777, + 0x777777, + 0x888888, + 0x999999, + 0xaaaaaa, + 0xbbbbbb, + 0xbbbbbb, + 0xcccccc, + 0xdddddd, + 0xeeeeee, + 0xeeeeee, + 0xffffff, +} + +local rainbow = { + 0x000000, + 0x000040, + 0x000080, + 0x002480, + 0x0000BF, + 0x0024BF, + 0x002400, + 0x004900, + 0x006D00, + 0x009200, + 0x00B600, + 0x33DB00, + 0x99FF00, + 0xCCFF00, + 0xFFDB00, + 0xFFB600, + 0xFF9200, + 0xFF6D00, + 0xFF4900, + 0xFF2400, + 0xFF0000, +} + +local currentPalette = rainbow + +local topObjects + +local currentTopObject = 0 + +local function gui() + topObjects = ecs.drawTopMenu(1, 1, widthOfImage, 0xeeeeee, currentTopObject, {"Камера", 0x000000}, {"Сделать снимок", 0x444444}, {"Параметры рендера", 0x444444}, {"Палитра", 0x444444}) +end + +local function capture(x, y) + local xPos, yPos = x, y + local distance, color + + local oldPixels = ecs.info("auto", "auto", " ", " Делаю снимок... ") + + for y = from, -from, -step do + for x = -from, from, step do + distance = camera.distance(x, y) + if distance >= 0 then + if distance > distanceLimit then distance = distanceLimit end + + color = currentPalette[(#currentPalette + 1) - math.ceil(distance / (distanceLimit / #currentPalette))] + + buffer.set(xPos, yPos, color, 0x000000, " ") + buffer.set(xPos + 1, yPos, color, 0x000000, " ") + else + buffer.set(xPos, yPos, 0x000000, 0x000000, " ") + buffer.set(xPos + 1, yPos, 0x000000, 0x000000, " ") + end + + percent = (x * y) / (widthOfImage * heightOfImage) + xPos = xPos + 2 + end + xPos = x + yPos = yPos + 1 + end + + ecs.drawOldPixels(oldPixels) +end + +local function drawDistanceMeter() + local width = 4 + local xPos, yPos = widthOfImage - 3 - width, 3 + buffer.square(xPos, yPos, width + 2, #currentPalette * 2 + 2, 0x000000, 0x000000, " ") + yPos = yPos + 1 + xPos = xPos + 1 + for i = #currentPalette, 1, -1 do + buffer.square(xPos, yPos, width, 2, currentPalette[i], 0x000000, " ") + yPos = yPos + 2 + end +end + +local xOld, yOld = gpu.getResolution() +gpu.setResolution(100, 50) +buffer.flush() + +gui() +ecs.square(1, 2, widthOfImage, heightOfImage - 1, 0x000000) +buffer.square(1, 2, widthOfImage, heightOfImage - 1, 0x000000, 0x000000, " ") +capture(1, 1) +drawDistanceMeter() +buffer.draw() +gui() + +while true do + local e = {event.pull()} + if e[1] == "touch" then + for key in pairs(topObjects) do + if ecs.clickedAtArea(e[3], e[4], topObjects[key][1], topObjects[key][2], topObjects[key][3], topObjects[key][4]) then + currentTopObject = topObjects[key][5] + gui() + + if key == "Камера" then + + local action = context.menu(topObjects[key][1] - 1, 2, {"О программе"}, {"Выход"}) + + if action == "О программе" then + + local text = "Эта программа является тестом библиотеки двойной буферизации изображения, написана для проверки адекватности нескольких функций. Сама идея сперта у какого-то крутого парня с форума CC, однако немного доработана в GUI-плане. Такие дела." + + ecs.universalWindow("auto", "auto", 36, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x000000, "О программе \"Камера\""}, {"EmptyLine"}, {"TextField", 9, 0xFFFFFF, 0x000000, 0xaaaaaa, ecs.colors.blue, text}, {"EmptyLine"}, {"Button", {0x999999, 0xffffff, "OK"}}) + + elseif action == "Выход" then + gpu.setResolution(xOld, yOld) + ecs.prepareToExit() + return + end + + elseif key == "Сделать снимок" then + capture(1, 1) + drawDistanceMeter() + buffer.draw() + gui() + elseif key == "Параметры рендера" then + + local action = context.menu(topObjects[key][1] - 1, 2, {"Масштаб"}, {"Дальность рейкастинга"}) + + if action == "Масштаб" then + local data = ecs.universalWindow("auto", "auto", 36, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x000000, "Изменить масштаб:"}, {"EmptyLine"}, {"Slider", 0x262626, 0x880000, 1, 100, 100, "", "%"}, {"EmptyLine"}, {"Button", {0x999999, 0xffffff, "OK"}}) + + local part = (0.04 - 0.01) / 100 + local percent = part * data[1] + + step = percent + from = step * 25 + + capture(1, 1) + drawDistanceMeter() + buffer.draw() + gui() + elseif action == "Дальность рейкастинга" then + local data = ecs.universalWindow("auto", "auto", 36, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x000000, "Изменить дальность:"}, {"EmptyLine"}, {"Slider", 0x262626, 0x880000, 10, 36, distanceLimit, "", " блоков"}, {"EmptyLine"}, {"Button", {0x999999, 0xffffff, "OK"}}) + + distanceLimit = data[1] + + capture(1, 1) + drawDistanceMeter() + buffer.draw() + gui() + end + + elseif key == "Палитра" then + + local action = context.menu(topObjects[key][1] - 1, 2, {"Черно-белая"}, {"Термальная"}) + + if action == "Черно-белая" then + currentPalette = grayScale + capture(1, 1) + drawDistanceMeter() + buffer.draw() + gui() + elseif action == "Термальная" then + currentPalette = rainbow + capture(1, 1) + drawDistanceMeter() + buffer.draw() + gui() + end + end + + currentTopObject = 0 + gui() + break + end + end + end +end + + + + + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Camera.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Camera.app/Resources/About/Russian.txt new file mode 100755 index 00000000..23540c7b --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Camera.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Программа-рейкастер, делающая снимки местности с помощью камеры из мода Computronix. Разумеется, данный мод должен быть установлен для работы. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Camera.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Camera.app/Resources/Icon.pic new file mode 100755 index 00000000..09876074 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Camera.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ChristmasTree.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ChristmasTree.app/Main.lua new file mode 100755 index 00000000..d676ec51 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ChristmasTree.app/Main.lua @@ -0,0 +1,148 @@ +local component = require("component") +local ecs = require("ECSAPI") +local hologram +local c = 23 + +----------------------------------------------------------- + +if not component.isAvailable("hologram") then + ecs.error("Этой программе необходим голографический проектор 2 уровня.") + return +else + hologram = component.hologram +end + +----------------------------------------------------------- + +local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "Настройки анимации"}, + {"EmptyLine"}, + {"Selector", 0xFFFFFF, ecs.colors.orange, "Снегопад", "Легкий снежок", "Что-то сыпется", "Без осадков"}, + {"Selector", 0xFFFFFF, ecs.colors.orange, "Легкое вращение", "Быстрое вращение", "Турбина", "Дюраселл", "Без вращения"}, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "Размер елочки"}, + {"EmptyLine"}, + {"Slider", ecs.colors.white, ecs.colors.orange, 1, 100, 50, "", ""}, + {"EmptyLine"}, + {"CenterText", ecs.colors.white, "Программа закрывается через"}, + {"CenterText", ecs.colors.white, "CTRL + ALT + C"}, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0xffffff, "OK"}, {0x999999, 0xffffff, "Отмена"}} +) + +local snowMode, rotationMode, scale, buttonPress = data[1], data[2], data[3], data[4] + +scale = scale * 4 / 100 + +if snowMode == "Снегопад" then + snowMode = 0 +elseif snowMode == "Легкий снежок" then + snowMode = 0.2 +elseif snowMode == "Что-то сыпется" then + snowMode = 0.5 +end + +if rotationMode == "Легкое вращение" then + rotationMode = 5 +elseif rotationMode == "Быстрое вращение" then + rotationMode = 15 +elseif rotationMode == "Турбина" then + rotationMode = 25 +elseif rotationMode == "Дюраселл" then + rotationMode = 35 +elseif rotationMode == "Без вращения" then + rotationMode = 0 +end + +if buttonPress == "Отмена" then return end + +----------------------------------------------------------- + +-- создаем модель елки +local tSpruce = {3, 2, 2, 2, 2, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 4, 6, 8, 7, 6, 5, 4, 3, 6, 5, 4, 3, 2, 3, 2, 1} + +-- создаем таблицу с падающими снежинками +local tSnow = {} + +-- создаем палитру цветов +hologram.setPaletteColor(1, 0xFFFFFF) -- снег +hologram.setPaletteColor(2, 0x221100) -- ствол +hologram.setPaletteColor(3, 0x005522) -- хвоя + +local function cricle(x0, y, z0, R, i) -- задействуем алгоритм Брезенхэма для рисования кругов + local x = R + local z = 0 + local err = -R + while z <= x do + hologram.set(x + x0, y, z + z0, i) + hologram.set(z + x0, y, x + z0, i) + hologram.set(-x + x0, y, z + z0, i) + hologram.set(-z + x0, y, x + z0, i) + hologram.set(-x + x0, y, -z + z0, i) + hologram.set(-z + x0, y, -x + z0, i) + hologram.set(x + x0, y, -z + z0, i) + hologram.set(z + x0, y, -x + z0, i) + z = z + 1 + if err <= 0 then + err = err + (2 * z + 1) + else + x = x - 1 + err = err + (2 * (z - x) + 1) + end + end +end + +local function spruce() -- рисуем ель + for i = 1, 5 do + cricle(c, i, c, tSpruce[i], 2) -- отрисовываем основание ствола + cricle(c, i, c, tSpruce[i]-1, 2) + end + for j = 5, #tSpruce do + cricle(c, j, c, tSpruce[j]-1, 3) -- отрисовываем хвою + cricle(c, j, c, tSpruce[j]-2, 3) + end +end + +local function gen_snow() -- генерируем снежинку + local x, y, z = math.random(1, 46), 32, math.random(1, 46) + table.insert(tSnow,{x=x,y=y,z=z}) + hologram.set(x, y, z, 1) +end + +local function falling_snow() -- сдвигаем снежинки вниз + local i=1 + while i<=#tSnow do + if tSnow[i].y>1 then + local x,y,z=tSnow[i].x+math.random(-1, 1), tSnow[i].y-1, tSnow[i].z+math.random(-1, 1) + if x<1 then x=1 end + if x>46 then x=46 end + if z<1 then z=1 end + if z>46 then z=46 end + c=hologram.get(x, y, z) + if c==0 or c==1 then + hologram.set(tSnow[i].x, tSnow[i].y, tSnow[i].z, 0) + tSnow[i].x, tSnow[i].y, tSnow[i].z=x,y,z + hologram.set(x, y, z, 1) + i=i+1 + else + table.remove(tSnow,i) + end + else + table.remove(tSnow,i) + end + os.sleep(snowMode) + end +end + +ecs.info("auto", "auto", "", "Счастливого нового года!") + +hologram.clear() +hologram.setScale(scale) +hologram.setRotationSpeed(rotationMode, 0, 23, 0) + +spruce() +while 1 do + gen_snow() + falling_snow() +end \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ChristmasTree.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ChristmasTree.app/Resources/About/Russian.txt new file mode 100755 index 00000000..b0f5477c --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ChristmasTree.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Красивая новогодняя программа, написанная разработчиком Doob, сотворяющая атмосферу праздника в любом месте, где бы вы ни находились. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ChristmasTree.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ChristmasTree.app/Resources/Icon.pic new file mode 100755 index 00000000..ac91b177 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ChristmasTree.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/CodeDoor.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/CodeDoor.app/Main.lua new file mode 100755 index 00000000..1fab2147 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/CodeDoor.app/Main.lua @@ -0,0 +1,276 @@ +local rs +local component = require("component") +local gpu = component.gpu +local unicode = require("unicode") +local ecs = require("ECSAPI") +local sides = require("sides") +local event = require("event") +local fs = require("filesystem") +local serialization = require("serialization") + +if not component.isAvailable("redstone") then + ecs.error("This program requires Redstone I/O block or Redstone Card to work.") + return +else + rs = component.redstone +end + +------------------------------------------------------------------------------------------------------------ + +local colors = { + background = 0x202020, + borders = 0xFFDD00, +} + +------------------------------------------------------------------------------------------------------------ + +local keyPad = { + {"1", "2", "3"}, + {"4", "5", "6"}, + {"7", "8", "9"}, + {"*", "0", "#"}, +} + +local xSize, ySize +local buttons = {} +local biometry = {} +local input + +local password = "12345" + +local showPassword = true +local showKeyPresses = true + +local nicknames = { + "IgorTimofeev" +} + +local pathToConfig = "System/CodeDoor/Config.cfg" +local function saveConfig() + local file = io.open(pathToConfig, "w") + local massiv = {["password"] = password, ["nicknames"] = nicknames, ["showPassword"] = showPassword, ["showKeyPresses"] = showKeyPresses} + file:write(serialization.serialize(massiv)) + file:close() +end + +local function loadConfig() + if fs.exists(pathToConfig) then + local massiv = {} + local file = io.open(pathToConfig, "r") + local stroka = file:read("*a") + massiv = serialization.unserialize(stroka) + file:close() + nicknames = massiv.nicknames + password = massiv.password + showPassword = massiv.showPassword + showKeyPresses = massiv.showKeyPresses + else + fs.makeDirectory(fs.path(pathToConfig)) + local data = ecs.universalWindow("auto", "auto", 30, 0xEEEEEE, true, {"EmptyLine"}, {"CenterText", 0x880000, "Добро пожаловать в программу"}, {"CenterText", 0x880000, "конфигурации кодовой двери!"}, {"EmptyLine"}, {"CenterText", 0x262626, "Введите ваш пароль:"}, {"Input", 0x262626, 0x880000, "12345"}, {"EmptyLine"}, {"Switch", 0xF2B233, 0xffffff, 0x262626, "Показывать вводимый пароль", true}, {"EmptyLine"}, {"Switch", 0x3366CC, 0xffffff, 0x262626, "Показывать нажатие клавиш", true}, {"EmptyLine"}, {"Button", {0xbbbbbb, 0xffffff, "OK"}}) + if data[1] == "" or tonumber(data[1]) == nil then ecs.error("Указан неверный пароль. По умолчанию он будет 12345."); password = "12345" else password = data[1] end + showPassword = data[2] + showKeyPresses = data[3] + saveConfig() + end +end + +local function drawKeyPad(x, y) + local xPos, yPos = x, y + buttons = {} + for j = 1, #keyPad do + xPos = x + for i = 1, #keyPad[j] do + ecs.drawFramedButton(xPos, yPos, 5, 3, keyPad[j][i], colors.borders) + buttons[keyPad[j][i]] = {xPos, yPos, xPos + 4, yPos + 2} + xPos = xPos + 6 + end + yPos = yPos + 3 + end +end + +local function visualScan(x, y, timing) + local yPos = y + gpu.setBackground(colors.background) + gpu.setForeground(colors.borders) + + gpu.set(x, yPos, "╞══════════╡") + yPos = yPos - 1 + os.sleep(timing) + + for i = 1, 3 do + gpu.set(x, yPos, "╞══════════╡") + gpu.set(x, yPos + 1, "│ │") + yPos = yPos - 1 + os.sleep(timing) + end + + yPos = yPos + 2 + + for i = 1, 3 do + gpu.set(x, yPos, "╞══════════╡") + gpu.set(x, yPos - 1, "│ │") + yPos = yPos + 1 + os.sleep(timing) + end + gpu.set(x, yPos - 1, "│ │") +end + +local function infoPanel(info, background, foreground, hideData) + ecs.square(1, 1, xSize, 3, background) + local text if hideData then + text = ecs.stringLimit("start", string.rep("*", unicode.len(info)), xSize - 4) + else + text = ecs.stringLimit("start", info, xSize - 4) + end + ecs.colorText(math.ceil(xSize / 2 - unicode.len(text) / 2) + 1 , 2, foreground, text) +end + +local function drawAll() + local xPos, yPos = 3, 5 + + --Как прописывать знаки типа © § ® ™ + + --кейпад + gpu.setBackground(colors.background) + drawKeyPad(xPos, yPos) + + --Био + xPos = xPos + 18 + ecs.border(xPos, yPos, 12, 6, colors.background, colors.borders) + ecs.square(xPos + 5, yPos + 2, 2, 2, colors.borders) + gpu.setBackground(colors.background) + biometry = {xPos, yPos, xPos + 11, yPos + 5} + + --Био текст + yPos = yPos + 7 + xPos = xPos + 1 + gpu.set(xPos + 3, yPos, "ECS®") + gpu.set(xPos + 1, yPos + 1, "Security") + gpu.set(xPos + 1, yPos + 2, "Systems™") + +end + +local function checkNickname(name) + for i = 1, #nicknames do + if name == nicknames[i] then + return true + end + end + return false +end + +local function pressButton(x, y, name) + ecs.square(x, y, 5, 3, colors.borders) + gpu.setForeground(colors.background) + gpu.set(x + 2, y + 1, name) + os.sleep(0.2) +end + +local function waitForExit() + local e2 = {event.pull(3, "touch")} + if #e2 > 0 then + if ecs.clickedAtArea(e2[3], e2[4], buttons["*"][1], buttons["*"][2], buttons["*"][3], buttons["*"][4]) then + pressButton(buttons["*"][1], buttons["*"][2], "*") + return true + end + end + return false +end + +local function redstone(go) + if go then + rs.setOutput(sides.top, 15) + local goexit = waitForExit() + rs.setOutput(sides.top, 0) + rs.setOutput(sides.bottom, 0) + return goexit + else + rs.setOutput(sides.bottom, 15) + os.sleep(2) + rs.setOutput(sides.top, 0) + rs.setOutput(sides.bottom, 0) + end + return false +end + +------------------------------------------------------------------------------------------------------------ + +ecs.prepareToExit(colors.background) +loadConfig() + +local oldWidth, oldHeight = gpu.getResolution() +gpu.setResolution(34, 17) +xSize, ySize = 34, 17 + +drawAll() +infoPanel("Введите пароль", colors.borders, colors.background) + +while true do + local e = {event.pull()} + if e[1] == "touch" then + for key in pairs(buttons) do + if ecs.clickedAtArea(e[3], e[4], buttons[key][1], buttons[key][2], buttons[key][3], buttons[key][4]) then + + if showKeyPresses then + pressButton(buttons[key][1], buttons[key][2], key) + end + + if key == "*" then + input = nil + infoPanel("Поле ввода очищено", colors.borders, colors.background) + elseif key == "#" then + drawAll() + if input == password then + infoPanel("Доступ разрешён!", ecs.colors.green, 0xFFFFFF) + local goexit = redstone(true) + for i = 1, #nicknames do + if nicknames[i] == e[6] then nicknames[i] = nil end + end + table.insert(nicknames, e[6]) + saveConfig() + + if goexit then + ecs.prepareToExit() + gpu.setResolution(oldWidth, oldHeight) + ecs.prepareToExit() + return + end + else + infoPanel("Доступ запрещён!", ecs.colors.red, 0xFFFFFF) + redstone(false) + end + infoPanel("Введите пароль", colors.borders, colors.background) + input = nil + else + input = (input or "") .. key + + infoPanel(input, colors.borders, colors.background, not showPassword) + end + drawAll() + + break + end + end + + if ecs.clickedAtArea(e[3], e[4], biometry[1], biometry[2], biometry[3], biometry[4]) then + visualScan(biometry[1], biometry[2] + 4, 0.08) + if checkNickname(e[6]) then + infoPanel("Привет, " .. e[6], ecs.colors.green, 0xFFFFFF) + redstone(true) + else + infoPanel("В доступе отказано!", ecs.colors.red, 0xFFFFFF) + redstone(false) + end + infoPanel("Введите пароль", colors.borders, colors.background) + drawAll() + end + end +end + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/CodeDoor.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/CodeDoor.app/Resources/About/Russian.txt new file mode 100755 index 00000000..a2f0d277 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/CodeDoor.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Программа для защиты вашего жилища от нежелательных гостей. При старте вы указываете желаемый пароль, а как только вы или ваш друг его корректно ввели, система автоматически вносит вас в список доверенных пользователей, так что вы сможете пользоваться биометрической защитой, не тратя время на ввод пароля. Крайне красивая и полезная программа. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/CodeDoor.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/CodeDoor.app/Resources/Icon.pic new file mode 100755 index 00000000..e17de0ae Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/CodeDoor.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Main.lua new file mode 100644 index 00000000..8ef76f6d --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Main.lua @@ -0,0 +1,60 @@ + +require("advancedLua") +local component = require("component") +local computer = require("computer") +local image = require("image") +local buffer = require("doubleBuffering") +local GUI = require("GUI") +local fs = require("filesystem") +local unicode = require("unicode") +local MineOSPaths = require("MineOSPaths") +local MineOSCore = require("MineOSCore") +local MineOSInterface = require("MineOSInterface") + +---------------------------------------------------------------------------------------------------------------- + +local resourcesPath = MineOSCore.getCurrentApplicationResourcesDirectory() +local modulesPath = resourcesPath .. "Modules/" +local localization = MineOSCore.getLocalization(resourcesPath .. "Localization/") + +local mainContainer, window = MineOSInterface.addWindow(MineOSInterface.tabbedWindow(1, 1, 80, 25)) + +---------------------------------------------------------------------------------------------------------------- + +window.contentContainer = window:addChild(GUI.container(1, 4, window.width, window.height - 3)) + +local function loadModules() + local fileList = fs.sortedList(modulesPath, "name", false) + for i = 1, #fileList do + local loadedFile, reason = loadfile(modulesPath .. fileList[i]) + if loadedFile then + local pcallSuccess, reason = pcall(loadedFile, mainContainer, window, localization) + if pcallSuccess then + window.tabBar:addItem(reason.name).onTouch = function() + reason.onTouch() + end + else + error("Failed to call loaded module \"" .. tostring(fileList[i]) .. "\": " .. tostring(reason)) + end + else + error("Failed to load module \"" .. tostring(fileList[i]) .. "\": " .. tostring(reason)) + end + end +end + +window.onResize = function(width, height) + window.tabBar.width = width + window.backgroundPanel.width = width + window.backgroundPanel.height = height - 3 + window.contentContainer.width = width + window.contentContainer.height = window.backgroundPanel.height + + window.tabBar:getItem(window.tabBar.selectedItem).onTouch() +end + +---------------------------------------------------------------------------------------------------------------- + +loadModules() +window.onResize(80, 25) + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Icon.pic new file mode 100644 index 00000000..748c38bb Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Localization/English.lang b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Localization/English.lang new file mode 100755 index 00000000..41fd3ad3 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Localization/English.lang @@ -0,0 +1,24 @@ +{ + moduleDisk = "Disks", + moduleRAM = "RAM", + moduleEvent = "Events", + moduleLua = "Lua interpreter", + + diskLabel = "Disk label", + bootable = "Bootable", + of = "of", + free = "Free", + options = "Options", + arguments = "Arguments", + format = "Format", + execute = "Execute", + waitingEvents = "Waiting for events", + processingEnabled = "Event processing enabled", + luaInfo = { + {color = 0x880000, text = _G._VERSION .. " Copyright (C) 1994-2017 Lua.org, PUC-Rio"}, + "Type a statement and hit Enter to evaluate it", + "Prefix an expression with \"=\" to show its value", + " " + }, + luaType = "Type statement here" +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Localization/Russian.lang b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Localization/Russian.lang new file mode 100755 index 00000000..7ce06038 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Localization/Russian.lang @@ -0,0 +1,24 @@ +{ + moduleDisk = "Диски", + moduleRAM = "Память", + moduleEvent = "События", + moduleLua = "Интерпретатор Lua", + + diskLabel = "Имя диска", + bootable = "Загрузочный", + of = "из", + free = "Свободно", + options = "Опции", + arguments = "Аргументы", + format = "Форматировать", + execute = "Выполнить", + waitingEvents = "Ожидание событий", + processingEnabled = "Обработка событий", + luaInfo = { + {color = 0x880000, text = _G._VERSION .. " Copyright (C) 1994-2017 Lua.org, PUC-Rio"}, + "Введите выражение и нажмите Enter, чтобы выполнить его", + "Используйте префикс \"=\", чтобы вывести значение переменной", + " ", + }, + luaType = "Введите выражение здесь" +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Modules/1.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Modules/1.lua new file mode 100644 index 00000000..396f6548 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Modules/1.lua @@ -0,0 +1,189 @@ + +local args = {...} +local mainContainer, window, localization = args[1], args[2], args[3] + +require("advancedLua") +local component = require("component") +local computer = require("computer") +local GUI = require("GUI") +local buffer = require("doubleBuffering") +local image = require("image") +local MineOSPaths = require("MineOSPaths") +local MineOSInterface = require("MineOSInterface") +local unicode = require("unicode") +local syntax = require("syntax") + +---------------------------------------------------------------------------------------------------------------- + +local module = {} +module.name = localization.moduleLua + +---------------------------------------------------------------------------------------------------------------- + +module.onTouch = function() + window.contentContainer:deleteChildren() + + _G.component = require("component") + _G.computer = require("computer") + + local textBox = window.contentContainer:addChild(GUI.textBox(1, 1, window.contentContainer.width, window.contentContainer.height - 3, nil, 0x444444, localization.luaInfo, 1, 2, 1)) + textBox.scrollBarEnabled = true + + local placeholder = localization.luaType + local input = window.contentContainer:addChild(GUI.input(1, window.contentContainer.height - 2, window.contentContainer.width, 3, 0x2D2D2D, 0xE1E1E1, 0x666666, 0x2D2D2D, 0xE1E1E1, "", placeholder, true)) + + input.textDrawMethod = function(x, y, color, text) + if text == placeholder then + buffer.text(x, y, color, text) + else + syntax.highlightString(x, y, text, 2) + end + end + + local function add(data, color) + for line in data:gmatch("[^\n]+") do + local wrappedLine = string.wrap(line, textBox.textWidth) + for i = 1, #wrappedLine do + table.insert(textBox.lines, color and {color = color, text = wrappedLine[i]} or wrappedLine[i]) + end + end + + textBox:scrollToEnd() + -- local abc = " "; for i = 1, 30 do abc = abc .. "p " end; print(abc) + end + + input.historyEnabled = true + + input.autoComplete.colors.default.background = 0x4B4B4B + input.autoComplete.colors.default.text = 0xC3C3C3 + input.autoComplete.colors.default.textMatch = 0xFFFFFF + input.autoComplete.colors.selected.background = 0x777777 + input.autoComplete.colors.selected.text = 0xD2D2D2 + input.autoComplete.colors.selected.textMatch = 0xFFFFFF + input.autoComplete.scrollBar.colors.background = 0x666666 + input.autoComplete.scrollBar.colors.foreground = 0xAAAAAA + + input.autoCompleteVerticalAlignment = GUI.alignment.vertical.top + input.autoCompleteEnabled = true + input.autoCompleteMatchMethod = function() + local inputTextLength = unicode.len(input.text) + local left, right = 1, inputTextLength + for i = input.cursorPosition - 1, 1, -1 do + if not unicode.sub(input.text, i, i):match("[%w%_%.]+") then + left = i + 1 + break + end + end + for i = input.cursorPosition, inputTextLength do + if not unicode.sub(input.text, i, i):match("[%w%_%.]+") then + right = i - 1 + break + end + end + local cykaText = unicode.sub(input.text, left, right) + + local array = {} + local t = _G + if cykaText:match("^[%w%_%.]+$") then + local words = {} + for word in cykaText:gmatch("[^%.]+") do + table.insert(words, word) + end + local dotInEnd = unicode.sub(cykaText, -1, -1) == "." + local wordCount = #words - (dotInEnd and 0 or 1) + + for i = 1, wordCount do + if t[words[i]] and type(t[words[i]]) == "table" then + t = t[words[i]] + else + input.autoComplete:clear() + return + end + end + + input.autoComplete.resultLeft = unicode.sub(input.text, 1, left - 1) + if wordCount > 0 then + input.autoComplete.resultLeft = input.autoComplete.resultLeft .. table.concat(words, ".", 1, wordCount) .. "." + end + input.autoComplete.resultRight = unicode.sub(input.text, right + 1, -1) + + if dotInEnd then + for key, value in pairs(t) do + table.insert(array, tostring(key)) + end + input.autoComplete:match(array) + else + for key, value in pairs(t) do + table.insert(array, tostring(key)) + end + input.autoComplete:match(array, words[#words]) + end + elseif input.text == "" then + input.autoComplete.resultLeft = "" + input.autoComplete.resultRight = "" + for key, value in pairs(t) do + table.insert(array, tostring(key)) + end + input.autoComplete:match(array) + else + input.autoComplete:clear() + end + end + + input.autoComplete.onItemSelected = function() + input.text = input.autoComplete.resultLeft .. input.autoComplete.items[input.autoComplete.selectedItem] + input:setCursorPosition(unicode.len(input.text) + 1) + input.text = input.text .. input.autoComplete.resultRight + + if input.autoCompleteEnabled then + input.autoCompleteMatchMethod() + end + + mainContainer:draw() + buffer.draw() + end + + input.onInputFinished = function() + if input.text:len() > 0 then + local oldPrint = print + + print = function(...) + local args = {...} + for i = 1, #args do + if type(args[i]) == "table" then + args[i] = table.toString(args[i], true, 2, false, 2) + else + args[i] = tostring(args[i]) + end + end + add(table.concat(args, " ")) + end + + add("> " .. input.text, 0xAAAAAA) + + if input.text:match("^%=") then + input.text = "return " .. unicode.sub(input.text, 2, -1) + end + + local result, reason = load(input.text) + if result then + local data = {xpcall(result, debug.traceback())} + if data[1] then + print(table.unpack(data, 2)) + else + add(tostring(data[2]), 0x880000) + end + else + add(tostring(reason), 0x880000) + end + + print = oldPrint + + input.text = "" + end + end +end + +---------------------------------------------------------------------------------------------------------------- + +return module \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Modules/2.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Modules/2.lua new file mode 100644 index 00000000..e767408e --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Modules/2.lua @@ -0,0 +1,107 @@ + +local args = {...} +local mainContainer, window, localization = args[1], args[2], args[3] + +require("advancedLua") +local component = require("component") +local computer = require("computer") +local GUI = require("GUI") +local buffer = require("doubleBuffering") +local image = require("image") +local MineOSPaths = require("MineOSPaths") +local MineOSInterface = require("MineOSInterface") + +---------------------------------------------------------------------------------------------------------------- + +local module = {} +module.name = localization.moduleDisk + +local HDDImage = image.load(MineOSPaths.icons .. "HDD.pic") +local floppyImage = image.load(MineOSPaths.icons .. "Floppy.pic") + +---------------------------------------------------------------------------------------------------------------- + +module.onTouch = function() + window.contentContainer:deleteChildren() + local container = window.contentContainer:addChild(GUI.container(1, 1, window.contentContainer.width, window.contentContainer.height)) + + local y = 2 + for address in component.list("filesystem") do + local proxy = component.proxy(address) + local isBoot = computer.getBootAddress() == proxy.address + local isReadOnly = proxy.isReadOnly() + + local diskContainer = container:addChild(GUI.container(1, y, container.width, 4)) + + local button = diskContainer:addChild(GUI.adaptiveRoundedButton(1, 3, 2, 0, 0x2D2D2D, 0xE1E1E1, 0x0, 0xE1E1E1, localization.options)) + button.onTouch = function() + local container = MineOSInterface.addUniversalContainer(mainContainer, localization.options) + local inputField = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, proxy.getLabel() or "", localization.diskLabel)) + inputField.onInputFinished = function() + if inputField.text and inputField.text:len() > 0 then + proxy.setLabel(inputField.text) + + container:delete() + module.onTouch() + end + end + + local formatButton = container.layout:addChild(GUI.button(1, 1, 36, 3, 0xC3C3C3, 0x2D2D2D, 0x666666, 0xE1E1E1, localization.format)) + formatButton.onTouch = function() + local list = proxy.list("/") + for i = 1, #list do + proxy.remove(list[i]) + end + + container:delete() + module.onTouch() + end + formatButton.disabled = isReadOnly + + local switch = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x1E1E1E, 0xE1E1E1, 0xBBBBBB, localization.bootable .. ":", isBoot)).switch + switch.onStateChanged = function() + if switch.state then + computer.setBootAddress(proxy.address) + + container:delete() + module.onTouch() + end + end + + mainContainer:draw() + buffer.draw() + end + button.localX = diskContainer.width - button.width - 1 + + local width = diskContainer.width - button.width - 17 + local x = 13 + local spaceTotal = proxy.spaceTotal() + local spaceUsed = proxy.spaceUsed() + + diskContainer:addChild(GUI.image(3, 1, isReadOnly and floppyImage or HDDImage)) + diskContainer:addChild(GUI.label(x, 1, width, 1, 0x2D2D2D, (proxy.getLabel() or "Unknown") .. " (" .. (isBoot and (localization.bootable .. ", ") or "") .. proxy.address .. ")")) + diskContainer:addChild(GUI.progressBar(x, 3, width, 0x66DB80, 0xD2D2D2, 0xD2D2D2, spaceUsed / spaceTotal * 100, true)) + diskContainer:addChild(GUI.label(x, 4, width, 1, 0xBBBBBB, localization.free .. " " .. math.roundToDecimalPlaces((spaceTotal - spaceUsed) / 1024 / 1024, 2) .. " MB " .. localization.of .. " " .. math.roundToDecimalPlaces(spaceTotal / 1024 / 1024, 2) .. " MB")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + + y = y + diskContainer.height + 1 + end + + container.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "scroll" then + if eventData[5] < 0 or container.children[1].localY < 2 then + for i = 1, #container.children do + container.children[i].localY = container.children[i].localY + eventData[5] + end + + mainContainer:draw() + buffer.draw() + end + elseif eventData[1] == "component_added" or eventData[1] == "component_removed" and eventData[3] == "filesystem" then + module.onTouch() + end + end +end + +---------------------------------------------------------------------------------------------------------------- + +return module \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Modules/3.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Modules/3.lua new file mode 100644 index 00000000..89e8a290 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Modules/3.lua @@ -0,0 +1,146 @@ + +local args = {...} +local mainContainer, window, localization = args[1], args[2], args[3] + +require("advancedLua") +local component = require("component") +local computer = require("computer") +local GUI = require("GUI") +local buffer = require("doubleBuffering") +local image = require("image") +local MineOSPaths = require("MineOSPaths") +local MineOSInterface = require("MineOSInterface") +local unicode = require("unicode") + +---------------------------------------------------------------------------------------------------------------- + +local module = {} +module.name = localization.moduleRAM + +---------------------------------------------------------------------------------------------------------------- + +module.onTouch = function() + window.contentContainer:deleteChildren() + + local cykaPanel = window.contentContainer:addChild(GUI.panel(1, 1, 1, 1, 0xE1E1E1)) + + local mainLayout = window.contentContainer:addChild(GUI.layout(1, 1, window.contentContainer.width, window.contentContainer.height, 2, 1)) + mainLayout:setColumnWidth(1, GUI.sizePolicies.percentage, 0.3) + mainLayout:setColumnWidth(2, GUI.sizePolicies.percentage, 0.7) + mainLayout:setCellFitting(1, 1, true, true) + mainLayout:setCellFitting(2, 1, true, true) + + local tree = mainLayout:setCellPosition(1, 1, mainLayout:addChild(GUI.tree(1, 1, 1, 1, 0xE1E1E1, 0x3C3C3C, 0x3C3C3C, 0xAAAAAA, 0x3C3C3C, 0xFFFFFF, 0xBBBBBB, 0xAAAAAA, 0xC3C3C3, 0x444444, GUI.filesystemModes.both, GUI.filesystemModes.file))) + + local itemsLayout = mainLayout:setCellPosition(2, 1, mainLayout:addChild(GUI.layout(1, 1, 1, 1, 1, 2))) + itemsLayout:setRowHeight(1, GUI.sizePolicies.percentage, 0.6) + itemsLayout:setRowHeight(2, GUI.sizePolicies.percentage, 0.4) + itemsLayout:setCellFitting(1, 1, true, false, 4, 0) + itemsLayout:setCellFitting(1, 2, true, true) + + local infoLabel = itemsLayout:setCellPosition(1, 1, itemsLayout:addChild(GUI.label(1, 1, 1, 1, 0x3C3C3C, "nil")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) + local argumentsInputField = itemsLayout:setCellPosition(1, 1, itemsLayout:addChild(GUI.input(1, 1, 1, 3, 0xFFFFFF, 0x666666, 0x888888, 0xFFFFFF, 0x262626, nil, localization.arguments))) + local executeButton = itemsLayout:setCellPosition(1, 1, itemsLayout:addChild(GUI.button(1, 1, 1, 3, 0x3C3C3C, 0xFFFFFF, 0x0, 0xFFFFFF, localization.execute))) + local outputTextBox = itemsLayout:setCellPosition(1, 2, itemsLayout:addChild(GUI.textBox(1, 1, 1, 1, 0xFFFFFF, 0x888888, {"nil"}, 1, 1, 0))) + + local function updateList(tree, t, definitionName, offset) + local list = {} + for key in pairs(t) do + table.insert(list, key) + end + + local i, expandables = 1, {} + while i <= #list do + if type(t[list[i]]) == "table" then + table.insert(expandables, list[i]) + table.remove(list, i) + else + i = i + 1 + end + end + + table.sort(expandables, function(a, b) return unicode.lower(tostring(a)) < unicode.lower(tostring(b)) end) + table.sort(list, function(a, b) return unicode.lower(tostring(a)) < unicode.lower(tostring(b)) end) + + for i = 1, #expandables do + local definition = definitionName .. expandables[i] + + tree:addItem(tostring(expandables[i]), definition, offset, true) + if tree.expandedItems[definition] then + updateList(tree, t[expandables[i]], definition, offset + 2) + end + end + + for i = 1, #list do + tree:addItem(tostring(list[i]), {key = list[i], value = t[list[i]]}, offset, false) + end + end + + local function out(text) + local wrappedLines = string.wrap(text, outputTextBox.width - 2) + for i = 1, #wrappedLines do + table.insert(outputTextBox.lines, wrappedLines[i]) + end + end + + tree.onItemExpanded = function() + tree.items = {} + updateList(tree, _G, "_G", 1) + end + + tree.onItemSelected = function() + local valueType = type(tree.selectedItem.value) + local valueIsFunction = valueType == "function" + + executeButton.disabled = not valueIsFunction + argumentsInputField.disabled = executeButton.disabled + + infoLabel.text = tostring(tree.selectedItem.key) .. " (" .. valueType .. ")" + outputTextBox.lines = {} + + if valueIsFunction then + out("nil") + else + out(tostring(tree.selectedItem.value)) + end + end + + executeButton.onTouch = function() + outputTextBox.lines = {} + + local data = "local method = ({...})[1]; return method(" .. (argumentsInputField.text or "") .. ")" + local success, reason = load(data) + if success then + local success, reason = pcall(success, tree.selectedItem.value) + if success then + if type(reason) == "table" then + local serialized = table.toString(reason, true, 2, false, 3) + for line in serialized:gmatch("[^\n]+") do + out(line) + end + else + out(tostring(reason)) + end + else + out("Failed to pcall loaded string \"" .. data .. "\": " .. reason) + end + else + out("Failed to load string \"" .. data .. "\": " .. reason) + end + + mainContainer:draw() + buffer.draw() + end + + + executeButton.disabled = true + argumentsInputField.disabled = true + executeButton.colors.disabled.background = 0x777777 + executeButton.colors.disabled.text = 0xD2D2D2 + + tree.onItemExpanded() +end + +---------------------------------------------------------------------------------------------------------------- + +return module \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Modules/4.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Modules/4.lua new file mode 100644 index 00000000..c0bd7ae9 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Control.app/Resources/Modules/4.lua @@ -0,0 +1,50 @@ + +local args = {...} +local mainContainer, window, localization = args[1], args[2], args[3] + +require("advancedLua") +local component = require("component") +local computer = require("computer") +local GUI = require("GUI") +local buffer = require("doubleBuffering") +local image = require("image") +local MineOSPaths = require("MineOSPaths") +local MineOSInterface = require("MineOSInterface") + +---------------------------------------------------------------------------------------------------------------- + +local module = {} +module.name = localization.moduleEvent + +---------------------------------------------------------------------------------------------------------------- + +module.onTouch = function() + window.contentContainer:deleteChildren() + + local container = window.contentContainer:addChild(GUI.container(1, 1, window.contentContainer.width, window.contentContainer.height)) + + local layout = container:addChild(GUI.layout(1, 1, container.width, window.contentContainer.height, 1, 1)) + layout:setCellAlignment(1, 1, GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + layout:setCellMargin(1, 1, 0, 1) + + local textBox = layout:addChild(GUI.textBox(1, 1, container.width - 4, container.height - 4, nil, 0x888888, {localization.waitingEvents .. "..."}, 1, 0, 0)) + local switch = layout:addChild(GUI.switchAndLabel(1, 1, 27, 6, 0x66DB80, 0x1E1E1E, 0xFFFFFF, 0x2D2D2D, localization.processingEnabled .. ": ", true)).switch + + container.eventHandler = function(mainContainer, object, eventData) + if switch.state and eventData[1] then + local lines = table.concat(eventData, " ") + lines = string.wrap(lines, textBox.width) + for i = 1, #lines do + table.insert(textBox.lines, lines[i]) + end + textBox:scrollToEnd() + + mainContainer:draw() + buffer.draw() + end + end +end + +---------------------------------------------------------------------------------------------------------------- + +return module \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Finder.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Finder.app/Main.lua new file mode 100644 index 00000000..2439c24b --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Finder.app/Main.lua @@ -0,0 +1,363 @@ + +local GUI = require("GUI") +local buffer = require("doubleBuffering") +local computer = require("computer") +local fs = require("filesystem") +local event = require("event") +local MineOSPaths = require("MineOSPaths") +local MineOSCore = require("MineOSCore") +local MineOSNetwork = require("MineOSNetwork") +local MineOSInterface = require("MineOSInterface") + +local args, options = require("shell").parse(...) + +------------------------------------------------------------------------------------------------------ + +local mainContainer, window = MineOSInterface.addWindow(MineOSInterface.filledWindow(1, 1, 88, 26, 0xF0F0F0)) + +local iconFieldYOffset = 2 +local scrollTimerID + +local favourites = { + {text = "Root", path = "/"}, + {text = "Desktop", path = MineOSPaths.desktop}, + {text = "Applications", path = MineOSPaths.applications}, + {text = "Pictures", path = MineOSPaths.pictures}, + {text = "System", path = MineOSPaths.system}, + {text = "Trash", path = MineOSPaths.trash}, +} +local resourcesPath = MineOSCore.getCurrentApplicationResourcesDirectory() +local favouritesPath = resourcesPath .. "Favourites.cfg" + +if fs.exists(favouritesPath) then + favourites = table.fromFile(favouritesPath) +else + table.toFile(favouritesPath, favourites) +end + +------------------------------------------------------------------------------------------------------ + +local workpathHistory = {} +local workpathHistoryCurrent = 0 + +local function updateFileListAndDraw() + window.iconField:updateFileList() + mainContainer:draw() + buffer.draw() +end + +local function workpathHistoryButtonsUpdate() + window.prevButton.disabled = workpathHistoryCurrent <= 1 + window.nextButton.disabled = workpathHistoryCurrent >= #workpathHistory +end + +local function addWorkpath(path) + workpathHistoryCurrent = workpathHistoryCurrent + 1 + table.insert(workpathHistory, workpathHistoryCurrent, path) + for i = workpathHistoryCurrent + 1, #workpathHistory do + workpathHistory[i] = nil + end + + workpathHistoryButtonsUpdate() + window.searchInput.text = "" + window.iconField.yOffset = iconFieldYOffset + window.iconField:setWorkpath(path) +end + +local function prevOrNextWorkpath(next) + if next then + if workpathHistoryCurrent < #workpathHistory then + workpathHistoryCurrent = workpathHistoryCurrent + 1 + end + else + if workpathHistoryCurrent > 1 then + workpathHistoryCurrent = workpathHistoryCurrent - 1 + end + end + + workpathHistoryButtonsUpdate() + window.iconField.yOffset = iconFieldYOffset + window.iconField:setWorkpath(workpathHistory[workpathHistoryCurrent]) + + updateFileListAndDraw() +end + +------------------------------------------------------------------------------------------------------ + +local function newSidebarItem(text, textColor, path) + local y = 1 + if #window.sidebarContainer.itemsContainer.children > 0 then + y = window.sidebarContainer.itemsContainer.children[#window.sidebarContainer.itemsContainer.children].localY + 1 + end + local object = window.sidebarContainer.itemsContainer:addChild(GUI.object(1, y, 1, 1)) + + object.text = text + object.textColor = textColor + object.path = path + + object.draw = function(object) + object.width = window.sidebarContainer.itemsContainer.width + + local textColor = object.textColor + if object.path == window.iconField.workpath then + textColor = 0xFFFFFF + buffer.square(object.x, object.y, object.width, 1, 0x3366CC, textColor, " ") + end + buffer.text(object.x + 1, object.y, textColor, string.limit(object.text, object.width - 1, "center")) + end + + object.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + if object.onTouch then + object.onTouch(object, eventData) + end + end + end + + return object +end + +local function sidebarItemOnTouch(object, eventData) + if eventData[5] == 0 then + if fs.isDirectory(object.path) then + addWorkpath(object.path) + mainContainer:draw() + buffer.draw() + + updateFileListAndDraw() + end + else + + end +end + +local function updateSidebar() + window.sidebarContainer.itemsContainer:deleteChildren() + + window.sidebarContainer.itemsContainer:addChild(newSidebarItem("Favourites", 0x3C3C3C)) + for i = 1, #favourites do + window.sidebarContainer.itemsContainer:addChild(newSidebarItem(" " .. fs.name(favourites[i].text), 0x555555, favourites[i].path)).onTouch = sidebarItemOnTouch + end + + if MineOSCore.properties.network.enabled and MineOSNetwork.getProxyCount() > 0 then + window.sidebarContainer.itemsContainer:addChild(newSidebarItem(" ", 0x3C3C3C)) + window.sidebarContainer.itemsContainer:addChild(newSidebarItem("Network", 0x3C3C3C)) + + for proxy, path in fs.mounts() do + if proxy.network then + window.sidebarContainer.itemsContainer:addChild(newSidebarItem(" " .. MineOSNetwork.getProxyName(proxy), 0x555555, path .. "/")).onTouch = sidebarItemOnTouch + end + end + end + + window.sidebarContainer.itemsContainer:addChild(newSidebarItem(" ", 0x3C3C3C)) + + window.sidebarContainer.itemsContainer:addChild(newSidebarItem("Mounts", 0x3C3C3C)) + for proxy, path in fs.mounts() do + if path ~= "/" and not proxy.network then + window.sidebarContainer.itemsContainer:addChild(newSidebarItem(" " .. (proxy.getLabel() or fs.name(path)), 0x555555, path .. "/")).onTouch = sidebarItemOnTouch + end + end +end + +window.titlePanel = window:addChild(GUI.panel(1, 1, 1, 3, 0xDDDDDD)) + +window.prevButton = window:addChild(GUI.adaptiveRoundedButton(9, 2, 1, 0, 0xFFFFFF, 0x3C3C3C, 0x3C3C3C, 0xFFFFFF, "<")) +window.prevButton.onTouch = function() + prevOrNextWorkpath(false) +end +window.prevButton.colors.disabled.background = window.prevButton.colors.default.background +window.prevButton.colors.disabled.text = 0xCCCCCC + +window.nextButton = window:addChild(GUI.adaptiveRoundedButton(14, 2, 1, 0, 0xFFFFFF, 0x3C3C3C, 0x3C3C3C, 0xFFFFFF, ">")) +window.nextButton.onTouch = function() + prevOrNextWorkpath(true) +end +window.nextButton.colors.disabled = window.prevButton.colors.disabled + +window.sidebarContainer = window:addChild(GUI.container(1, 4, 20, 1)) +window.sidebarContainer.panel = window.sidebarContainer:addChild(GUI.panel(1, 1, window.sidebarContainer.width, 1, 0xFFFFFF, MineOSCore.properties.transparencyEnabled and 0.24)) +window.sidebarContainer.itemsContainer = window.sidebarContainer:addChild(GUI.container(1, 1, window.sidebarContainer.width, 1)) + +window.iconField = window:addChild( + MineOSInterface.iconField( + 1, 4, 1, 1, 2, 2, 0x3C3C3C, 0x3C3C3C, + MineOSPaths.desktop + ) +) + +window.iconField.launchers.directory = function(icon) + addWorkpath(icon.path) + updateFileListAndDraw() +end + +window.iconField.launchers.showPackageContent = function(icon) + addWorkpath(icon.path) + updateFileListAndDraw() +end + +window.iconField.launchers.showContainingFolder = function(icon) + addWorkpath(fs.path(MineOSCore.readShortcut(icon.path))) + updateFileListAndDraw() +end + +window.scrollBar = window:addChild(GUI.scrollBar(1, 4, 1, 1, 0xC3C3C3, 0x444444, iconFieldYOffset, 1, 1, 1, 1, true)) + +window.searchInput = window:addChild(GUI.input(1, 2, 36, 1, 0xFFFFFF, 0x666666, 0xAAAAAA, 0xFFFFFF, 0x2D2D2D, nil, "Search", true)) +window.searchInput.onInputFinished = function() + window.iconField.filenameMatcher = window.searchInput.text + window.iconField.fromFile = 1 + window.iconField.yOffset = iconFieldYOffset + + updateFileListAndDraw() +end + +local function updateScrollBar() + local shownFilesCount = #window.iconField.fileList - window.iconField.fromFile + 1 + + local horizontalLines = math.ceil(shownFilesCount / window.iconField.iconCount.horizontal) + local minimumOffset = 3 - (horizontalLines - 1) * (MineOSCore.properties.iconHeight + MineOSCore.properties.iconVerticalSpaceBetween) - MineOSCore.properties.iconVerticalSpaceBetween + + if window.iconField.yOffset > iconFieldYOffset then + window.iconField.yOffset = iconFieldYOffset + elseif window.iconField.yOffset < minimumOffset then + window.iconField.yOffset = minimumOffset + end + + if shownFilesCount > window.iconField.iconCount.total then + window.scrollBar.hidden = false + window.scrollBar.maximumValue = math.abs(minimumOffset) + window.scrollBar.value = math.abs(window.iconField.yOffset - iconFieldYOffset) + else + window.scrollBar.hidden = true + end +end + +local overrideUpdateFileList = window.iconField.updateFileList +window.iconField.updateFileList = function(...) + overrideUpdateFileList(...) + updateScrollBar() +end + +window.iconField.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "scroll" then + eventData[5] = eventData[5] * 2 + window.iconField.yOffset = window.iconField.yOffset + eventData[5] + + updateScrollBar() + + local delta = window.iconField.yOffset - window.iconField.iconsContainer.children[1].localY + for i = 1, #window.iconField.iconsContainer.children do + window.iconField.iconsContainer.children[i].localY = window.iconField.iconsContainer.children[i].localY + delta + end + + mainContainer:draw() + buffer.draw() + + if scrollTimerID then + event.cancel(scrollTimerID) + scrollTimerID = nil + end + + scrollTimerID = event.timer(0.3, function() + computer.pushSignal("Finder", "updateFileList") + end, 1) + elseif (eventData[1] == "MineOSCore" or eventData[1] == "Finder") and eventData[2] == "updateFileList" then + if eventData[1] == "MineOSCore" then + window.iconField.yOffset = iconFieldYOffset + end + updateFileListAndDraw() + end +end + +window.statusBar = window:addChild(GUI.object(1, 1, 1, 1)) +window.statusBar.draw = function(object) + buffer.square(object.x, object.y, object.width, object.height, 0xFFFFFF, 0x3C3C3C, " ") + buffer.text(object.x + 1, object.y, 0x3C3C3C, string.limit(("root/" .. window.iconField.workpath):gsub("/+$", ""):gsub("%/+", " ► "), object.width - 1, "start")) +end +window.statusBar.eventHandler = function(mainContainer, object, eventData) + if (eventData[1] == "component_added" or eventData[1] == "component_removed") and eventData[3] == "filesystem" then + updateSidebar() + + mainContainer:draw() + buffer.draw() + elseif eventData[1] == "MineOSNetwork" then + if eventData[2] == "updateProxyList" or eventData[2] == "timeout" then + updateSidebar() + + mainContainer:draw() + buffer.draw() + end + end +end +window.sidebarResizer = window:addChild(GUI.resizer(1, 4, 3, 5, 0xFFFFFF, 0x0)) + +local function calculateSizes(width, height) + window.sidebarContainer.height = height - 3 + + window.sidebarContainer.panel.width = window.sidebarContainer.width + window.sidebarContainer.panel.height = window.sidebarContainer.height + + window.sidebarContainer.itemsContainer.width = window.sidebarContainer.width + window.sidebarContainer.itemsContainer.height = window.sidebarContainer.height + + window.sidebarResizer.localX = window.sidebarContainer.width - 1 + window.sidebarResizer.localY = math.floor(window.sidebarContainer.localY + window.sidebarContainer.height / 2 - window.sidebarResizer.height / 2 - 1) + + window.backgroundPanel.width = width - window.sidebarContainer.width + window.backgroundPanel.height = height - 4 + window.backgroundPanel.localX = window.sidebarContainer.width + 1 + window.backgroundPanel.localY = 4 + + window.statusBar.localX = window.sidebarContainer.width + 1 + window.statusBar.localY = height + window.statusBar.width = window.backgroundPanel.width + + window.titlePanel.width = width + window.searchInput.width = math.floor(width * 0.25) + window.searchInput.localX = width - window.searchInput.width - 1 + + window.iconField.width = window.backgroundPanel.width + window.iconField.height = height + 4 + window.iconField.localX = window.backgroundPanel.localX + window.iconField.localY = window.backgroundPanel.localY + + window.scrollBar.localX = window.width + window.scrollBar.height = window.backgroundPanel.height + window.scrollBar.shownValueCount = window.scrollBar.height - 1 + + window.actionButtons:moveToFront() +end + +window.onResize = function(width, height) + calculateSizes(width, height) + window.iconField:updateFileList() +end + +window.sidebarResizer.onResize = function(mainContainer, object, eventData, dragWidth, dragHeight) + window.sidebarContainer.width = window.sidebarContainer.width + dragWidth + window.sidebarContainer.width = window.sidebarContainer.width >= 5 and window.sidebarContainer.width or 5 + calculateSizes(window.width, window.height) +end + +window.sidebarResizer.onResizeFinished = function() + window.iconField:updateFileList() +end + +local overrideMaximize = window.actionButtons.maximize.onTouch +window.actionButtons.maximize.onTouch = function() + window.iconField.yOffset = iconFieldYOffset + overrideMaximize() +end + +------------------------------------------------------------------------------------------------------ + +if options.o and args[1] and fs.isDirectory(args[1]) then + addWorkpath(args[1]) +else + addWorkpath("/") +end + +updateSidebar() +window:resize(window.width, window.height) + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Finder.app/Resources/Favourites.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Finder.app/Resources/Favourites.cfg new file mode 100644 index 00000000..a1220e39 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Finder.app/Resources/Favourites.cfg @@ -0,0 +1 @@ +{[1]={["path"]="/",["text"]="Root"},[2]={["path"]="/MineOS/Desktop/",["text"]="Desktop"},[3]={["path"]="/MineOS/Applications/",["text"]="Applications"},[4]={["path"]="/MineOS/Pictures/",["text"]="Pictures"},[5]={["path"]="/MineOS/System/",["text"]="System"},[6]={["path"]="/MineOS/Trash/",["text"]="Trash"}} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Finder.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Finder.app/Resources/Icon.pic new file mode 100644 index 00000000..3a4281b9 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Finder.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FlappyBird.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FlappyBird.app/Main.lua new file mode 100755 index 00000000..50affd38 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FlappyBird.app/Main.lua @@ -0,0 +1,294 @@ +local image = require("image") +local buffer = require("doubleBuffering") +local keyboard = require("keyboard") +local bigLetters = require("bigLetters") +local fs = require("filesystem") +local serialization = require("serialization") +local ecs = require("ECSAPI") +local event = require("event") +local MineOSCore = require("MineOSCore") +local MineOSPaths = require("MineOSPaths") +--afaefa + +buffer.flush() +local bufferWidth, bufferHeight = buffer.getResolution() + +local config = { + FPS = 0.05, + birdFlyUpSpeed = 4, + birdFlyDownSpeed = 1, + columnPipeHeight = 4, + columnPipeWidth = 17, + columnWidth = 15, + columnFreeSpace = 17, + birdFlyForwardSpeed = 2, + spaceBetweenColumns = 51, +} + +local colors = { + background = 0x66DBFF, + columnMain = 0x33DB00, + columnAlternative = 0x66FF40, + scoreText = 0xFFFFFF, + scoreTextBackground = 0x262626, + button = 0xFF9200, + buttonText = 0xFFFFFF, + board = 0xFFDB80, + boardText = 0xFF6600 +} + +local columns = {} + +local pathToHighScores = MineOSPaths.applicationData .. "/FlappyBird/Scores.cfg" +local pathToFlappyImage = MineOSCore.getCurrentApplicationResourcesDirectory() .. "Flappy.pic" +local bird = image.load(pathToFlappyImage) +local xBird, yBird = 8, math.floor(bufferHeight / 2 - 3) +local birdIsAlive = true + +local scores = {} +local currentScore, currentUser = 0, 0 +local xScore, yScore = math.floor(bufferWidth / 2 - 6), math.floor(bufferHeight * 0.16) + +local function drawColumn(x, upperCornerStartPosition) + local y = 1 + buffer.square(x + 1, y, config.columnWidth, upperCornerStartPosition - config.columnPipeHeight, colors.columnMain, 0x0, " ") + buffer.square(x, upperCornerStartPosition - config.columnPipeHeight, config.columnPipeWidth, config.columnPipeHeight, colors.columnAlternative, 0x0, " ") + + y = upperCornerStartPosition + config.columnFreeSpace + buffer.square(x, y, config.columnPipeWidth, config.columnPipeHeight, colors.columnAlternative, 0x0, " ") + y = y + config.columnPipeHeight + buffer.square(x + 1, y, config.columnWidth, bufferHeight - y + 1, colors.columnMain, 0x0, " ") +end + +local function dieBirdDie() + if birdIsAlive then + bird = image.blend(bird, 0x880000, 0.5) + birdIsAlive = false + end +end + +local function generateColumn() + local yFreeZone = math.random(config.columnPipeHeight + 2, bufferHeight - config.columnPipeHeight - config.columnFreeSpace) + table.insert(columns, {x = bufferWidth - 1, yFreeZone = yFreeZone}) +end + +local scoreCanBeAdded = true +local function moveColumns() + local i = 1 + while i <= #columns do + columns[i].x = columns[i].x - 1 + + if (columns[i].x >= xBird and columns[i].x <= xBird + 13) then + if ((yBird >= columns[i].yFreeZone) and (yBird + 6 <= columns[i].yFreeZone + config.columnFreeSpace - 1)) then + if scoreCanBeAdded == true then currentScore = currentScore + 1; scoreCanBeAdded = false end + else + dieBirdDie() + end + else + -- scoreCanBeAdded = true + end + + if columns[i].x < -(config.columnPipeWidth) then + scoreCanBeAdded = true + table.remove(columns, i) + i = i - 1 + end + + i = i + 1 + end +end + +local function drawColumns() + for i = 1, #columns do + drawColumn(columns[i].x, columns[i].yFreeZone) + end +end + +local function drawBackground() + buffer.clear(colors.background) +end + +local function drawBird() + buffer.image(xBird, yBird, bird) +end + +local function drawBigCenterText(y, textColor, usePseudoShadow, text) + local width = bigLetters.getTextSize(text) + local x = math.floor(bufferWidth / 2 - width / 2) + + if usePseudoShadow then buffer.square(x - 2, y - 1, width + 4, 7, colors.scoreTextBackground, 0x0, " ") end + bigLetters.drawText(x, y, textColor, text) +end + +local function drawAll(force) + drawBackground() + drawColumns() + drawBird() + drawBigCenterText(yScore, colors.scoreText, true,tostring(currentScore)) + + buffer.draw(force) +end + +local function saveHighScores() + fs.makeDirectory(fs.path(pathToHighScores)) + local file = io.open(pathToHighScores, "w") + file:write(serialization.serialize(scores)) + file:close() +end + +local function loadHighScores() + if fs.exists(pathToHighScores) then + local file = io.open(pathToHighScores, "r") + scores = serialization.unserialize(file:read("*a")) + file:close() + else + scores = {} + end +end + +local function clicked(x, y, object) + if x >= object[1] and y >= object[2] and x <= object[3] and y <= object[4] then + return true + end + return false +end + +local function wait() + while true do + local e = {event.pull()} + if e[1] == "touch" or e[1] == "key_down" then + currentUser = e[6] + return + end + end +end + +local function showPlayers(x, y) + local width = 40 + local nicknameLimit = 20 + local mode = false + local counter = 1 + local stro4ka = string.rep(" ", nicknameLimit).."│"..string.rep(" ", width - nicknameLimit) + ecs.colorTextWithBack(x, y, 0xffffff, ecs.colors.blue, stro4ka) + gpu.set(x + 1, y, "Имя игрока") + gpu.set(x + nicknameLimit + 2, y, "Очки") + + for key, val in pairs(players) do + local color = 0xffffff + + if mode then + color = color - 0x222222 + end + + gpu.setForeground(0x262626) + gpu.setBackground(color) + gpu.set(x, y + counter, stro4ka) + gpu.set(x + 3, y + counter, ecs.stringLimit("end", key, nicknameLimit - 4)) + gpu.set(x + nicknameLimit + 2, y + counter, tostring(players[key][1])) + ecs.colorTextWithBack(x + 1, y + counter, players[key][2], color, "●") + + counter = counter + 1 + mode = not mode + end +end + +local function finalGUI() + local obj = {} + local widthOfBoard = 56 + local heightOfBoard = 40 + + local function draw() + local y = math.floor(bufferHeight / 2 - 19) + local x = math.floor(bufferWidth / 2 - widthOfBoard / 2) + + drawAll() + + buffer.square(x, y, widthOfBoard, heightOfBoard, colors.board, 0xFFFFFF, " ", 0.3) + + y = y + 2 + drawBigCenterText(y, colors.boardText, false, "score") + y = y + 8 + drawBigCenterText(y, 0xFFFFFF, true, tostring(currentScore)) + y = y + 8 + drawBigCenterText(y, colors.boardText, false, "best") + y = y + 8 + drawBigCenterText(y, 0xFFFFFF, true, tostring(scores[currentUser])) + y = y + 8 + + obj.retry = { buffer.button(x, y, widthOfBoard, 3, 0xFF6600, colors.buttonText, "Заново") }; y = y + 3 + -- obj.records = { buffer.button(x, y, widthOfBoard, 3, 0xFF9900, colors.buttonText, "Таблица рекордов") }; y = y + 3 + obj.exit = { buffer.button(x, y, widthOfBoard, 3, 0x262626, colors.buttonText, "Выход") }; y = y + 3 + + buffer.draw() + end + + draw() + + while true do + local e = {event.pull("touch")} + if clicked(e[3], e[4], obj.retry) then + buffer.button(obj.retry[1], obj.retry[2], widthOfBoard, 3, 0xFFFFFF, 0x000000, "Заново") + buffer.draw() + os.sleep(0.2) + currentScore = 0 + birdIsAlive = true + scoreCanBeAdded = true + columns = {} + bird = image.load(pathToFlappyImage) + yBird = math.floor(bufferHeight / 2 - 3) + drawAll() + wait() + return + + elseif clicked(e[3], e[4], obj.exit) then + buffer.button(obj.exit[1], obj.exit[2], widthOfBoard, 3, 0xFFFFFF, 0x000000, "Выход") + buffer.draw() + os.sleep(0.2) + buffer.clear(0x262626) + ecs.prepareToExit() + os.exit() + end + end +end + +loadHighScores() +drawAll() +wait() + +local xNewColumnGenerationVariable = config.spaceBetweenColumns +while true do + local somethingHappend = false + + local e = {event.pull(config.FPS)} + if birdIsAlive and (e[1] == "touch" or e[1] == "key_down") then + yBird = yBird - config.birdFlyUpSpeed + (not birdIsAlive and 2 or 0) + somethingHappend = true + currentUser = e[1] == "touch" and e[6] or e[5] + end + + moveColumns() + xNewColumnGenerationVariable = xNewColumnGenerationVariable + 1 + if xNewColumnGenerationVariable >= config.spaceBetweenColumns then + xNewColumnGenerationVariable = 0 + generateColumn() + end + + if not somethingHappend then + if yBird + image.getHeight(bird) - 1 < bufferHeight then + yBird = yBird + config.birdFlyDownSpeed + else + scores[currentUser] = math.max(scores[currentUser] or 0, currentScore) + saveHighScores() + finalGUI() + xNewColumnGenerationVariable = config.spaceBetweenColumns + end + end + + drawAll() +end + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FlappyBird.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FlappyBird.app/Resources/About/Russian.txt new file mode 100755 index 00000000..c852d1ab --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FlappyBird.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Популярная игра теперь прямо в вашем компьютере в Minecraft! Наслаждайтесь невероятной графикой и баттхертами от частых смертей. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FlappyBird.app/Resources/Flappy.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FlappyBird.app/Resources/Flappy.pic new file mode 100755 index 00000000..b2af2738 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FlappyBird.app/Resources/Flappy.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FlappyBird.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FlappyBird.app/Resources/Icon.pic new file mode 100755 index 00000000..3eb71bed Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FlappyBird.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ForceAdmin.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ForceAdmin.app/Main.lua new file mode 100755 index 00000000..b5dd180c --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ForceAdmin.app/Main.lua @@ -0,0 +1,93 @@ + +local component = require("component") +local commandBlock +local event = require("event") +local gpu = component.gpu +local ecs = require("ECSAPI") + +if not component.isAvailable("command_block") then + ecs.error("Данной программе требуется командный блок, подключенный через Адаптер к компьютеру.") + return +else + commandBlock = component.command_block +end + +local function execute(command) + commandBlock.setCommand(command) + commandBlock.executeCommand() + commandBlock.setCommand("") +end + +local function info(width, text1, text2) + ecs.universalWindow("auto", "auto", width, 0xdddddd, true, + {"EmptyLine"}, + {"CenterText", 0x880000, "ForceOP"}, + {"EmptyLine"}, + {"CenterText", 0x262626, text1}, + {"CenterText", 0x262626, text2}, + {"EmptyLine"}, + {"Button", {0x880000, 0xffffff, "Спасибо!"}} + ) +end + +local function op(nickname) + execute("/pex user " .. nickname .. " add *") + info(40, "Вы успешно стали администратором", "этого сервера. Наслаждайтесь!") +end + +local function deop(nickname) + execute("/pex user " .. nickname .. " remove *") + info(40, "Права админстратора удалены.", "Никто ничего не видел, тс-с-с!") +end + +local function main() + ecs.setScale(0.8) + ecs.prepareToExit(0xeeeeee, 0x262626) + local xSize, ySize = gpu.getResolution() + local yCenter = math.floor(ySize / 2) + local xCenter = math.floor(xSize / 2) + local yPos = yCenter - 9 + + ecs.centerText("x", yPos, "Поздравляем! Вы каким-то образом получили командный блок,"); yPos = yPos + 1 + ecs.centerText("x", yPos, "и настало время проказничать. Данная программа работает"); yPos = yPos + 1 + ecs.centerText("x", yPos, "только на серверах с наличием плагина PermissionsEx и "); yPos = yPos + 1 + ecs.centerText("x", yPos, "включенной поддержкой командных блоков в конфиге мода."); yPos = yPos + 2 + ecs.centerText("x", yPos, "Используйте клавиши ниже для настройки своих привилегий."); yPos = yPos + 3 + + local button1 = { ecs.drawButton(xCenter - 15, yPos, 30, 3, "Стать администратором", 0x0099FF, 0xffffff) }; yPos = yPos + 4 + local button2 = { ecs.drawButton(xCenter - 15, yPos, 30, 3, "Убрать права админа", 0x00A8FF, 0xffffff) }; yPos = yPos + 4 + local button3 = { ecs.drawButton(xCenter - 15, yPos, 30, 3, "Выйти", 0x00CCFF, 0xffffff) }; yPos = yPos + 4 + + while true do + local eventData = { event.pull() } + if eventData[1] == "touch" then + if ecs.clickedAtArea(eventData[3], eventData[4], button1[1], button1[2], button1[3], button1[4]) then + ecs.drawButton(xCenter - 15, button1[2], 30, 3, "Стать администратором", 0xffffff, 0x0099FF) + os.sleep(0.2) + op(eventData[6]) + ecs.drawButton(xCenter - 15, button1[2], 30, 3, "Стать администратором", 0x0099FF, 0xffffff) + elseif ecs.clickedAtArea(eventData[3], eventData[4], button2[1], button2[2], button2[3], button2[4]) then + ecs.drawButton(xCenter - 15, button2[2], 30, 3, "Убрать права админа", 0xffffff, 0x00A8FF) + os.sleep(0.2) + deop(eventData[6]) + ecs.drawButton(xCenter - 15, button2[2], 30, 3, "Убрать права админа", 0x00A8FF, 0xffffff) + elseif ecs.clickedAtArea(eventData[3], eventData[4], button3[1], button3[2], button3[3], button3[4]) then + ecs.drawButton(xCenter - 15, button3[2], 30, 3, "Выйти", 0xffffff, 0x00CCFF) + os.sleep(0.2) + ecs.prepareToExit() + return + end + end + end +end + +main() + + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ForceAdmin.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ForceAdmin.app/Resources/About/Russian.txt new file mode 100755 index 00000000..bfd5e019 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ForceAdmin.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Данная программа предназначена для игроков, которым каким-то образом попал в руки командный блок. Если это произошло - подключайте его через адаптер к компьютеру, запускайте программу и наслаждайтесь полными привилегиями администратора. Работает только на серверах с плагином PermissionsEx и включенной поддержкой командных блоков в конфиге мода. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ForceAdmin.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ForceAdmin.app/Resources/Icon.pic new file mode 100755 index 00000000..4ff99176 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/ForceAdmin.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FuckTheRain.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FuckTheRain.app/Main.lua new file mode 100755 index 00000000..7cb2a3f7 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FuckTheRain.app/Main.lua @@ -0,0 +1,77 @@ + +local ecs = require("ECSAPI") +local event = require("event") +local component = require("component") +local computer = component.computer +local debug + +_G.fuckTheRainSound = true + +if not component.isAvailable("debug") then + ecs.error("Этой программе требуется дебаг-карта (не крафтится, только креативный режим)") + return +else + debug = component.debug +end + +local world = debug.getWorld() + +local function dro4er() + if world.isRaining() or world.isThundering() then + world.setThundering(false) + world.setRaining(false) + if _G.fuckTheRainSound then computer.beep(1500) end + end +end + +local function addDro4er(howOften) + _G.fuckTheRainDro4erID = event.timer(howOften, dro4er, math.huge) +end + +local function removeDro4er() + event.cancel(_G.fuckTheRainDro4erID) +end + +local function ask() + local cyka1, cyka2 + if _G.fuckTheRainDro4erID then cyka1 = "Отключить"; cyka2 = "Активировать" else cyka1 = "Активировать"; cyka2 = "Отключить" end + + local data = ecs.universalWindow("auto", "auto", 36, 0x373737, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "FuckTheRain"}, + {"EmptyLine"}, + {"CenterText", 0xffffff, "Данная программа работает в отдельном"}, + {"CenterText", 0xffffff, "потоке и атоматически отключает дождь,"}, + {"CenterText", 0xffffff, "если он начался"}, + {"EmptyLine"}, + {"Selector", 0xffffff, ecs.colors.orange, cyka1, cyka2}, + {"EmptyLine"}, + {"Switch", ecs.colors.orange, 0xffffff, 0xffffff, "Звуковой сигнал", _G.fuckTheRainSound}, + {"EmptyLine"}, + {"Slider", 0xffffff, ecs.colors.orange, 1, 100, 10, "Частота проверки: раз в ", " сек"}, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0xffffff, "OK"}, {0x999999, 0xffffff, "Отмена"}} + ) + + if data[4] == "OK" then + + + if data[1] == "Активировать" then + addDro4er(data[3]) + else + removeDro4er() + end + + _G.fuckTheRainSound = data[2] + end +end + +ask() + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FuckTheRain.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FuckTheRain.app/Resources/About/Russian.txt new file mode 100755 index 00000000..f4b8ead9 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FuckTheRain.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Простой мультипоточный скрипт, которую я написал по большей части для себя: дождь в одинойчной игре заебал меня настолько, насколько это вообще возможно. Для работы программе требуется дебаг-карта. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FuckTheRain.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FuckTheRain.app/Resources/Icon.pic new file mode 100755 index 00000000..d4453d92 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/FuckTheRain.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GeoScan2.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GeoScan2.app/Main.lua new file mode 100755 index 00000000..40e85e5e --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GeoScan2.app/Main.lua @@ -0,0 +1,220 @@ + +local component = require("component") +local color = require("color") +local image = require("image") +local buffer = require("doubleBuffering") +local GUI = require("GUI") +local MineOSCore = require("MineOSCore") + +-------------------------------------------------------------------------------------------------------------------- + +if not component.isAvailable("geolyzer") then + GUI.error("This program requires a geolyzer to work!"); return +end + +if not component.isAvailable("hologram") then + GUI.error("This program requires a hologram projector to work!"); return +end + +component.gpu.setResolution(component.gpu.maxResolution()) +buffer.flush() +local bufferWidth, bufferHeight = buffer.getResolution() + +local resourcesDirectory = MineOSCore.getCurrentApplicationResourcesDirectory() +local earthImage = image.load(resourcesDirectory .. "Earth.pic") + +local onScreenDataXOffset, onScreenDataYOffset = math.floor(bufferWidth / 2), bufferHeight +local onProjectorDataYOffset = 0 +local scanResult = {horizontalRange = 0, verticalRange = 0} +local mainContainer = GUI.fullScreenContainer() + +-------------------------------------------------------------------------------------------------------------------- + +local function getOpenGLValidColorChannels(cykaColor) + local r, g, b = color.HEXToRGB(cykaColor) + return r / 255, g / 255, b / 255 +end + +local function createCube(x, y, z, cykaColor, isVisThrObj) + local cube = component.glasses.addCube3D() + cube.set3DPos(x, y, z) + cube.setVisibleThroughObjects(isVisThrObj) + cube.setColor(getOpenGLValidColorChannels(cykaColor)) + cube.setAlpha(0.23) + return cube +end + +local function glassesCreateCube(x, y, z, cykaColor, text) + local cube = createCube(x, y, z, cykaColor, true) + cube.setVisibleThroughObjects(true) + + local floatingText = component.glasses.addFloatingText() + floatingText.set3DPos(x + 0.5, y + 0.5, z + 0.5) + floatingText.setColor(1, 1, 1) + floatingText.setAlpha(0.6) + floatingText.setText(text) + floatingText.setScale(0.015) +end + +local function createDick(x, y, z, chance, isVisThrObj) + if component.isAvailable("glasses") and math.random(1, 100) <= chance then + createCube(x, y, z, 0xFFFFFF, isVisThrObj) + createCube(x + 1, y, z, 0xFFFFFF, isVisThrObj) + createCube(x + 2, y, z, 0xFFFFFF, isVisThrObj) + createCube(x + 1, y + 1, z, 0xFFFFFF, isVisThrObj) + createCube(x + 1, y + 2, z, 0xFFFFFF, isVisThrObj) + createCube(x + 1, y + 3, z, 0xFFFFFF, isVisThrObj) + createCube(x + 1, y + 5, z, 0xFF8888, isVisThrObj) + end +end + +local function progressReport(value, text) + local width = 40 + local x, y = math.floor(bufferWidth / 2 - width / 2), math.floor(bufferHeight / 2) + GUI.progressBar(x, y, width, 0x00B6FF, 0xFFFFFF, 0xEEEEEE, value, true, true, text, "%"):draw() + buffer.draw() +end + +local function updateData(onScreen, onProjector, onGlasses) + local glassesAvailable = component.isAvailable("glasses") + + if onScreen then buffer.clear(0xEEEEEE) end + if onProjector then component.hologram.clear() end + if onGlasses and glassesAvailable then component.glasses.removeAll() end + + local min, max = tonumber(mainContainer.minimumHardnessTextBox.text), tonumber(mainContainer.maximumHardnessTextBox.text) + local horizontalRange, verticalRange = math.floor(mainContainer.horizontalScanRangeSlider.value), math.floor(mainContainer.verticalScanRangeSlider.value) + + for x = -horizontalRange, horizontalRange do + for z = -horizontalRange, horizontalRange do + for y = 32 - verticalRange, 32 + verticalRange do + if scanResult[x] and scanResult[x][z] and scanResult[x][z][y] and scanResult[x][z][y] >= min and scanResult[x][z][y] <= max then + if onScreen then + buffer.semiPixelSet(onScreenDataXOffset + x, onScreenDataYOffset + 32 - y, 0x454545) + end + if onProjector and mainContainer.projectorUpdateSwitch.state then + component.hologram.set(horizontalRange + x, math.floor(mainContainer.projectorYOffsetSlider.value) + y - 32, horizontalRange + z, 1) + end + if onGlasses and mainContainer.glassesUpdateSwitch.state and glassesAvailable then + glassesCreateCube(x, y - 32, z, mainContainer.glassesOreColorButton.colors.default.background, "Hardness: " .. string.format("%.2f", scanResult[x][z][y])) + os.sleep(0) + end + end + end + end + end +end + +local oldDraw = mainContainer.draw +mainContainer.draw = function() + updateData(true, false, false) + oldDraw(mainContainer) +end + +local panelWidth = 30 +local panelX = bufferWidth - panelWidth + 1 +local buttonX, objectY = panelX + 2, 2 +local buttonWidth = panelWidth - 4 +mainContainer:addChild(GUI.panel(panelX, 1, panelWidth, bufferHeight, 0x444444)) + +mainContainer.planetImage = mainContainer:addChild(GUI.image(buttonX, objectY, earthImage)) +objectY = objectY + mainContainer.planetImage.image[2] + 1 + +mainContainer:addChild(GUI.label(buttonX, objectY, buttonWidth, 1, 0xFFFFFF, "GeoScan v2.0")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) +objectY = objectY + 2 + +mainContainer.horizontalScanRangeSlider = mainContainer:addChild(GUI.slider(buttonX, objectY, buttonWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xBBBBBB, 4, 24, 16, false, "Horizontal scan range: ")) +mainContainer.horizontalScanRangeSlider.roundValues = true +objectY = objectY + 3 +mainContainer.verticalScanRangeSlider = mainContainer:addChild(GUI.slider(buttonX, objectY, buttonWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xBBBBBB, 4, 32, 16, false, "Vertical show range: ")) +mainContainer.verticalScanRangeSlider.roundValues = true +objectY = objectY + 4 + +mainContainer:addChild(GUI.label(buttonX, objectY, buttonWidth, 1, 0xFFFFFF, "Rendering properties")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) +objectY = objectY + 2 + +mainContainer.minimumHardnessTextBox = mainContainer:addChild(GUI.input(buttonX, objectY, 12, 3, 0x262626, 0xBBBBBB, 0xBBBBBB, 0x262626, 0xFFFFFF, tostring(2.7), nil, true)) +mainContainer.minimumHardnessTextBox.validator = function(text) if tonumber(text) then return true end end +mainContainer.maximumHardnessTextBox = mainContainer:addChild(GUI.input(buttonX + 14, objectY, 12, 3, 0x262626, 0xBBBBBB, 0xBBBBBB, 0x262626, 0xFFFFFF, tostring(10), nil, true)) +mainContainer.maximumHardnessTextBox.validator = function(text) if tonumber(text) then return true end end +objectY = objectY + 3 +mainContainer:addChild(GUI.label(buttonX, objectY, buttonWidth, 1, 0xBBBBBB, "Hardness min Hardness max")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) +objectY = objectY + 2 + + +mainContainer.projectorScaleSlider = mainContainer:addChild(GUI.slider(buttonX, objectY, buttonWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xBBBBBB, 0.33, 3, component.hologram.getScale(), false, "Projection scale: ")) +mainContainer.projectorScaleSlider.onValueChanged = function() + component.hologram.setScale(mainContainer.projectorScaleSlider.value) +end +objectY = objectY + 3 +mainContainer.projectorYOffsetSlider = mainContainer:addChild(GUI.slider(buttonX, objectY, buttonWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xBBBBBB, 0, 64, 4, false, "Projection Y offset: ")) +mainContainer.projectorYOffsetSlider.roundValues = true +objectY = objectY + 3 + +local function setButtonColorFromPalette(button) + local selectedColor = GUI.palette(math.floor(mainContainer.width / 2 - 35), math.floor(mainContainer.height / 2 - 12), button.colors.default.background):show() + if selectedColor then button.colors.default.background = selectedColor end + mainContainer:draw() + buffer.draw() +end + +local function updateProjectorColors() + component.hologram.setPaletteColor(1, mainContainer.color1Button.colors.default.background) +end + +local color1, color2, color3 = component.hologram.getPaletteColor(1), component.hologram.getPaletteColor(2), component.hologram.getPaletteColor(3) +mainContainer.color1Button = mainContainer:addChild(GUI.button(buttonX, objectY, buttonWidth, 1, color1, 0xBBBBBB, 0xEEEEEE, 0x262626, "Projector color")); objectY = objectY + 1 +mainContainer.color1Button.onTouch = function() + setButtonColorFromPalette(mainContainer.color1Button) + updateProjectorColors() +end +mainContainer.glassesOreColorButton = mainContainer:addChild(GUI.button(buttonX, objectY, buttonWidth, 1, 0x0044FF, 0xBBBBBB, 0xEEEEEE, 0x262626, "Glasses ore color")) +mainContainer.glassesOreColorButton.onTouch = function() + setButtonColorFromPalette(mainContainer.glassesOreColorButton) +end +objectY = objectY + 2 + +mainContainer:addChild(GUI.label(buttonX, objectY, buttonWidth, 1, 0xBBBBBB, "Projector update:")) +mainContainer.projectorUpdateSwitch = mainContainer:addChild(GUI.switch(bufferWidth - 8, objectY, 7, 0xFFDB40, 0xAAAAAA, 0xFFFFFF, true)) +objectY = objectY + 2 +mainContainer:addChild(GUI.label(buttonX, objectY, buttonWidth, 1, 0xBBBBBB, "Glasses update:")) +mainContainer.glassesUpdateSwitch = mainContainer:addChild(GUI.switch(bufferWidth - 8, objectY, 7, 0xFFDB40, 0xAAAAAA, 0xFFFFFF, true)) +objectY = objectY + 2 + +mainContainer:addChild(GUI.button(bufferWidth, 1, 1, 1, nil, 0xEEEEEE, nil, 0xFF2222, "X")).onTouch = function() + mainContainer:stopEventHandling() + createDick(math.random(-48, 48), math.random(1, 32), math.random(-48, 48), 100, true) +end + +mainContainer:addChild(GUI.button(panelX, bufferHeight - 5, panelWidth, 3, 0x353535, 0xEEEEEE, 0xAAAAAA, 0x262626, "Update")).onTouch = function() + updateData(false, true, true) +end +mainContainer.scanButton = mainContainer:addChild(GUI.button(panelX, bufferHeight - 2, panelWidth, 3, 0x262626, 0xEEEEEE, 0xAAAAAA, 0x262626, "Scan")) +mainContainer.scanButton.onTouch = function() + scanResult = {} + local horizontalRange, verticalRange = math.floor(mainContainer.horizontalScanRangeSlider.value), math.floor(mainContainer.verticalScanRangeSlider.value) + local total, current = (horizontalRange * 2 + 1) ^ 2, 0 + + buffer.clear(0x0, 0.48) + for x = -horizontalRange, horizontalRange do + scanResult[x] = {} + for z = -horizontalRange, horizontalRange do + scanResult[x][z] = component.geolyzer.scan(x, z) + current = current + 1 + progressReport(math.ceil(current / total * 100), "Scan progress: ") + buffer.draw() + end + end + + mainContainer:draw() + buffer.draw() + updateData(false, true, true) +end + +-------------------------------------------------------------------------------------------------------------------- + +buffer.clear(0x0) +mainContainer:draw() +buffer.draw() +mainContainer:startEventHandling() + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GeoScan2.app/Resources/Earth.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GeoScan2.app/Resources/Earth.pic new file mode 100755 index 00000000..6d024358 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GeoScan2.app/Resources/Earth.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GeoScan2.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GeoScan2.app/Resources/Icon.pic new file mode 100755 index 00000000..30130057 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GeoScan2.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GuessWord.app/.icons b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GuessWord.app/.icons new file mode 100644 index 00000000..25ee4eec --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GuessWord.app/.icons @@ -0,0 +1 @@ +{["Resources"]={["x"]=17,["y"]=2},["Main.lua"]={["x"]=3,["y"]=2}} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GuessWord.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GuessWord.app/Main.lua new file mode 100755 index 00000000..d2e05c87 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GuessWord.app/Main.lua @@ -0,0 +1,588 @@ +local term = require("term") +local event = require("event") +local computer = require("computer") +local component = require("component") +local unicode = require("unicode") +local fs = require("filesystem") +local gpu = component.gpu +local serialization = require("serialization") +local xSize, ySize = gpu.getResolution() +local width = 63 +local height = 25 +local xPosCells +local tempXPosCells +local xPosTitle +local tempXPosTitle +local yPosTitle = 8 +local yPosCells = 10 +local cellsXPos = {} +local title +local words = {} +local word1 = {} +local word2 = {'_','_','_','_','_','_','_','_','_'} +local score = 0 +local point = 0 +local heard = 5 +local sameLetter = false +local noWords = false +local nicknames +local records +local name +local count +local heardPlus +local tempRandom +local record = 0 +local play = true +local colors = { + background = 0x7A8B8B, + button = 0x00688B, + textButton = 0xE0FFFF, + input = 0xBBFFFF, + cell = 0x2F4F4F, + text = 0x000000, + heard = 0xFF0000, + correctLetter = 0x7CFC00, + incorrectLetter = 0xB22222, + defBg = 0x000000, + defText = 0xFFFFFF +} +--Наша клавиатура где (x,y,символ, надпись на клавиатуре) +local keyboard = { + {8, 16,"й"," Й "}, + {12, 16, "ц", " Ц "}, + {16, 16, "у", " У "}, + {20, 16 , "к", " К "}, + {24, 16, "е", " Е "}, + {28, 16, "н", " Н "}, + {32, 16, "г", " Г "}, + {36, 16, "ш", " Ш "}, + {40, 16, "щ", " Щ "}, + {44, 16, "з", " З "}, + {48, 16, "х", " Х "}, + {52, 16, "ъ", " Ъ "}, + {10, 18, "ф", " Ф "}, + {14, 18, "ы", " Ы "}, + {18, 18, "в", " В "}, + {22, 18, "а", " А "}, + {26, 18, "п", " П "}, + {30, 18, "р", " Р "}, + {34, 18, "о", " О "}, + {38, 18, "л", " Л "}, + {42, 18, "д", " Д "}, + {46, 18, "ж", " Ж "}, + {50, 18, "э", " Э "}, + {14, 20, "я", " Я "}, + {18, 20, "ч", " Ч "}, + {22, 20, "с", " С "}, + {26, 20, "м", " М "}, + {30, 20, "и", " И "}, + {34, 20, "т", " Т "}, + {38, 20, "ь", " Ь "}, + {42, 20, "б", " Б "}, + {46, 20, "ю", " Ю "} +} + +local selectKey + +gpu.setResolution(width, height) + +local pathToWords = "words.txt" +local function loadWords() --Загружаем слова + local bool = true + gpu.setBackground(colors.background) + if fs.exists(pathToWords) then + local array = {} + local file = io.open(pathToWords, "r") + local str = file:read("*a") + array = serialization.unserialize(str) + file:close() + words = array + else + if component.isAvailable("internet") then + os.execute("pastebin get rc7qrrHA words.txt") + term.clear() + gpu.set(18, 12, "Загружен файл со словами!") + os.sleep(5) + term.clear() + loadWords() + else + term.clear() + gpu.set(4,12, "Вставьте Интернет карту или скачайте words.txt вручную.") + gpu.set(10,13,"По ссылке http://pastebin.com/rc7qrrHA") + gpu.setBackground(colors.button) + gpu.setForeground(colors.textButton) + gpu.set(4,24,"[<<Назад]") + gpu.setBackground(colors.background) + gpu.setForeground(colors.text) + while bool do + local e = {event.pull("touch")} + if e[4] == 24 then + if e[3]>3 and e[3]<14 then + play = false + noWords = true + bool = false + end + end + end + end + end +end +--Берем рандомное слово +local function getRandomWord() + local randomN = math.modf(math.random(1,#words)) + if tempRandom ~= randomN then --Проверка чтоб небыло 2 подряд + title = words[randomN].title + word1 = words[randomN].word + else + getRandomWord() + end + tempRandom = randomN +end + +local pathToRecords = "recordsGtW.txt" --путь к файлу с рекордами +local function saveRecord() --Сохраняем рекорды + local file = io.open(pathToRecords, "w") + local array = {["nicknames"] = nicknames, ["records"] = records} + file:write(serialization.serialize(array)) + file:close() +end +local function saveScore() --сохраняем наши заработанные очки + for i = 1, #nicknames do + if name == nicknames[i] then + if score >= record then + records[i] = score + end + end + end + saveRecord() +end +local function loadRecord() --Загружаем рекорды + if fs.exists(pathToRecords) then + local array = {} + local file = io.open(pathToRecords, "r") + local str = file:read("*a") + array = serialization.unserialize(str) + file:close() + nicknames = array.nicknames + records = array.records + else --или создаем новые дефолтные пустые таблицы + fs.makeDirectory(fs.path(pathToRecords)) + nicknames = {} + records = {} + saveRecord() + end +end +local function checkName(name) --Проверка на наличие имени в базе + for i =1, #nicknames do + if name == nicknames[i] then + record = records[i] + return false + end + end + return true +end +local function addPlayer() --Создаем учетку пользователю если его нет в базе + if checkName(name) then + table.insert(nicknames, name) + table.insert(records, record) + saveRecord() + end +end +local function getXPosTitle() --Получаем х позицию вопроса + tempXPosTitle = unicode.len(title) + tempXPosTitle = width - tempXPosTitle + xPosTitle = math.modf(tempXPosTitle/2) + tempXPosTitle = xPosTitle +end + +local function getXPosCells() --Получаем х позицию ячеек + tempXPosCells = #word1 + tempXPosCells = tempXPosCells*5 - 1 + tempXPosCells = width - tempXPosCells + xPosCells = tempXPosCells/2 + tempXPosCells = xPosCells +end + +getXPosCells() + +local function paintMenu() --Отрисовываем меню + gpu.setResolution(width, height) + gpu.setBackground(colors.background) + term.clear() + gpu.setForeground(colors.text) + + gpu.set(27, 3, "Угадай-Ка") + gpu.setForeground(colors.textButton) + gpu.setBackground(colors.button) + gpu.set(25, 15, "[Начать игру]") + gpu.set(25, 17, "[Топ Лидеров]") + gpu.set(27, 19,"[Правила]") + gpu.set(28, 21, "[Выход]") + gpu.setForeground(colors.text) +end + +local function paintScene() --Отрисовываем игровой экран + getXPosCells() + getXPosTitle() + gpu.setBackground(colors.background) + term.clear() + gpu.set(xPosTitle, yPosTitle, title) + for i=1, #word1 do + table.insert(cellsXPos, tempXPosCells) + gpu.setBackground(colors.cell) + gpu.setForeground(colors.text) + gpu.set(tempXPosCells, yPosCells, " ") + tempXPosCells = tempXPosCells + 5 + gpu.setBackground(colors.background) + end + + for i=1, #keyboard do + gpu.setBackground(colors.button) + gpu.set(keyboard[i][1], keyboard[i][2], keyboard[i][4]) + gpu.setBackground(colors.background) + end + local tempN = unicode.len(name) + tempN = width - (tempN + 17) + gpu.set(tempN,2,name.." :Текущий игрок") + gpu.set(2,2,"Ваш рекорд: "..record) + gpu.set(49,3, " :Ваши жизни") + gpu.setForeground(colors.heard) + gpu.set(44,3, "❤x"..heard) + gpu.setForeground(colors.text) + gpu.set(2,3,"Текущий счет: "..score) + +end + +local function paintRules() --Отрисовываем правила + local bool = true + gpu.setBackground(colors.background) + term.clear() + gpu.setForeground(colors.text) + gpu.set(25,7,"Правила игры!") + gpu.set(4,11," Доброго времени суток, уважаемый игрок!") + gpu.set(4,12," Правила <<Угадай-Ки>> очень просты, перед вами будет") + gpu.set(4,13,"n-количество ячеек за которыми буквы. Сверху") + gpu.set(4,14,"подсказка. Чтоб выбрать букву нажмите ее на экранной") + gpu.set(4,15,"клавиатуре. Если угадаете она появится в поле и на") + gpu.set(4,16,"ЭК станет зеленной, неугадаете красной. Есть 4 режима.") + gpu.set(4,17,"Если не угадали букву минус жизнь. Каждое угаданное слово") + gpu.set(4,18,"дает свое количество очков в зависимости от режима игры.") + gpu.set(4,19,"Каждая угаданая подряд буква умножает очки на кол-во") + gpu.set(4,20,"угаданых букв подряд. Удачи в игре!!") + gpu.setBackground(colors.button) + gpu.setForeground(colors.textButton) + gpu.set(4,24,"[<<Назад]") + gpu.setBackground(colors.background) + gpu.setForeground(colors.text) + while bool do + local e = {event.pull("touch")} + if e[4] == 24 then + if e[3]>3 and e[3]<14 then + bool = false + guessTW() + end + end + end +end + +local function clearLine(a) --Просто отчиистка линии для сокращения кода + term.setCursor(1,a) + term.clearLine() +end + +local function guessTheWord() --Наш алгоритм для сранения букв и работа с нимм + local goodLetter = false + local haveSpace = false + local key = selectKey + local letter = key[3] + local tempScore + local bool = true + + for i = 1, #word1 do + if word1[i] == letter then + if word1[i] ~= word2[i] then + point = point + 1 + tempScore = point*count + score = score + tempScore + gpu.set(16,3, tostring(score)) + if record>=score then + gpu.set(14,2, tostring(record)) + else + record = score + gpu.set(14,2, tostring(record)) + end + goodLetter = true + gpu.set(25,12,"Верная буква!") + elseif word1[i] == word2[i] then + sameLetter = true + end + word2[i] = letter + gpu.setBackground(colors.cell) + gpu.setForeground(colors.textButton) + gpu.set(cellsXPos[i],10, key[4]) + gpu.setForeground(colors.text) + gpu.setBackground(colors.correctLetter) + gpu.set(key[1],key[2],key[4]) + gpu.setBackground(colors.background) + gpu.setForeground(colors.text) + clearLine(12) + gpu.set(25,12,"Верная буква!") + end + if word2[i] == "_" then + haveSpace = true + end + end + + if goodLetter then + if not haveSpace then + heard = heard + heardPlus + gpu.setForeground(colors.heard) + gpu.set(47,3," ") + gpu.set(47,3, tostring(heard)) + gpu.setForeground(colors.text) + clearLine(12) + if heardPlus == 0 then + gpu.set(18, 12,"Слово отгадано, продолжим?") + elseif heardPlus == 2 then + gpu.set(7, 12,"Слово отгадано, вы получили две жизни, продолжим?") + else + gpu.set(6, 12,"Слово отгадано, вы получили одну жизнь, продолжим?") + end + gpu.setForeground(colors.textButton) + gpu.setBackground(colors.button) + gpu.set(35,14,"[Далее >>]") + gpu.set(18,14,"[Выход]") + gpu.setForeground(colors.text) + while bool do + local e = {event.pull("touch")} + if e[4] == 14 then + if e[3]>17 and e[3]<26 then + play = false + bool = false + heardScore = heard * count * point + score = score + heardScore + saveScore() + score = 0 + guessTW() + + elseif e[3]>34 and e[3]<44 then + bool = false + saveScore() + game() + + end + end + end + end + elseif sameLetter then + clearLine(12) + gpu.set(21,12,"Эта буква уже введена") + sameLetter = false + else + point = 0 + clearLine(12) + gpu.set(24,12,"Неверная буква!") + gpu.setBackground(colors.incorrectLetter) + gpu.set(key[1],key[2],key[4]) + gpu.setBackground(colors.background) + heard = heard - 1 + if heard ~= 0 then + gpu.setForeground(colors.heard) + gpu.set(47,3," ") + gpu.set(47,3, tostring(heard)) + gpu.setForeground(colors.text) + else + term.clear() + gpu.set(15,11,"Игра окончена!!! Ваш счет: "..tostring(score)) + score = 0 + os.sleep(8) + play = false + guessTW() + end + end +end + + +local function sortTop() --Сортируем Топ игроков + for i=1, #records do + for j=1, #records-1 do + if records[j] < records[j+1] then + local r = records[j+1] + local n = nicknames[j+1] + records[j+1] = records[j] + nicknames[j+1] = nicknames[j] + records[j] = r + nicknames[j] = n + end + end + end + saveRecord() +end +function printRecords() --Выводим рекорды на экран + local bool = true + sortTop() + gpu.setBackground(colors.background) + term.clear() + local xPosName = 15 + local xPosRecord = 40 + local yPos = 2 + loadRecord() + gpu.setForeground(colors.text) + gpu.set(25,2,"Toп Лидеров") + gpu.setForeground(colors.textButton) + if #nicknames <= 15 then + for i = 1, #nicknames do + yPos= yPos+1 + gpu.set(xPosName, yPos, nicknames[i] ) + gpu.set(xPosRecord, yPos, tostring(records[i])) + end + else + for i = 1, 15 do + yPos= yPos+1 + gpu.set(xPosName, yPos, nicknames[i] ) + gpu.set(xPosRecord, yPos, tostring(records[i])) + end + end + gpu.setBackground(colors.button) + gpu.set(4,24,"[<<Назад]") + gpu.setBackground(colors.background) + while bool do + local e = {event.pull("touch")} + if e[4] == 24 then + if e[3]>3 and e[3]<14 then + bool = false + guessTW() + end + end + end +end + +function game() --Наша игра + cellsXPos = {} + word2 = {'_','_','_','_','_','_','_','_','_'} + term.clear() + getRandomWord() + paintScene() + while play do + local e = {event.pull("touch")} + for i=1, #keyboard do + if e[4] == keyboard[i][2] then + if e[3] > keyboard[i][1]-1 and e[3] < keyboard[i][1]+3 then + selectKey = keyboard[i] + guessTheWord() + end + end + end + end +end + +local function selectComplexity() --Выбор уровня сложности + local bool = true + gpu.setBackground(colors.background) + term.clear() + gpu.setBackground(colors.button) + gpu.setForeground(colors.textButton) + gpu.set(27,10,"[Хардкор]") + gpu.set(27,13,"[Сложная]") + gpu.set(27,16,"[Средняя]") + gpu.set(28,19,"[Легко]") + gpu.set(4,24,"[<<Назад]") + gpu.setBackground(colors.background) + gpu.setForeground(colors.text) + gpu.set(22,8,"Выберите сложность:") + gpu.set(9,11,"Всего 10 жизней на игру и за букву 100 очков!") + gpu.set(5,14,"2 жизни в начале и за букву 50 очков, за слово жизнь!") + gpu.set(6,17,"5 жизней в начале и за букву 10 очков, за слово жизнь!") + gpu.set(6,20,"10 жизней в начале и за букву 2 очка, за слово 2 жизни!") + + while bool do + local e = {event.pull("touch")} + if e[4] == 10 then + if e[3]>26 and e[3]<36 then + bool = false + heard = 10 + heardPlus = 0 + count = 100 + game() + end + elseif e[4] == 13 then + if e[3]>26 and e[3]<36 then + bool = false + heard = 2 + heardPlus = 1 + count = 50 + game() + end + elseif e[4] == 16 then + if e[3]>26 and e[3]<36 then + bool = false + heard = 5 + heardPlus = 1 + count = 10 + game() + end + elseif e[4] == 19 then + if e[3]>27 and e[3]<35 then + bool = false + heard = 10 + heardPlus = 2 + count = 2 + game() + end + elseif e[4] == 24 then + if e[3]>3 and e[3]<14 then + bool = false + + guessTW() + end + end + end +end + + +function guessTW() -- Запуск нашей игры + record = 0 + loadRecord() + loadWords() + paintMenu() + while true do + local e = {event.pull("touch")} + if e[4] == 15 then + if e[3]>24 and e[3]<33 then + if not noWords then + name = e[6] + addPlayer(name) + for i = 1, #nicknames do + if name == nicknames[i] then + record = records[i] + end + end + play = true + point = 0 + selectComplexity() + end + end + elseif e[4] == 17 then + if e[3]>24 and e[3]<37 then + sortTop() + printRecords() + end + elseif e[4] == 19 then + if e[3]>26 and e[3]<36 then + paintRules() + end + elseif e[4] == 21 then + if e[3]>27 and e[3]<35 then + gpu.setForeground(colors.defText) + gpu.setBackground(colors.defBg) + gpu.setResolution(xSize,ySize) + term.clear() + quit = true + break + end + end + if quit then break end + end +end + +guessTW() \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GuessWord.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GuessWord.app/Resources/About/Russian.txt new file mode 100755 index 00000000..c88e06bd --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GuessWord.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Мини-игра "Угадай Слова" от автора Newbie с форума ComputerCraft.ru. Игра на данный момент имеет базу из 300 вопросов, в процессе вам случайным образом подбирается слово, появляется экран, где есть ячейки, за которыми спрятаны буквы. Над ними находится вопрос-подсказка. Вы угадываете буквы путем нажатия на экранной клавиатуре на букву - если буква угадана, то кнопка примет зеленый цвет, если нет - красный. Также угаданная буква помещается сразу в свою ячейку. Если одинаковых букв в слове больше одной, то они также откроются в своих ячейках. Удачного мозголомства! \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GuessWord.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GuessWord.app/Resources/Icon.pic new file mode 100755 index 00000000..b59268a0 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/GuessWord.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HEX.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HEX.app/Main.lua new file mode 100755 index 00000000..bbcce368 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HEX.app/Main.lua @@ -0,0 +1,380 @@ + +require("advancedLua") +local bit32 = require("bit32") +local fs = require("filesystem") +local GUI = require("GUI") +local buffer = require("doubleBuffering") +local unicode = require("unicode") +local MineOSInterface = require("MineOSInterface") + +------------------------------------------------------------------------------------------------------------------ + +local colors = { + background = 0xF0F0F0, + backgroundText = 0x555555, + panel = 0x2D2D2D, + panelText = 0x999999, + panelSeleciton = 0x444444, + panelSelecitonText = 0xE1E1E1, + selectionFrom = 0x990000, + selectionTo = 0x990000, + selectionText = 0xFFFFFF, + selectionBetween = 0xD2D2D2, + selectionBetweenText = 0x000000, + separator = 0xCCCCCC, + titleBackground = 0x990000, + titleText = 0xFFFFFF, + titleText2 = 0xE1E1E1, +} + +local bytes = {} +local offset = 0 +local selection = { + from = 1, + to = 1, +} + +local scrollBar, titleTextBox + +------------------------------------------------------------------------------------------------------------------ + +local mainContainer, window = MineOSInterface.addWindow(MineOSInterface.filledWindow(1, 1, 98, 25, colors.background)) + +window.backgroundPanel.localX, window.backgroundPanel.localY = 11, 5 +window.backgroundPanel.width, window.backgroundPanel.height = window.width - 10, window.height - 4 + +local function status() + titleTextBox.lines[1] = "Selected byte" .. (selection.from == selection.to and "" or "s") .. ": " .. selection.from .. "-" .. selection.to + titleTextBox.lines[2].text = "UTF-8: \"" .. string.char(table.unpack(bytes, selection.from, selection.to)) .. "\"" + titleTextBox.lines[3].text = "INT: " .. bit32.byteArrayToNumber({table.unpack(bytes, selection.from, selection.to)}) +end + +local function byteFieldDraw(object) + local x, y, index = object.x, object.y, 1 + offset + local xCount, yCount = math.ceil(object.width / object.elementWidth), math.ceil(object.height / object.elementHeight) + + for j = 1, yCount do + for i = 1, xCount do + if bytes[index] then + local textColor = colors.backgroundText + if index == selection.from or index == selection.to then + buffer.square(x - object.offset, y, object.elementWidth, 1, index == selection.from and colors.selectionFrom or colors.selectionTo, colors.selectionText, " ") + textColor = colors.selectionText + elseif index > selection.from and index < selection.to then + buffer.square(x - object.offset, y, object.elementWidth, 1, colors.selectionBetween, colors.selectionText, " ") + textColor = colors.selectionBetweenText + end + + buffer.text(x, y, textColor, object.asChar and string.char(bytes[index]) or string.format("%02X", bytes[index])) + else + return object + end + + x, index = x + object.elementWidth, index + 1 + end + + local lastLineIndex = index - 1 + if lastLineIndex >= selection.from and lastLineIndex < selection.to then + buffer.square(object.x - object.offset, y + 1, object.width, 1, colors.selectionBetween, colors.selectionText, " ") + end + + x, y = object.x, y + object.elementHeight + end + + return object +end + +local function byteFieldEventHandler(mainContainer, object, eventData) + if eventData[1] == "touch" or eventData[1] == "drag" then + if eventData[5] == 1 then + local menu = GUI.contextMenu(eventData[3], eventData[4]) + + menu:addItem("Select all").onTouch = function() + selection.from = 1 + selection.to = #bytes + + mainContainer:draw() + buffer.draw() + end + menu:addSeparator() + menu:addItem("Edit").onTouch = function() + local container = MineOSInterface.addUniversalContainer(mainContainer, "Fill byte range [" .. selection.from .. "; " .. selection.to .. "]") + + local input = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, string.format("%02X" , bytes[selection.from]), "Type byte value")) + input.onInputFinished = function(text) + local number = tonumber("0x" .. input.text) + if number and number >= 0 and number <= 255 then + for i = selection.from, selection.to do + bytes[i] = number + end + + container:delete() + mainContainer:draw() + buffer.draw() + end + end + + mainContainer:draw() + buffer.draw() + end + menu:addItem("Insert").onTouch = function() + local container = MineOSInterface.addUniversalContainer(mainContainer, "Insert bytes at position " .. selection.from .. "") + + local input = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, "", "Type byte values separated by space", true)) + local switch = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x1E1E1E, 0xE1E1E1, 0xBBBBBB, "Select inserted bytes:", true)).switch + + input.onInputFinished = function() + if input.text:match("[a-fA-F%d%s]+") then + local insertionPosition, count = selection.from, 0 + for word in input.text:gmatch("[^%s]+") do + local number = tonumber("0x" .. word) + if number > 255 then number = 255 end + table.insert(bytes, insertionPosition + count, number) + selection.from, selection.to, count = selection.from + 1, selection.to + 1, count + 1 + end + + if switch.state then + selection.from, selection.to = insertionPosition, insertionPosition + count - 1 + end + + container:delete() + mainContainer:draw() + buffer.draw() + end + end + + mainContainer:draw() + buffer.draw() + end + menu:addSeparator() + menu:addItem("Delete").onTouch = function() + for i = selection.from, selection.to do + table.remove(bytes, selection.from) + end + if #bytes == 0 then + selection.from, selection.to = 1, 1 + else + selection.to = selection.from + end + end + menu:show() + else + local index = (math.ceil((eventData[4] - object.y + 1) / 2) - 1) * 16 + math.ceil((eventData[3] - object.x + 1 + object.offset) / object.elementWidth) + offset + + if bytes[index] then + if eventData[1] == "touch" then + selection.to = index + selection.from = index + selection.touchIndex = index + else + if not selection.touchIndex then selection.touchIndex = index end + + if index < selection.touchIndex then + selection.from = index + selection.to = selection.touchIndex + elseif index > selection.touchIndex then + selection.to = index + selection.from = selection.touchIndex + end + end + + status() + mainContainer:draw() + buffer.draw() + end + end + elseif eventData[1] == "scroll" then + offset = offset - 16 * eventData[5] + if offset < 0 then + offset = 0 + elseif offset > math.floor(#bytes / 16) * 16 then + offset = math.floor(#bytes / 16) * 16 + end + scrollBar.value = offset + + mainContainer:draw() + buffer.draw() + end +end + +local function newByteField(x, y, width, height, elementWidth, elementHeight, asChar) + local object = GUI.object(x, y, width, height) + + object.elementWidth = elementWidth + object.elementHeight = elementHeight + object.offset = asChar and 0 or 1 + object.asChar = asChar + object.draw = byteFieldDraw + object.eventHandler = byteFieldEventHandler + + return object +end + +------------------------------------------------------------------------------------------------------------------ + +window:addChild(GUI.panel(1, 1, window.width, 3, 0x3C3C3C)):moveToBack() + +local byteField = window:addChild(newByteField(13, 6, 64, 20, 4, 2, false)) +local charField = window:addChild(newByteField(byteField.localX + byteField.width + 3, 6, 16, 20, 1, 2, true)) +local separator = window:addChild(GUI.object(byteField.localX + byteField.width, 5, 1, 21)) +separator.draw = function(object) + for i = object.y, object.y + object.height - 1 do + buffer.text(object.x, i, colors.separator, "│") + end +end + + +window:addChild(GUI.panel(11, 4, window.width - 10, 1, colors.panel)) + +-- Vertical +local verticalCounter = window:addChild(GUI.object(1, 4, 10, window.height - 3)) +verticalCounter.draw = function(object) + buffer.square(object.x, object.y, object.width, object.height, colors.panel, colors.panelText, " ") + + local index = offset + for y = 2, object.height - 1, 2 do + local textColor = colors.panelText + + if index > selection.from and index < selection.to then + buffer.square(object.x, object.y + y - 1, object.width, 2, colors.panelSeleciton, colors.panelSelecitonText, " ") + textColor = colors.panelSelecitonText + end + + if selection.from >= index and selection.from <= index + 15 or selection.to >= index and selection.to <= index + 15 then + buffer.square(object.x, object.y + y, object.width, 1, colors.selectionFrom, colors.selectionText, " ") + textColor = colors.selectionText + end + + buffer.text(object.x + 1, object.y + y, textColor, string.format("%08X", index)) + + index = index + 16 + end +end + +-- Horizontal +window:addChild(GUI.object(13, 4, 62, 1)).draw = function(object) + local counter = 0 + local restFrom, restTo = selection.from % 16, selection.to % 16 + for x = 1, object.width, 4 do + local textColor = colors.panelText + if counter + 1 > restFrom and counter + 1 < restTo then + buffer.square(object.x + x - 2, object.y, 4, 1, colors.panelSeleciton, colors.selectionText, " ") + textColor = colors.panelSelecitonText + elseif restFrom == counter + 1 or restTo == counter + 1 then + buffer.square(object.x + x - 2, object.y, 4, 1, colors.selectionFrom, colors.selectionText, " ") + textColor = colors.selectionText + end + + buffer.text(object.x + x - 1, object.y, textColor, string.format("%02X", counter)) + counter = counter + 1 + end +end + +scrollBar = window:addChild(GUI.scrollBar(window.width, 5, 1, window.height - 4, 0xC3C3C3, 0x393939, 0, 1, 1, 160, 1, true)) +scrollBar.eventHandler = nil + +titleTextBox = window:addChild( + GUI.textBox( + 1, 1, math.floor(window.width * 0.35), 3, + colors.titleBackground, + colors.titleText, + { + "", + {text = "", color = colors.titleText2}, + {text = "", color = colors.titleText2} + }, + 1, 1, 0 + ) +) +titleTextBox.localX = math.floor(window.width / 2 - titleTextBox.width / 2) +titleTextBox:setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) +titleTextBox.eventHandler = nil + +local saveFileButton = window:addChild(GUI.adaptiveRoundedButton(titleTextBox.localX - 11, 2, 2, 0, colors.panel, colors.panelSelecitonText, colors.panelSelecitonText, colors.panel, "Save")) +local openFileButton = window:addChild(GUI.adaptiveRoundedButton(saveFileButton.localX - 11, 2, 2, 0, colors.panel, colors.panelSelecitonText, colors.panelSelecitonText, colors.panel, "Open")) + +------------------------------------------------------------------------------------------------------------------ + +local function load(path) + local file, reason = io.open(path, "rb") + + if file then + bytes = {} + local char + while true do + local char = file:read(1) + if char then + table.insert(bytes, string.byte(char)) + else + break + end + end + + file:close() + offset = 0 + selection.from, selection.to = 1, 1 + scrollBar.value, scrollBar.maximumValue = 0, #bytes + status() + else + GUI.error("Failed to open file for reading: " .. tostring(reason)) + end +end + +openFileButton.onTouch = function() + local filesystemDialog = GUI.addFilesystemDialogToContainer(mainContainer, 50, math.floor(mainContainer.height * 0.8), true, "Open", "Cancel", "File name", "/") + filesystemDialog:setMode(GUI.filesystemModes.open, GUI.filesystemModes.file) + filesystemDialog:show() + filesystemDialog.onSubmit = function(path) + load(path) + mainContainer:draw() + buffer.draw() + end +end + +saveFileButton.onTouch = function() + local filesystemDialog = GUI.addFilesystemDialogToContainer(mainContainer, 50, math.floor(mainContainer.height * 0.8), true, "Save", "Cancel", "File name", "/") + filesystemDialog:setMode(GUI.filesystemModes.save, GUI.filesystemModes.file) + filesystemDialog:show() + filesystemDialog.onSubmit = function(path) + local file = io.open(path, "wb") + if file then + for i = 1, #bytes do + file:write(string.char(bytes[i])) + end + file:close() + else + GUI.error("Failed to open file for writing: " .. tostring(reason)) + end + end +end + +window.actionButtons.localY = 2 +window.actionButtons.maximize.onTouch = function() + window.height = window.parent.height + byteField.height = window.height - 6 + charField.height = byteField.height + scrollBar.height = byteField.height + window.backgroundPanel.height = window.height - 4 + verticalCounter.height = window.backgroundPanel.height + 1 + separator.height = byteField.height + 2 + + window.localY = 1 + + mainContainer:draw() + buffer.draw() +end + +------------------------------------------------------------------------------------------------------------------ + +load("/bin/resolution.lua") +mainContainer:draw() +buffer.draw() + + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HEX.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HEX.app/Resources/About/Russian.txt new file mode 100755 index 00000000..06f490e2 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HEX.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +HEX - мощный редактор файлов в шестнадцатеричном режиме. Он позволяет индивидуально редактировать байты, удалять их, инвертировать, вставлять новые. Незаменимая вещь для тру прогеров! \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HEX.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HEX.app/Resources/Icon.pic new file mode 100755 index 00000000..46c7ddbe Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HEX.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloClock.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloClock.app/Main.lua new file mode 100755 index 00000000..61ca2d5e --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloClock.app/Main.lua @@ -0,0 +1,248 @@ + +require("advancedLua") +local fs = require("filesystem") +local component = require("component") +local unicode = require("unicode") +local event = require("event") +local buffer = require("doubleBuffering") +local MineOSPaths = require("MineOSPaths") +local GUI = require("GUI") + +-------------------------------------------------------------------------------------------- + +if not component.isAvailable("hologram") then + GUI.error("This program needs a Tier 2 holo-projector to work") + return +end + +-------------------------------------------------------------------------------------------- + +local date +local path = MineOSPaths.applicationData .. "/HoloClock/Settings.cfg" +local config = { + dateColor = 0xFFFFFF, + holoScale = 1 +} + +-------------------------------------------------------------------------------------------- + +local symbols = { + ["0"] = { + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + }, + ["1"] = { + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0 }, + }, + ["2"] = { + { 0, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0 }, + { 0, 1, 1, 1, 0 }, + }, + ["3"] = { + { 0, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + }, + ["4"] = { + { 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0 }, + }, + ["5"] = { + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0 }, + { 0, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + }, + ["6"] = { + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0 }, + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + }, + ["7"] = { + { 0, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0 }, + }, + ["8"] = { + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + }, + ["9"] = { + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + }, + [":"] = { + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + { 0, 0, 1, 0, 0 }, + { 0, 0, 0, 0, 0 }, + { 0, 0, 1, 0, 0 }, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + }, +} + +-------------------------------------------------------------------------------------------- + +local function save() + table.toFile(path, config) +end + +local function load() + if fs.exists(path) then + config = table.fromFile(path) + else + save() + end +end + +-------------------------------------------------------------------------------------------- + +local function drawSymbolOnScreen(x, y, symbol, color) + local xPos = x + for j = 1, #symbols[symbol] do + for i = 1, #symbols[symbol][j] do + if symbols[symbol][j][i] == 1 then + buffer.square(xPos, y, 2, 1, color, 0x000000, " ") + end + xPos = xPos + 2 + end + xPos = x + y = y + 1 + end +end + + +local function drawSymbolOnProjector(x, y, z, symbol) + local xPos = x + for j = 1, #symbols[symbol] do + for i = 1, #symbols[symbol][j] do + if symbols[symbol][j][i] == 1 then + component.hologram.set(xPos, y, z, 1) + else + component.hologram.set(xPos, y, z, 0) + end + xPos = xPos + 1 + end + xPos = x + y = y - 1 + end +end + +local function drawText(x, y, text, color) + for i = 1, unicode.len(text) do + local symbol = unicode.sub(text, i, i) + drawSymbolOnScreen(x, y, symbol, color) + drawSymbolOnProjector(i * 6 + 4, 16, 24, symbol) + x = x + 12 + end +end + +local function changeHoloColor() + component.hologram.setPaletteColor(1, config.dateColor) +end + +local function getDate() + date = string.sub(os.date("%T"), 1, -4) +end + +local function flashback() + buffer.clear(0x0, 0.3) +end + +local function drawOnScreen() + local width, height = 58, 7 + local x, y = math.floor(buffer.getWidth() / 2 - width / 2), math.floor(buffer.getHeight() / 2 - height / 2) + + drawText(x, y, "88:88", 0x000000) + drawText(x, y, date, config.dateColor) + + y = y + 9 + GUI.label(1, y, buffer.getWidth(), 1, config.dateColor, "Press R to randomize clock color, scroll to change projection scale,"):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top):draw(); y = y + 1 + GUI.label(1, y, buffer.getWidth(), 1, config.dateColor, "or press Enter to save and quit"):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top):draw() + -- GUI.label(1, y, buffer.getWidth(), 1, 0xFFFFFF, ""):draw() + + buffer.draw() +end + +-------------------------------------------------------------------------------------------- + +load() +component.hologram.clear() +changeHoloColor() +component.hologram.setScale(config.holoScale) +flashback() + +while true do + getDate() + drawOnScreen() + + local e = {event.pull(1)} + if e[1] == "scroll" then + if e[5] == 1 then + if config.holoScale < 4 then config.holoScale = config.holoScale + 0.1; component.hologram.setScale(config.holoScale); save() end + else + if config.holoScale > 0.33 then config.holoScale = config.holoScale - 0.1; component.hologram.setScale(config.holoScale); save() end + end + elseif e[1] == "key_down" then + if e[4] == 19 then + config.dateColor = math.random(0x666666, 0xFFFFFF) + changeHoloColor() + save() + elseif e[4] == 28 then + save() + component.hologram.clear() + return + end + end +end + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloClock.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloClock.app/Resources/Icon.pic new file mode 100755 index 00000000..427da9b1 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloClock.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloEdit.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloEdit.app/Main.lua new file mode 100755 index 00000000..0d68db5f --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloEdit.app/Main.lua @@ -0,0 +1,785 @@ +-- Hologram Editor +-- by NEO, Totoro +-- 10/14/2014, all right reserved =) +-- райтс, хуяйтс, резервед ЙОПТА + +local MineOSCore = require("MineOSCore") +local unicode = require('unicode') +local event = require('event') +local term = require('term') +local fs = require('filesystem') +local com = require('component') +local gpu = com.gpu + +local lang = MineOSCore.getCurrentApplicationLocalization() + +-- Константы -- +HOLOH = 32 +HOLOW = 48 + +-- Цвета -- +backcolor = 0x000000 +forecolor = 0xFFFFFF +infocolor = 0x0066FF +errorcolor = 0xFF0000 +helpcolor = 0x006600 +graycolor = 0x080808 +goldcolor = 0xFFDF00 +-- *** -- + + +-- загружаем доп. оборудование +function trytofind(name) + if com.isAvailable(name) then + return com.getPrimary(name) + else + return nil + end +end + +local h = trytofind('hologram') + +-- ========================================= H O L O G R A P H I C S ========================================= -- +holo = {} +function set(x, y, z, value) + if holo[x] == nil then holo[x] = {} end + if holo[x][y] == nil then holo[x][y] = {} end + holo[x][y][z] = value +end +function get(x, y, z) + if holo[x] ~= nil and holo[x][y] ~= nil and holo[x][y][z] ~= nil then + return holo[x][y][z] + else + return 0 + end +end + +function save(filename) + -- сохраняем палитру + file = io.open(filename, 'wb') + for i=1, 3 do + for c=1, 3 do + file:write(string.char(colortable[i][c])) + end + end + -- сохраняем массив + for x=1, HOLOW do + for y=1, HOLOH do + for z=1, HOLOW, 4 do + a = get(x,y,z) + b = get(x,y,z+1) + c = get(x,y,z+2) + d = get(x,y,z+3) + byte = d*64 + c*16 + b*4 + a + file:write(string.char(byte)) + end + end + end + file:close() +end + +local function load(filename) + if fs.exists(filename) then + file = io.open(filename, 'rb') + -- загружаем палитру + for i=1, 3 do + for c=1, 3 do + colortable[i][c] = string.byte(file:read(1)) + end + setHexColor(i,colortable[i][1], + colortable[i][2], + colortable[i][3]) + end + -- загружаем массив + holo = {} + for x=1, HOLOW do + for y=1, HOLOH do + for z=1, HOLOW, 4 do + byte = string.byte(file:read(1)) + for i=0, 3 do + a = byte % 4 + byte = math.floor(byte / 4) + if a ~= 0 then set(x,y,z+i, a) end + end + end + end + end + file:close() + return true + else + --print("[ОШИБКА] Файл "..filename.." не найден.") + return false + end +end + + +-- ============================================= G R A P H I C S ============================================= -- +-- проверка разрешения экрана, для комфортной работы необходимо разрешение > HOLOW по высоте и ширине +OLDWIDTH, OLDHEIGHT = gpu.getResolution() +WIDTH, HEIGHT = gpu.maxResolution() +if HEIGHT < HOLOW+2 then + error(lang.badGPU) +else + WIDTH = HOLOW*2+40 + HEIGHT = HOLOW+2 + gpu.setResolution(WIDTH, HEIGHT) +end +gpu.setForeground(forecolor) +gpu.setBackground(backcolor) + +-- рисуем линию +local strLine = "+" +for i=1, WIDTH do + strLine = strLine..'-' +end +function line(x1, x2, y) + gpu.set(x1,y,string.sub(strLine, 1, x2-x1)) + gpu.set(x2,y,'+') +end + +-- рисуем фрейм +function frame(x1, y1, x2, y2, caption) + line(x1, x2, y1) + line(x1, x2, y2) + + if caption ~= nil then + gpu.set(x1+(x2-x1)/2-unicode.len(caption)/2, y1, caption) + end +end + +-- рисуем сетку +local strGrid = "" +for i=1, HOLOW/2 do + strGrid = strGrid.."██ " +end +function drawGrid(x, y) + gpu.fill(0, y, MENUX, HOLOW, ' ') + gpu.setForeground(graycolor) + for i=0, HOLOW-1 do + if view>0 and i==HOLOH then + gpu.setForeground(forecolor) + line(1, MENUX-1, y+HOLOH) + break + end + gpu.set(x+(i%2)*2, y+i, strGrid) + end + if view == 0 then gpu.setForeground(forecolor) end +end + +-- рисуем цветной прямоугольник +function drawRect(x, y, color) + gpu.set(x, y, "╓──────╖") + gpu.set(x, y+1, "║ ║") + gpu.set(x, y+2, "╙──────╜") + gpu.setForeground(color) + gpu.set(x+2, y+1, "████") + gpu.setForeground(forecolor) +end + +MENUX = HOLOW*2+5 +BUTTONW = 12 + +-- рисуем меню выбора "кисти" +function drawColorSelector() + frame(MENUX, 3, WIDTH-2, 16, lang.palette) + for i=0, 3 do + drawRect(MENUX+1+i*8, 5, hexcolortable[i]) + end + gpu.set(MENUX+1, 10, "R:") + gpu.set(MENUX+1, 11, "G:") + gpu.set(MENUX+1, 12, "B:") +end +function drawColorCursor(force) + if brush.color*8 ~= brush.x then brush.x = brush.color*8 end + if force or brush.gx ~= brush.x then + gpu.set(MENUX+1+brush.gx, 8, " ") + if brush.gx < brush.x then brush.gx = brush.gx + 1 end + if brush.gx > brush.x then brush.gx = brush.gx - 1 end + gpu.set(MENUX+1+brush.gx, 8, " -^--^- ") + end +end +function drawLayerSelector() + frame(MENUX, 16, WIDTH-2, 28, lang.layer) + gpu.set(MENUX+13, 18, lang.level) + gpu.set(MENUX+1, 23, lang.mainLevel) +end +function drawButtonsPanel() + frame(MENUX, 28, WIDTH-2, 36, lang.control) +end + +function mainScreen() + term.clear() + frame(1,1, WIDTH, HEIGHT, "{ Hologram Editor }") + -- "холст" + drawLayer() + drawColorSelector() + drawColorCursor(true) + drawLayerSelector() + drawButtonsPanel() + buttonsDraw() + textboxesDraw() + -- "about" - коротко о создателях + gpu.setForeground(infocolor) + gpu.setBackground(graycolor) + gpu.set(MENUX+3, HEIGHT-11, " Hologram Editor v0.60 Beta ") + gpu.setForeground(forecolor) + gpu.set(MENUX+3, HEIGHT-10, " * * * ") + gpu.set(MENUX+3, HEIGHT-9, lang.developers) + gpu.set(MENUX+3, HEIGHT-8, " NEO, Totoro ") + gpu.set(MENUX+3, HEIGHT-7, " * * * ") + gpu.set(MENUX+3, HEIGHT-6, lang.contact) + gpu.set(MENUX+3, HEIGHT-5, " computercraft.ru/forum ") + gpu.setBackground(backcolor) + -- выход + gpu.set(MENUX, HEIGHT-2, lang.quit) +end + + +-- =============================================== L A Y E R S =============================================== -- +GRIDX = 3 +GRIDY = 2 +function drawLayer() + drawGrid(GRIDX, GRIDY) + -- вид сверху (y) + if view == 0 then + for x=1, HOLOW do + for z=1, HOLOW do + gn = get(x, ghost_layer, z) + n = get(x, layer, z) + if n == 0 and gn ~= 0 then + gpu.setForeground(darkhexcolors[gn]) + gpu.set((GRIDX-2) + x*2, (GRIDY-1) + z, "░░") + end + if n ~= 0 then + gpu.setForeground(hexcolortable[n]) + gpu.set((GRIDX-2) + x*2, (GRIDY-1) + z, "██") + end + end + end + -- вид спереди (z) + elseif view == 1 then + for x=1, HOLOW do + for y=1, HOLOH do + n = get(x, y, layer) + gn = get(x, y, ghost_layer) + if n == 0 and gn ~= 0 then + gpu.setForeground(darkhexcolors[gn]) + gpu.set((GRIDX-2) + x*2, (GRIDY+HOLOH) - y, "░░") + end + if n ~= 0 then + gpu.setForeground(hexcolortable[n]) + gpu.set((GRIDX-2) + x*2, (GRIDY+HOLOH) - y, "██") + end + end + end + -- вид сбоку (x) + else + for z=1, HOLOW do + for y=1, HOLOH do + gn = get(ghost_layer, y, z) + n = get(layer, y, z) + if n == 0 and gn ~= 0 then + gpu.setForeground(darkhexcolors[gn]) + gpu.set((GRIDX+HOLOW*2) - z*2, (GRIDY+HOLOH) - y, "░░") + end + if n ~= 0 then + gpu.setForeground(hexcolortable[n]) + gpu.set((GRIDX+HOLOW*2) - z*2, (GRIDY+HOLOH) - y, "██") + end + end + end + end + gpu.setForeground(forecolor) + -- for messages + repaint = false +end +function fillLayer() + for x=1, HOLOW do + for z=1, HOLOW do + set(x, layer, z, brush.color) + end + end + drawLayer() +end +function clearLayer() + for x=1, HOLOW do + if holo[x] ~= nil then holo[x][layer] = nil end + end + drawLayer() +end + + +-- ============================================== B U T T O N S ============================================== -- +Button = {} +Button.__index = Button +function Button.new(func, x, y, text, color, width) + self = setmetatable({}, Button) + + self.form = '[ ' + if width == nil then width = 0 + else width = (width - unicode.len(text))-4 end + for i=1, math.floor(width/2) do + self.form = self.form.. ' ' + end + self.form = self.form..text + for i=1, math.ceil(width/2) do + self.form = self.form.. ' ' + end + self.form = self.form..' ]' + + self.func = func + + self.x = x; self.y = y + self.color = color + self.visible = true + + return self +end +function Button:draw(color) + if self.visible then + local color = color or self.color + gpu.setBackground(color) + if color > 0x888888 then gpu.setForeground(backcolor) end + gpu.set(self.x, self.y, self.form) + gpu.setBackground(backcolor) + if color > 0x888888 then gpu.setForeground(forecolor) end + end +end +function Button:click(x, y) + if self.visible then + if y == self.y then + if x >= self.x and x < self.x+unicode.len(self.form) then + self.func() + self:draw(self.color/2) + os.sleep(0.1) + self:draw() + return true + end + end + end + return false +end +buttons = {} +function buttonsNew(func, x, y, text, color, width) + table.insert(buttons, Button.new(func, x, y, text, color, width)) +end +function buttonsDraw() + for i=1, #buttons do + buttons[i]:draw() + end +end +function buttonsClick(x, y) + for i=1, #buttons do + buttons[i]:click(x, y) + end +end + +-- ================================ B U T T O N S F U N C T I O N A L I T Y ================================ -- +function exit() running = false end +function nextLayer() + -- ограничения разные для разных видов/проекций + local limit = HOLOH + if view > 0 then limit = HOLOW end + + if layer < limit then + layer = layer + 1 + tb_layer:setValue(layer) + tb_layer:draw(true) + moveGhost() + drawLayer() + end +end +function prevLayer() + if layer > 1 then + layer = layer - 1 + tb_layer:setValue(layer) + tb_layer:draw(true) + moveGhost() + drawLayer() + end +end +function setLayer(value) + local n = tonumber(value) + local limit = HOLOH + if view > 0 then limit = HOLOW end + if n == nil or n < 1 or n > limit then return false end + layer = n + moveGhost() + drawLayer() + return true +end +function nextGhost() + local limit = HOLOH + if view > 0 then limit = HOLOW end + + if ghost_layer_below then + ghost_layer_below = false + if ghost_layer < limit then + ghost_layer = layer + 1 + else ghost_layer = limit end + drawLayer() + else + if ghost_layer < limit then + ghost_layer = ghost_layer + 1 + drawLayer() + end + end +end +function prevGhost() + if not ghost_layer_below then + ghost_layer_below = true + if layer > 1 then + ghost_layer = layer - 1 + else ghost_layer = 1 end + drawLayer() + else + if ghost_layer > 1 then + ghost_layer = ghost_layer - 1 + drawLayer() + end + end +end +function setGhostLayer(value) + local n = tonumber(value) + local limit = HOLOH + if view > 0 then limit = HOLOW end + if n == nil or n < 1 or n > limit then return false end + ghost_layer = n + drawLayer() + return true +end +function moveGhost() + if ghost_layer_below then + if layer > 1 then ghost_layer = layer - 1 + else ghost_layer = 1 end + else + local limit = HOLOH + if view > 0 then limit = HOLOW end + if layer < limit then ghost_layer = layer + 1 + else ghost_layer = limit end + end +end + +function setFilename(str) + if str ~= nil and str ~= '' and unicode.len(str)<30 then + return true + else + return false + end +end + +function setHexColor(n, r, g, b) + local hexcolor = rgb2hex(r,g,b) + hexcolortable[n] = hexcolor + darkhexcolors[n] = bit32.rshift(bit32.band(hexcolor, 0xfefefe), 1) +end +function rgb2hex(r,g,b) + return r*65536+g*256+b +end +function changeRed(value) return changeColor(1, value) end +function changeGreen(value) return changeColor(2, value) end +function changeBlue(value) return changeColor(3, value) end +function changeColor(rgb, value) + if value == nil then return false end + n = tonumber(value) + if n == nil or n < 0 or n > 255 then return false end + -- сохраняем данные в таблицу + colortable[brush.color][rgb] = n + setHexColor(brush.color, colortable[brush.color][1], + colortable[brush.color][2], + colortable[brush.color][3]) + -- обновляем цвета на панельке + for i=0, 3 do + drawRect(MENUX+1+i*8, 5, hexcolortable[i]) + end + return true +end + +function moveSelector(num) + brush.color = num + tb_red:setValue(colortable[num][1]); tb_red:draw(true) + tb_green:setValue(colortable[num][2]); tb_green:draw(true) + tb_blue:setValue(colortable[num][3]); tb_blue:draw(true) +end + +function setTopView() + view = 0 + -- в виде сверху меньше слоев + if layer > HOLOH then layer = HOLOH end + drawLayer() +end +function setFrontView() view = 1; drawLayer() end +function setSideView() view = 2; drawLayer() end + +function drawHologram() + -- проверка на наличие проектора + h = trytofind('hologram') + if h ~= nil then + local depth = h.maxDepth() + -- очищаем + h.clear() + -- отправляем палитру + if depth == 2 then + for i=1, 3 do + h.setPaletteColor(i, hexcolortable[i]) + end + else + h.setPaletteColor(1, hexcolortable[1]) + end + -- отправляем массив + for x=1, HOLOW do + for y=1, HOLOH do + for z=1, HOLOW do + n = get(x,y,z) + if n ~= 0 then + if depth == 2 then + h.set(x,y,z,n) + else + h.set(x,y,z,1) + end + end + end + end + end + end +end + +function newHologram() + holo = {} + drawLayer() +end + +function saveHologram() + local filename = tb_file:getValue() + if filename ~= FILE_REQUEST then + -- выводим предупреждение + showMessage(lang.savingFile, lang.attention, goldcolor) + -- добавляем фирменное расширение =) + if string.sub(filename, -3) ~= '.3d' then + filename = filename..'.3d' + end + -- сохраняем + save(filename) + -- выводим предупреждение + showMessage(lang.complete, lang.attention, goldcolor) + repaint = true + end +end + +function loadHologram() + local filename = tb_file:getValue() + if filename ~= FILE_REQUEST then + -- выводим предупреждение + showMessage(lang.loadingFile, lang.attention, goldcolor) + -- добавляем фирменное расширение =) + if string.sub(filename, -3) ~= '.3d' then + filename = filename..'.3d' + end + -- загружаем + load(filename) + -- обновляем значения в текстбоксах + tb_red:setValue(colortable[brush.color][1]); tb_red:draw(true) + tb_green:setValue(colortable[brush.color][2]); tb_green:draw(true) + tb_blue:setValue(colortable[brush.color][3]); tb_blue:draw(true) + -- обновляем цвета на панельке + for i=0, 3 do + drawRect(MENUX+1+i*8, 5, hexcolortable[i]) + end + -- обновляем слой + drawLayer() + end +end + +-- ============================================ T E X T B O X E S ============================================ -- +Textbox = {} +Textbox.__index = Textbox +function Textbox.new(func, x, y, value, width) + self = setmetatable({}, Textbox) + + self.form = '>' + if width == nil then width = 10 end + for i=1, width-1 do + self.form = self.form..' ' + end + + self.func = func + self.value = tostring(value) + + self.x = x; self.y = y + self.visible = true + + return self +end +function Textbox:draw(content) + if self.visible then + if content then gpu.setBackground(graycolor) end + gpu.set(self.x, self.y, self.form) + if content then gpu.set(self.x+2, self.y, self.value) end + gpu.setBackground(backcolor) + end +end +function Textbox:click(x, y) + if self.visible then + if y == self.y then + if x >= self.x and x < self.x+unicode.len(self.form) then + self:draw(false) + term.setCursor(self.x+2, self.y) + value = string.sub(term.read({self.value}), 1, -2) + if self.func(value) then + self.value = value + end + self:draw(true) + return true + end + end + end + return false +end +function Textbox:setValue(value) + self.value = tostring(value) +end +function Textbox:getValue() + return self.value +end +textboxes = {} +function textboxesNew(func, x, y, value, width) + textbox = Textbox.new(func, x, y, value, width) + table.insert(textboxes, textbox) + return textbox +end +function textboxesDraw() + for i=1, #textboxes do + textboxes[i]:draw(true) + end +end +function textboxesClick(x, y) + for i=1, #textboxes do + textboxes[i]:click(x, y) + end +end + + +-- ============================================= M E S S A G E S ============================================= -- +repaint = false +function showMessage(text, caption, color) + local x = WIDTH/2 - unicode.len(text)/2 - 4 + local y = HEIGHT/2 - 2 + gpu.fill(x, y, unicode.len(text)+8, 5, ' ') + frame(x, y, x+unicode.len(text)+7, y+4, caption) + gpu.setForeground(color) + gpu.set(x+4,y+2, text) + gpu.setForeground(forecolor) +end + + +-- =========================================== M A I N C Y C L E =========================================== -- +-- инициализация +colortable = {{255, 0, 0}, {0, 255, 0}, {0, 102, 255}} +colortable[0] = {0, 0, 0} +hexcolortable = {} +darkhexcolors = {} +for i=0,3 do setHexColor(i, colortable[i][1], colortable[i][2], colortable[i][3]) end +brush = {color = 1, x = 8, gx = 8} +ghost_layer = 1 +ghost_layer_below = true +layer = 1 +view = 0 +running = true + +buttonsNew(exit, WIDTH-BUTTONW-2, HEIGHT-2, lang.exit, errorcolor, BUTTONW) +buttonsNew(drawLayer, MENUX+10, 14, lang.refresh, goldcolor, BUTTONW) +buttonsNew(prevLayer, MENUX+1, 19, '-', infocolor, 5) +buttonsNew(nextLayer, MENUX+7, 19, '+', infocolor, 5) +buttonsNew(setTopView, MENUX+1, 21, lang.fromUp, infocolor, 10) +buttonsNew(setFrontView, MENUX+12, 21, lang.fromFront, infocolor, 10) +buttonsNew(setSideView, MENUX+24, 21, lang.fromSide, infocolor, 9) + +buttonsNew(prevGhost, MENUX+1, 24, lang.lower, infocolor, 6) +buttonsNew(nextGhost, MENUX+10, 24, lang.upper, infocolor, 6) + +buttonsNew(clearLayer, MENUX+1, 26, lang.clear, infocolor, BUTTONW) +buttonsNew(fillLayer, MENUX+2+BUTTONW, 26, lang.fill, infocolor, BUTTONW) + +buttonsNew(drawHologram, MENUX+8, 30, lang.toProjector, goldcolor, 16) +buttonsNew(saveHologram, MENUX+1, 33, lang.save, helpcolor, BUTTONW) +buttonsNew(loadHologram, MENUX+8+BUTTONW, 33, lang.load, infocolor, BUTTONW) +buttonsNew(newHologram, MENUX+1, 35, lang.new, infocolor, BUTTONW) + +tb_red = textboxesNew(changeRed, MENUX+5, 10, '255', WIDTH-MENUX-7) +tb_green = textboxesNew(changeGreen, MENUX+5, 11, '0', WIDTH-MENUX-7) +tb_blue = textboxesNew(changeBlue, MENUX+5, 12, '0', WIDTH-MENUX-7) +tb_layer = textboxesNew(setLayer, MENUX+13, 19, '1', WIDTH-MENUX-15) +tb_ghostlayer = textboxesNew(setGhostLayer, MENUX+19, 24, ' ', WIDTH-MENUX-21) +FILE_REQUEST = lang.enterFileName +tb_file = textboxesNew(setFilename, MENUX+1, 32, FILE_REQUEST, WIDTH-MENUX-3) +mainScreen() + +while running do + if brush.x ~= brush.gx then name, add, x, y, b = event.pull(0.02) + else name, add, x, y, b = event.pull(1.0) end + + if name == 'key_down' then + -- если нажата 'Q' - выходим + if y == 16 then break + elseif y == 41 then + moveSelector(0) + elseif y>=2 and y<=4 then + moveSelector(y-1) + elseif y == 211 then + clearLayer() + end + elseif name == 'touch' then + -- проверка GUI + buttonsClick(x, y) + textboxesClick(x, y) + -- выбор цвета + if x>MENUX+1 and x4 and y<8 then + moveSelector(math.floor((x-MENUX-1)/8)) + end + end + end + if name == 'touch' or name == 'drag' then + -- "рисование" + local limit = HOLOW + if view > 0 then limit = HOLOH end + if x >= GRIDX and x < GRIDX+HOLOW*2 then + if y >= GRIDY and y < GRIDY+limit then + -- перерисуем, если на экране был мессейдж + if repaint then drawLayer() end + -- рассчет клика + if view == 0 then + dx = math.floor((x-GRIDX)/2)+1; gx = dx + dy = layer; gy = ghost_layer + dz = y-GRIDY+1; gz = dz + elseif view == 1 then + dx = math.floor((x-GRIDX)/2)+1; gx = dx + dy = HOLOH - (y-GRIDY); gy = dy + dz = layer; gz = ghost_layer + else + dx = layer; gx = ghost_layer + dy = HOLOH - (y-GRIDY); gy = dy + dz = HOLOW - math.floor((x-GRIDX)/2); gz = dz + end + if b == 0 and brush.color ~= 0 then + set(dx, dy, dz, brush.color) + gpu.setForeground(hexcolortable[brush.color]) + gpu.set(x-(x-GRIDX)%2, y, "██") + else + set(dx, dy, dz, 0) + gpu.setForeground(darkhexcolors[get(gx,gy,gz)]) + gpu.set(x-(x-GRIDX)%2, y, "░░") + end + gpu.setForeground(forecolor) + end + end + end + + drawColorCursor() +end + +-- завершение +term.clear() +gpu.setResolution(OLDWIDTH, OLDHEIGHT) +gpu.setForeground(0xFFFFFF) +gpu.setBackground(0x000000) diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloEdit.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloEdit.app/Resources/Icon.pic new file mode 100755 index 00000000..1e74fc67 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloEdit.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloEdit.app/Resources/Localization/English.lang b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloEdit.app/Resources/Localization/English.lang new file mode 100755 index 00000000..fe0905bc --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloEdit.app/Resources/Localization/English.lang @@ -0,0 +1,29 @@ +{ + badGPU = "[ERROR] Your monitor/GPU doesn't support required resolution.", + palette = "[ Palette ]", + control = "[ Control ]", + layer = "[ Layer ]", + level = "Hologram level:", + mainLevel = "Main level:", + quit = "Exit: 'Q' or ", + developers = "Developers: ", + contact = "Contact", + savingFile = "Saving file...", + loadingFile = "Loading file...", + attention = "[ Attention ]", + complete = "[ Done! ]", + exit = "Quit", + refresh = "Refresh", + fromUp = "Top", + fromFront = "Front", + fromSide = "Side", + upper = "Upper", + lower = "Lower", + clear = "Clear", + fill = "Fill", + toProjector = "To projector", + save = "Save", + load = "Load", + new = "New file", + enterFileName = "Enter file name here:", +} diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloEdit.app/Resources/Localization/Russian.lang b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloEdit.app/Resources/Localization/Russian.lang new file mode 100755 index 00000000..5780c77f --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/HoloEdit.app/Resources/Localization/Russian.lang @@ -0,0 +1,29 @@ +{ + badGPU = "[ОШИБКА] Ваш монитор/видеокарта не поддерживает требуемое разрешение.", + palette = "[ Палитра ]", + control = "[ Управление ]", + layer = "[ Слой ]", + level = "Уровень голограммы:", + mainLevel = "Направляющий уровень:", + quit = "Выход: 'Q' или ", + developers = "Разработчики: ", + contact = "Контакты:", + savingFile = "Сохраняю файл...", + loadingFile = "Загружаю файл...", + attention = "[ Внимание ]", + complete = "[ Файл сохранен! ]", + exit = "Выход", + refresh = "Обновить", + fromUp = "Сверху", + fromFront = "Спереди", + fromSide = "Сбоку", + upper = "Выше", + lower = "Ниже", + clear = "Очистить", + fill = "Залить", + toProjector = "На проектор", + save = "Сохранить", + load = "Загрузить", + new = "Новый файл", + enterFileName = "Введите сюда имя файла", +} diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Main.lua new file mode 100755 index 00000000..cbb299fd --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Main.lua @@ -0,0 +1,186 @@ +local ecs = require("ECSAPI") +local MineOSCore = require("MineOSCore") +local xml = require("xmlParser") +local image = require("image") +local event = require("event") +local unicode = require("unicode") +local fs = require("filesystem") +local gpu = require("component").gpu + +------------------------------------------------------------------------------------------------------------------ + +local config = { + scale = 0.63, + leftBarWidth = 20, + scrollSpeed = 6, + pathToInfoPanelFolder = MineOSCore.getCurrentApplicationResourcesDirectory() .. "Pages/", + colors = { + leftBar = 0xEEEEEE, + leftBarText = 0x262626, + leftBarSelection = 0x00C6FF, + leftBarSelectionText = 0xFFFFFF, + scrollbarBack = 0xEEEEEE, + scrollbarPipe = 0x3366CC, + background = 0x262626, + text = 0xFFFFFF, + }, +} + +local xOld, yOld = gpu.getResolution() +ecs.setScale(config.scale) +local xSize, ySize = gpu.getResolution() + +fs.makeDirectory(config.pathToInfoPanelFolder) +local currentFile = 1 +local fileList +local stroki = {} +local currentString = 1 +local stringsHeightLimit = ySize - 2 +local stringsWidthLimit = xSize - config.leftBarWidth - 4 + +------------------------------------------------------------------------------------------------------------------ + +local obj = {} +local function newObj(class, name, ...) + obj[class] = obj[class] or {} + obj[class][name] = {...} +end + +local function drawLeftBar() + --ecs.square(1, 1, config.leftBarWidth, ySize, config.colors.leftBar) + fileList = ecs.getFileList(config.pathToInfoPanelFolder) + obj["Files"] = {} + local yPos = 1, 1 + for i = 1, #fileList do + if i == currentFile then + newObj("Files", i, ecs.drawButton(1, yPos, config.leftBarWidth, 3, ecs.hideFileFormat(fileList[i]), config.colors.leftBarSelection, config.colors.leftBarSelectionText)) + else + if i % 2 == 0 then + newObj("Files", i, ecs.drawButton(1, yPos, config.leftBarWidth, 3, ecs.stringLimit("end", ecs.hideFileFormat(fileList[i]), config.leftBarWidth - 2), config.colors.leftBar, config.colors.leftBarText)) + else + newObj("Files", i, ecs.drawButton(1, yPos, config.leftBarWidth, 3, ecs.stringLimit("end", ecs.hideFileFormat(fileList[i]), config.leftBarWidth - 2), config.colors.leftBar - 0x111111, config.colors.leftBarText)) + end + end + yPos = yPos + 3 + end + ecs.square(1, yPos, config.leftBarWidth, ySize - yPos + 1, config.colors.leftBar) +end + +local function loadFile() + currentString = 1 + stroki = {} + local file = io.open(config.pathToInfoPanelFolder .. fileList[currentFile], "r") + for line in file:lines() do table.insert(stroki, xml.collect(line)) end + file:close() +end + +local function drawMain() + local x, y = config.leftBarWidth + 3, 2 + local xPos, yPos = x, y + + ecs.square(xPos, yPos, xSize - config.leftBarWidth - 5, ySize, config.colors.background) + gpu.setForeground(config.colors.text) + + for line = currentString, (stringsHeightLimit + currentString - 1) do + if stroki[line] then + for i = 1, #stroki[line] do + if type(stroki[line][i]) == "table" then + if stroki[line][i].label == "color" then + gpu.setForeground(tonumber(stroki[line][i][1])) + elseif stroki[line][i].label == "image" then + local bg, fg = gpu.getBackground(), gpu.getForeground() + local picture = image.load(stroki[line][i][1]) + image.draw(xPos, yPos, picture) + yPos = yPos + picture.height - 1 + gpu.setForeground(fg) + gpu.setBackground(bg) + end + else + gpu.set(xPos, yPos, stroki[line][i]) + xPos = xPos + unicode.len(stroki[line][i]) + end + end + yPos = yPos + 1 + xPos = x + else + break + end + end + +end + +local function drawScrollBar() + local name + name = "⬆"; newObj("Scroll", name, ecs.drawButton(xSize - 2, 1, 3, 3, name, config.colors.leftBarSelection, config.colors.leftBarSelectionText)) + name = "⬇"; newObj("Scroll", name, ecs.drawButton(xSize - 2, ySize - 2, 3, 3, name, config.colors.leftBarSelection, config.colors.leftBarSelectionText)) + + ecs.srollBar(xSize - 2, 4, 3, ySize - 6, #stroki, currentString, config.colors.scrollbarBack, config.colors.scrollbarPipe) +end + +------------------------------------------------------------------------------------------------------------------ + +ecs.prepareToExit() +drawLeftBar() +loadFile() +drawMain() +drawScrollBar() + +while true do + local e = {event.pull()} + if e[1] == "touch" then + for key in pairs(obj["Files"]) do + if ecs.clickedAtArea(e[3], e[4], obj["Files"][key][1], obj["Files"][key][2], obj["Files"][key][3], obj["Files"][key][4]) then + currentFile = key + loadFile() + drawLeftBar() + drawMain() + drawScrollBar() + break + end + end + + for key in pairs(obj["Scroll"]) do + if ecs.clickedAtArea(e[3], e[4], obj["Scroll"][key][1], obj["Scroll"][key][2], obj["Scroll"][key][3], obj["Scroll"][key][4]) then + ecs.drawButton(obj["Scroll"][key][1], obj["Scroll"][key][2], 3, 3, key, config.colors.leftBarSelectionText, config.colors.leftBarSelection) + os.sleep(0.2) + ecs.drawButton(obj["Scroll"][key][1], obj["Scroll"][key][2], 3, 3, key, config.colors.leftBarSelection, config.colors.leftBarSelectionText) + + if key == "⬆" then + if currentString > config.scrollSpeed then + currentString = currentString - config.scrollSpeed + drawMain() + drawScrollBar() + end + else + if currentString < (#stroki - config.scrollSpeed + 1) then + currentString = currentString + config.scrollSpeed + drawMain() + drawScrollBar() + end + end + + break + end + end + + elseif e[1] == "key_down" then + if e[4] == 28 then + gpu.setResolution(xOld, yOld) + ecs.prepareToExit() + return + end + end +end + + + + + + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/About/Russian.txt new file mode 100755 index 00000000..b82f7960 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Эта программа предназначена для визуального отображения информации для пользователей компьютера, она идеально впишется в ваш спавн, дом или милитаризированный бункер. Файлы с информацией хранятся в папке MineOS/System/InfoPanel, вы можете изменить их в любое время. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/Icon.pic new file mode 100755 index 00000000..8f074d12 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/Pages/Claims.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/Pages/Claims.txt new file mode 100755 index 00000000..4ff57557 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/Pages/Claims.txt @@ -0,0 +1,15 @@ + Приват + +Для привата и защиты от гриферства используется классический плагин +WorldGuard в совокупности с аддоном MachineGuard. + +● Приват осуществляется деревянным топором, проверка привата кожей. +● Количество блоков, доступное пользователю для привата: 700 000. +● Максимальное количество приватов на пользователя: 1. +● Приват сундуков, механизмов IC2, компьютеров и прочего создается + автоматически. +● Если вам мешает графическая подсветка выделения, используйте + команду //sel, чтобы убрать ее. +● Роботы не могут ломать блоки в привате, однако могут снимать + гаечным ключом механизмы IC2. Будьте внимательны и защищайте жилье + тщательно! \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/Pages/Main.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/Pages/Main.txt new file mode 100755 index 00000000..afb75d12 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/Pages/Main.txt @@ -0,0 +1,21 @@ + Главная + +Добро пожаловать на индустриальный сервер 0xFFAA00Buttex0xFFFFFF! С помощью этой панели +вы всегда можете узнать последние новости сервера и ознакомиться с +основными устоями, сложившимися в нашем обществе. Новичкам рекомендуется +прочитать все имеющиеся вкладки. + + История сервера + +Buttex существует с незапамятного 2010 года, когда кубач еще только +набирал свою популярность. Основным направлением сервера всегда были +красивые постройки, редстоун-схемы, а с недавних пор еще и кодинг +на компьютерах, предоставляемых модами. На сервере всегда царила +дружеская и домашняя атмосфера, которую мы поддерживаем из года в год. +Иногда, когда нашей теплой компании надоедало играть в кубики, мы +делали перерыв, но в скором времени сервер возрождался раз за разом. +Сейчас на дворе ноябрь, 2015 год, и мы вновь открываем Buttex для всех +желающих в новом формате - с собственным лаунчером, интересными модами +и грамотно настроенными плагинами. + + Приятной игры, дорогие мои! \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/Pages/Rules.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/Pages/Rules.txt new file mode 100755 index 00000000..c204a560 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/Pages/Rules.txt @@ -0,0 +1,49 @@ + Правила + +На сервере существует лишь одно правило: 0xFF5555нет никаких правил0xFFFFFF. + +Вам дозволяется абсолютно все: гриферство, читерство, мат в чате, +оскорбление админа и других игроков, ибо все это - неотъемлемая +часть нашего бытия. Вы можете быть культурным и святым человеком, +а можете крушить все направо-налево, строя хуи и свастики из грязи. +Помните, что не существует плохих или хороших деяний, есть лишь +поступки и их закономерные последствия. Таким образом, если вы +загадите личную хату админа, то он выебет вас по самые гланды, а если +будете неадекватным малым, то крайне велика вероятность, что вам +всадят нож в спину. + + Багоюз + +Любые баги - это вина администрации, безответственно отнесшейся к +исправлению ошибок плагинов и модов. Таким образом, если вы нашли +способ дюпа, способ использования недочетов сервера себе на благо, +крайне рекомендуется сообщить об этом админам - вы получите приятный +бонус за бдительность, а другие игроки получат честную игру. + + Флуд + +Если в чате творится полный бардак, и нежелательные личности флудят +или просто раздражают вас - используйте Систему Серверной Поддержки +Игроков, чтобы навести порядок: команда "0xFFAA00сервер замуть Cyka0xFFFFFF" +откроет голосование за мут игрока под ником Cyka. + + Убийства + +Вас убил сильно развитый игрок? Ну что ж, печально. Чтобы избежать +подобных эксцессов, защищайте ваше жилище тщательнее, закрывайте +дыры в обороне, копайте больше ресурсов для создания орудия мести. + + Гриферство + +Чей-то робот своровал ваши солнечные панели и механизмы IC2? Какая +неприятность! Чтобы защититься от этого, грамотно приватьте зону +вашего дома, закрывайте все щели, ставьте двери, которые нельзя +открыть редстоуном. Если вы узнали имя вора, обратитесь к обладателям +мощной брони и оружия, чтобы восстановить справедливость. + + Заключение + +Причиной всему этому "беззаконию" послужило наличие слишком больших +ограничений на большинстве серверов, где складывается впечатление, +что админы - нежные телки с завышенным ЧСВ. Но долой такую чушь! +Добро пожаловать на 0xFFAA00Buttex0xFFFFFF, где каждый сам себе хозяин! \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/Pages/SSPI.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/Pages/SSPI.txt new file mode 100755 index 00000000..a90842aa --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/InfoPanel.app/Resources/Pages/SSPI.txt @@ -0,0 +1,35 @@ + ССПИ + +У нас имеется автоматическая 0xFFAA00Серверная Система Поддержки Игроков0xFFFFFF, +сокращенно 0xFFAA00ССПИ0xFFFFFF. Она предназначена для минимизации контактов вида +игрок-админ, заменяя по сути целый штаб модераторов. Данная система +работает через чат в виде виртуального собеседника - вводите указанные +ниже команды и получайте результат. + +● 0xFFAA00Сервер дай ресов0xFFFFFF - вы получите произвольное количество произвольных + произвольно выбранных ресурсов. +● 0xFFAA00Сервер замуть [Username]0xFFFFFF - откроется публичное голосование за мут + игрока с ником Username. +● 0xFFAA00Сервер как дела 0xFFFFFF- если ССПИ будет в хорошем расположении духа, она + может рассказать, как у нее дела. За последствия плохого настроения + системы мы ответственности не несем. +● 0xFFAA00Сервер очисти чат0xFFFFFF - очищает чат лично для вас, отправляя вам в ЛС + большое количество пробелов. +● 0xFFAA00Сервер скажи админам [сообщение]0xFFFFFF - отправляет всем администраторам + сообщение, даже если они отсутствуют на сервере. Впоследствии они + смогут его прочесть. +● 0xFFAA00Сервер вероятность [событие]0xFFFFFF - вычисляет вероятность какого-либо + события. Полезно, чтобы доказать кому-то, что он пидор. +● 0xFFAA00Сервер хеш [фраза]0xFFFFFF - возвращает хеш-сумму указанной фразы, просчитанную + по алгоритму SHA2-256. + +Следующие команды для ССПИ предназначены только для администраторов, +у простых смертных к ним нет доступа: + +● 0xFFAA00Сервер отпизди [Username]0xFFFFFF - убивает игрока с ником Username. +● 0xFFAA00Сервер сделай день/ночь0xFFFFFF - устанавливает указанное время суток. +● 0xFFAA00Сервер включи/выключи свет0xFFFFFF - управление освещение спавна. + +Кроме того, ключевое слово "Сервер" имеет несколько синонимов +для удобства: серв, сервак, ССПИ, а также все эти вариации, +написанные с заглавной буквы. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/MineCode IDE.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/MineCode IDE.app/Main.lua new file mode 100755 index 00000000..535326b8 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/MineCode IDE.app/Main.lua @@ -0,0 +1,1855 @@ + +---------------------------------------------------- Libraries ---------------------------------------------------- + +-- "/MineOS/Applications/MineCode IDE.app/MineCode IDE.lua" -o /OS.lua + +-- package.loaded.syntax = nil +-- package.loaded.ECSAPI = nil +-- package.loaded.GUI = nil +-- package.loaded.MineOSCore = nil + +local args = {...} +require("advancedLua") +local computer = require("computer") +local component = require("component") +local fs = require("filesystem") +local buffer = require("doubleBuffering") +local event = require("event") +local syntax = require("syntax") +local unicode = require("unicode") +local web = require("web") +local image = require("image") +local keyboard = require("keyboard") +local GUI = require("GUI") +local MineOSPaths = require("MineOSPaths") +local MineOSCore = require("MineOSCore") +local MineOSInterface = require("MineOSInterface") + +---------------------------------------------------- Constants ---------------------------------------------------- + +local about = { + "MineCode IDE", + "Copyright © 2014-2017 ECS Inc.", + " ", + "Developers:", + " ", + "Timofeev Igor, vk.com/id7799889", + "Trifonov Gleb, vk.com/id88323331", + " ", + "Testers:", + " ", + "Semyonov Semyon, vk.com/id92656626", + "Prosin Mihail, vk.com/id75667079", + "Shestakov Timofey, vk.com/id113499693", + "Bogushevich Victoria, vk.com/id171497518", + "Vitvitskaya Yana, vk.com/id183425349", + "Golovanova Polina, vk.com/id226251826", +} + +local config = { + leftTreeViewWidth = 26, + syntaxColorScheme = syntax.colorScheme, + scrollSpeed = 8, + cursorColor = 0x00A8FF, + cursorSymbol = "┃", + cursorBlinkDelay = 0.5, + doubleClickDelay = 0.4, + screenResolution = {}, + enableAutoBrackets = true, + highlightLuaSyntax = true, + enableAutocompletion = true, +} +config.screenResolution.width, config.screenResolution.height = component.gpu.getResolution() + +local colors = { + topToolBar = 0xDDDDDD, + bottomToolBar = { + background = 0x3C3C3C, + buttons = 0x2D2D2D, + buttonsText = 0xFFFFFF, + }, + topMenu = { + backgroundColor = 0xEEEEEE, + textColor = 0x444444, + backgroundPressedColor = 0x3366CC, + textPressedColor = 0xFFFFFF, + }, + title = { + default = { + sides = 0x555555, + background = 0x3C3C3C, + text = 0xEEEEEE, + }, + onError = { + sides = 0xCC4940, + background = 0x880000, + text = 0xEEEEEE, + }, + }, + highlights = { + onError = 0xFF4940, + onBreakpoint = 0x990000, + } +} + +local possibleBrackets = { + openers = { + ["{"] = "}", + ["["] = "]", + ["("] = ")", + ["\""] = "\"", + ["\'"] = "\'" + }, + closers = { + ["}"] = "{", + ["]"] = "[", + [")"] = "(", + ["\""] = "\"", + ["\'"] = "\'" + } +} + +local cursor = { + position = { + symbol = 1, + line = 1 + }, + blinkState = false +} + +local scriptCoroutine +local resourcesPath = MineOSCore.getCurrentApplicationResourcesDirectory() +local configPath = MineOSPaths.applicationData .. "MineCode IDE/Config.cfg" +local localization = MineOSCore.getLocalization(resourcesPath .. "Localization/") +local findStartFrom +local clipboard +local breakpointLines +local lastErrorLine +local autocompleteDatabase + +------------------------------------------------------------------------------------------------------------------ + +local function convertTextPositionToScreenCoordinates(symbol, line) + return + mainContainer.codeView.codeAreaPosition + symbol - mainContainer.codeView.fromSymbol + 1, + mainContainer.codeView.y + line - mainContainer.codeView.fromLine +end + +local function convertScreenCoordinatesToTextPosition(x, y) + return x - mainContainer.codeView.codeAreaPosition + mainContainer.codeView.fromSymbol - 1, y - mainContainer.codeView.y + mainContainer.codeView.fromLine +end + +------------------------------------------------------------------------------------------------------------------ + +local function saveConfig() + table.toFile(configPath, config) +end + +local function loadConfig() + if fs.exists(configPath) then + config = table.fromFile(configPath) + syntax.colorScheme = config.syntaxColorScheme + else + saveConfig() + end +end + +------------------------------------------------------------------------------------------------------------------ + +local function updateAutocompleteDatabaseFromString(str, value) + for word in str:gmatch("[%a%d%_]+") do + if not word:match("^%d+$") then + autocompleteDatabase[word] = value + end + end +end + +local function updateAutocompleteDatabaseFromFile() + if config.enableAutocompletion then + autocompleteDatabase = {} + for line = 1, #mainContainer.codeView.lines do + updateAutocompleteDatabaseFromString(mainContainer.codeView.lines[line], true) + end + end +end + +local function getCurrentWordStartingAndEnding(fromSymbol) + local shittySymbolsRegexp, from, to = "[%s%c%p]" + + for i = fromSymbol, 1, -1 do + if unicode.sub(mainContainer.codeView.lines[cursor.position.line], i, i):match(shittySymbolsRegexp) then break end + from = i + end + + for i = fromSymbol, unicode.len(mainContainer.codeView.lines[cursor.position.line]) do + if unicode.sub(mainContainer.codeView.lines[cursor.position.line], i, i):match(shittySymbolsRegexp) then break end + to = i + end + + return from, to +end + +local function aplhabeticalSort(t) + table.sort(t, function(a, b) return a[1] < b[1] end) +end + +local function getAutocompleteDatabaseMatches(stringToSearch) + local matches = {} + + for word in pairs(autocompleteDatabase) do + if word ~= stringToSearch then + local match = word:match("^" .. stringToSearch) + if match then + table.insert(matches, { word, match }) + end + end + end + + aplhabeticalSort(matches) + return matches +end + +local function hideAutocompleteWindow() + mainContainer.autocompleteWindow.hidden = true +end + +local function showAutocompleteWindow() + if config.enableAutocompletion then + mainContainer.autocompleteWindow.currentWordStarting, mainContainer.autocompleteWindow.currentWordEnding = getCurrentWordStartingAndEnding(cursor.position.symbol - 1) + + if mainContainer.autocompleteWindow.currentWordStarting then + mainContainer.autocompleteWindow.matches = getAutocompleteDatabaseMatches( + unicode.sub( + mainContainer.codeView.lines[cursor.position.line], + mainContainer.autocompleteWindow.currentWordStarting, + mainContainer.autocompleteWindow.currentWordEnding + ) + ) + + if #mainContainer.autocompleteWindow.matches > 0 then + mainContainer.autocompleteWindow.fromMatch, mainContainer.autocompleteWindow.currentMatch = 1, 1 + mainContainer.autocompleteWindow.hidden = false + else + hideAutocompleteWindow() + end + else + hideAutocompleteWindow() + end + end +end + +local function toggleEnableAutocompleteDatabase() + config.enableAutocompletion = not config.enableAutocompletion + autocompleteDatabase = {} + saveConfig() +end + +------------------------------------------------------------------------------------------------------------------ + +local function calculateSizes() + mainContainer.width, mainContainer.height = buffer.getResolution() + + if mainContainer.leftTreeView.hidden then + mainContainer.codeView.localX, mainContainer.codeView.width = 1, mainContainer.width + mainContainer.bottomToolBar.localX, mainContainer.bottomToolBar.width = mainContainer.codeView.localX, mainContainer.codeView.width + else + mainContainer.codeView.localX, mainContainer.codeView.width = mainContainer.leftTreeView.width + 1, mainContainer.width - mainContainer.leftTreeView.width + mainContainer.bottomToolBar.localX, mainContainer.bottomToolBar.width = mainContainer.codeView.localX, mainContainer.codeView.width + end + + if mainContainer.topToolBar.hidden then + mainContainer.leftTreeView.localY, mainContainer.leftTreeView.height = 2, mainContainer.height - 1 + mainContainer.codeView.localY, mainContainer.codeView.height = 2, mainContainer.height - 1 + mainContainer.errorContainer.localY = 2 + else + mainContainer.leftTreeView.localY, mainContainer.leftTreeView.height = 5, mainContainer.height - 4 + mainContainer.codeView.localY, mainContainer.codeView.height = 5, mainContainer.height - 4 + mainContainer.errorContainer.localY = 5 + end + + if mainContainer.bottomToolBar.hidden then + + else + mainContainer.codeView.height = mainContainer.codeView.height - 3 + end + + mainContainer.leftTreeViewResizer.localX = mainContainer.leftTreeView.width - 2 + mainContainer.leftTreeViewResizer.localY = math.floor(mainContainer.leftTreeView.localY + mainContainer.leftTreeView.height / 2 - mainContainer.leftTreeViewResizer.height / 2) + + mainContainer.settingsContainer.width, mainContainer.settingsContainer.height = mainContainer.width, mainContainer.height + mainContainer.settingsContainer.backgroundPanel.width, mainContainer.settingsContainer.backgroundPanel.height = mainContainer.settingsContainer.width, mainContainer.settingsContainer.height + + mainContainer.bottomToolBar.localY = mainContainer.height - 2 + mainContainer.bottomToolBar.findButton.localX = mainContainer.bottomToolBar.width - mainContainer.bottomToolBar.findButton.width + 1 + mainContainer.bottomToolBar.inputField.width = mainContainer.bottomToolBar.width - mainContainer.bottomToolBar.inputField.localX - mainContainer.bottomToolBar.findButton.width + 1 + + mainContainer.topToolBar.width, mainContainer.topToolBar.backgroundPanel.width = mainContainer.width, mainContainer.width + mainContainer.titleTextBox.width = math.floor(mainContainer.topToolBar.width * 0.32) + mainContainer.titleTextBox.localX = math.floor(mainContainer.topToolBar.width / 2 - mainContainer.titleTextBox.width / 2) + mainContainer.runButton.localX = mainContainer.titleTextBox.localX - mainContainer.runButton.width - 2 + mainContainer.toggleSyntaxHighlightingButton.localX = mainContainer.runButton.localX - mainContainer.toggleSyntaxHighlightingButton.width - 2 + mainContainer.addBreakpointButton.localX = mainContainer.toggleSyntaxHighlightingButton.localX - mainContainer.addBreakpointButton.width - 2 + mainContainer.toggleLeftToolBarButton.localX = mainContainer.titleTextBox.localX + mainContainer.titleTextBox.width + 2 + mainContainer.toggleBottomToolBarButton.localX = mainContainer.toggleLeftToolBarButton.localX + mainContainer.toggleLeftToolBarButton.width + 2 + mainContainer.toggleTopToolBarButton.localX = mainContainer.toggleBottomToolBarButton.localX + mainContainer.toggleBottomToolBarButton.width + 2 + + mainContainer.RAMUsageProgressBar.localX = mainContainer.toggleTopToolBarButton.localX + mainContainer.toggleTopToolBarButton.width + 3 + mainContainer.RAMUsageProgressBar.width = mainContainer.topToolBar.width - mainContainer.RAMUsageProgressBar.localX - 3 + + mainContainer.errorContainer.localX, mainContainer.errorContainer.width = mainContainer.titleTextBox.localX, mainContainer.titleTextBox.width + mainContainer.errorContainer.backgroundPanel.width, mainContainer.errorContainer.errorTextBox.width = mainContainer.errorContainer.width, mainContainer.errorContainer.width - 4 + + mainContainer.topMenu.width = mainContainer.width +end + +local function updateTitle() + if not mainContainer.topToolBar.hidden then + if mainContainer.errorContainer.hidden then + mainContainer.titleTextBox.lines[1] = string.limit(localization.file .. ": " .. (mainContainer.leftTreeView.selectedItem or localization.none), mainContainer.titleTextBox.width - 4) + mainContainer.titleTextBox.lines[2] = string.limit(localization.cursor .. cursor.position.line .. localization.line .. cursor.position.symbol .. localization.symbol, mainContainer.titleTextBox.width - 4) + if mainContainer.codeView.selections[1] then + local countOfSelectedLines = mainContainer.codeView.selections[1].to.line - mainContainer.codeView.selections[1].from.line + 1 + local countOfSelectedSymbols + if mainContainer.codeView.selections[1].from.line == mainContainer.codeView.selections[1].to.line then + countOfSelectedSymbols = unicode.len(unicode.sub(mainContainer.codeView.lines[mainContainer.codeView.selections[1].from.line], mainContainer.codeView.selections[1].from.symbol, mainContainer.codeView.selections[1].to.symbol)) + else + countOfSelectedSymbols = unicode.len(unicode.sub(mainContainer.codeView.lines[mainContainer.codeView.selections[1].from.line], mainContainer.codeView.selections[1].from.symbol, -1)) + for line = mainContainer.codeView.selections[1].from.line + 1, mainContainer.codeView.selections[1].to.line - 1 do + countOfSelectedSymbols = countOfSelectedSymbols + unicode.len(mainContainer.codeView.lines[line]) + end + countOfSelectedSymbols = countOfSelectedSymbols + unicode.len(unicode.sub(mainContainer.codeView.lines[mainContainer.codeView.selections[1].to.line], 1, mainContainer.codeView.selections[1].to.symbol)) + end + mainContainer.titleTextBox.lines[3] = string.limit(localization.selection .. countOfSelectedLines .. localization.lines .. countOfSelectedSymbols .. localization.symbols, mainContainer.titleTextBox.width - 4) + else + mainContainer.titleTextBox.lines[3] = string.limit(localization.selection .. localization.none, mainContainer.titleTextBox.width - 4) + end + else + mainContainer.titleTextBox.lines[1], mainContainer.titleTextBox.lines[3] = " ", " " + if lastErrorLine then + mainContainer.titleTextBox.lines[2] = localization.runtimeError + else + mainContainer.titleTextBox.lines[2] = localization.debugging .. (_G.MineCodeIDEDebugInfo and _G.MineCodeIDEDebugInfo.line or "N/A") + end + end + end +end + +local function gotoLine(line) + mainContainer.codeView.fromLine = math.ceil(line - mainContainer.codeView.height / 2) + if mainContainer.codeView.fromLine < 1 then + mainContainer.codeView.fromLine = 1 + elseif mainContainer.codeView.fromLine > #mainContainer.codeView.lines then + mainContainer.codeView.fromLine = #mainContainer.codeView.lines + end +end + +local function updateHighlights() + mainContainer.codeView.highlights = {} + + if breakpointLines then + for i = 1, #breakpointLines do + mainContainer.codeView.highlights[breakpointLines[i]] = colors.highlights.onBreakpoint + end + end + + if lastErrorLine then + mainContainer.codeView.highlights[lastErrorLine] = colors.highlights.onError + end +end + +local function calculateErrorContainerSizeAndBeep(hideBreakpointButtons, frequency, times) + mainContainer.errorContainer.errorTextBox.height = #mainContainer.errorContainer.errorTextBox.lines + mainContainer.errorContainer.height = 2 + mainContainer.errorContainer.errorTextBox.height + mainContainer.errorContainer.backgroundPanel.height = mainContainer.errorContainer.height + + mainContainer.errorContainer.breakpointExitButton.hidden, mainContainer.errorContainer.breakpointContinueButton.hidden = hideBreakpointButtons, hideBreakpointButtons + if not hideBreakpointButtons then + mainContainer.errorContainer.height = mainContainer.errorContainer.height + 1 + mainContainer.errorContainer.breakpointExitButton.localY, mainContainer.errorContainer.breakpointContinueButton.localY = mainContainer.errorContainer.height, mainContainer.errorContainer.height + mainContainer.errorContainer.breakpointExitButton.width = math.floor(mainContainer.errorContainer.width / 2) + mainContainer.errorContainer.breakpointContinueButton.localX, mainContainer.errorContainer.breakpointContinueButton.width = mainContainer.errorContainer.breakpointExitButton.width + 1, mainContainer.errorContainer.width - mainContainer.errorContainer.breakpointExitButton.width + end + + updateTitle() + mainContainer:draw() + buffer.draw() + + for i = 1, times do component.computer.beep(frequency, 0.08) end +end + +local function showBreakpointMessage(variables) + mainContainer.titleTextBox.colors.background, mainContainer.titleTextBox.colors.text = colors.title.onError.background, colors.title.onError.text + mainContainer.errorContainer.hidden = false + + mainContainer.errorContainer.errorTextBox:setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + mainContainer.errorContainer.errorTextBox.lines = {} + + for variable, value in pairs(variables) do + table.insert(mainContainer.errorContainer.errorTextBox.lines, variable .. " = " .. value) + end + + if #mainContainer.errorContainer.errorTextBox.lines > 0 then + table.insert(mainContainer.errorContainer.errorTextBox.lines, 1, " ") + table.insert(mainContainer.errorContainer.errorTextBox.lines, 1, {text = localization.variables, color = 0x0}) + else + table.insert(mainContainer.errorContainer.errorTextBox.lines, 1, {text = localization.variablesNotAvailable, color = 0x0}) + end + + calculateErrorContainerSizeAndBeep(false, 1800, 1) +end + +local function showErrorContainer(errorCode) + mainContainer.titleTextBox.colors.background, mainContainer.titleTextBox.colors.text = colors.title.onError.background, colors.title.onError.text + mainContainer.errorContainer.hidden = false + + mainContainer.errorContainer.errorTextBox:setAlignment(GUI.alignment.horizontal.left, GUI.alignment.vertical.top) + mainContainer.errorContainer.errorTextBox.lines = string.wrap({errorCode}, mainContainer.errorContainer.errorTextBox.width) + + -- Извлекаем ошибочную строку текущего скрипта + lastErrorLine = tonumber(errorCode:match("%:(%d+)%: in main chunk")) + if lastErrorLine then + -- Делаем поправку на количество брейкпоинтов в виде вставленных дебаг-строк + if breakpointLines then + local countOfBreakpointsBeforeLastErrorLine = 0 + for i = 1, #breakpointLines do + if breakpointLines[i] < lastErrorLine then + countOfBreakpointsBeforeLastErrorLine = countOfBreakpointsBeforeLastErrorLine + 1 + else + break + end + end + lastErrorLine = lastErrorLine - countOfBreakpointsBeforeLastErrorLine + end + gotoLine(lastErrorLine) + end + updateHighlights() + calculateErrorContainerSizeAndBeep(true, 1500, 3) +end + +local function hideErrorContainer() + mainContainer.titleTextBox.colors.background, mainContainer.titleTextBox.colors.text = colors.title.default.background, colors.title.default.text + mainContainer.errorContainer.hidden = true + lastErrorLine, scriptCoroutine = nil, nil + updateHighlights() +end + +local function hideSettingsContainer() + for childIndex = 2, #mainContainer.settingsContainer.children do mainContainer.settingsContainer.children[childIndex] = nil end + mainContainer.settingsContainer.hidden = true + mainContainer:draw() + buffer.draw() +end + +local function clearSelection() + mainContainer.codeView.selections[1] = nil +end + +local function clearBreakpoints() + breakpointLines = nil + updateHighlights() +end + +local function addBreakpoint() + hideErrorContainer() + breakpointLines = breakpointLines or {} + + local lineExists + for i = 1, #breakpointLines do + if breakpointLines[i] == cursor.position.line then + lineExists = i + break + end + end + + if lineExists then + table.remove(breakpointLines, lineExists) + else + table.insert(breakpointLines, cursor.position.line) + end + + if #breakpointLines > 0 then + table.sort(breakpointLines, function(a, b) return a < b end) + else + breakpointLines = nil + end + + updateHighlights() +end + +local function fixFromLineByCursorPosition() + if mainContainer.codeView.fromLine > cursor.position.line then + mainContainer.codeView.fromLine = cursor.position.line + elseif mainContainer.codeView.fromLine + mainContainer.codeView.height - 2 < cursor.position.line then + mainContainer.codeView.fromLine = cursor.position.line - mainContainer.codeView.height + 2 + end +end + +local function fixFromSymbolByCursorPosition() + if mainContainer.codeView.fromSymbol > cursor.position.symbol then + mainContainer.codeView.fromSymbol = cursor.position.symbol + elseif mainContainer.codeView.fromSymbol + mainContainer.codeView.codeAreaWidth - 3 < cursor.position.symbol then + mainContainer.codeView.fromSymbol = cursor.position.symbol - mainContainer.codeView.codeAreaWidth + 3 + end +end + +local function fixCursorPosition(symbol, line) + if line < 1 then + line = 1 + elseif line > #mainContainer.codeView.lines then + line = #mainContainer.codeView.lines + end + + local lineLength = unicode.len(mainContainer.codeView.lines[line]) + if symbol < 1 or lineLength == 0 then + symbol = 1 + elseif symbol > lineLength then + symbol = lineLength + 1 + end + + return symbol, line +end + +local function setCursorPosition(symbol, line) + cursor.position.symbol, cursor.position.line = fixCursorPosition(symbol, line) + fixFromLineByCursorPosition() + fixFromSymbolByCursorPosition() + hideAutocompleteWindow() + hideErrorContainer() +end + +local function setCursorPositionAndClearSelection(symbol, line) + setCursorPosition(symbol, line) + clearSelection() +end + +local function moveCursor(symbolOffset, lineOffset) + if mainContainer.autocompleteWindow.hidden or lineOffset == 0 then + if mainContainer.codeView.selections[1] then + if symbolOffset < 0 or lineOffset < 0 then + setCursorPositionAndClearSelection(mainContainer.codeView.selections[1].from.symbol, mainContainer.codeView.selections[1].from.line) + else + setCursorPositionAndClearSelection(mainContainer.codeView.selections[1].to.symbol, mainContainer.codeView.selections[1].to.line) + end + else + local newSymbol, newLine = cursor.position.symbol + symbolOffset, cursor.position.line + lineOffset + + if symbolOffset < 0 and newSymbol < 1 then + newLine, newSymbol = newLine - 1, math.huge + elseif symbolOffset > 0 and newSymbol > unicode.len(mainContainer.codeView.lines[newLine] or "") + 1 then + newLine, newSymbol = newLine + 1, 1 + end + + setCursorPositionAndClearSelection(newSymbol, newLine) + end + elseif not mainContainer.autocompleteWindow.hidden then + mainContainer.autocompleteWindow.currentMatch = mainContainer.autocompleteWindow.currentMatch + lineOffset + + if mainContainer.autocompleteWindow.currentMatch < 1 then + mainContainer.autocompleteWindow.currentMatch = 1 + elseif mainContainer.autocompleteWindow.currentMatch > #mainContainer.autocompleteWindow.matches then + mainContainer.autocompleteWindow.currentMatch = #mainContainer.autocompleteWindow.matches + elseif mainContainer.autocompleteWindow.currentMatch < mainContainer.autocompleteWindow.fromMatch then + mainContainer.autocompleteWindow.fromMatch = mainContainer.autocompleteWindow.currentMatch + elseif mainContainer.autocompleteWindow.currentMatch > mainContainer.autocompleteWindow.fromMatch + mainContainer.autocompleteWindow.height - 1 then + mainContainer.autocompleteWindow.fromMatch = mainContainer.autocompleteWindow.currentMatch - mainContainer.autocompleteWindow.height + 1 + end + end +end + +local function setCursorPositionToHome() + setCursorPositionAndClearSelection(1, 1) +end + +local function setCursorPositionToEnd() + setCursorPositionAndClearSelection(unicode.len(mainContainer.codeView.lines[#mainContainer.codeView.lines]) + 1, #mainContainer.codeView.lines) +end + +local function scroll(direction, speed) + if direction == 1 then + if mainContainer.codeView.fromLine > speed then + mainContainer.codeView.fromLine = mainContainer.codeView.fromLine - speed + else + mainContainer.codeView.fromLine = 1 + end + else + if mainContainer.codeView.fromLine < #mainContainer.codeView.lines - speed then + mainContainer.codeView.fromLine = mainContainer.codeView.fromLine + speed + else + mainContainer.codeView.fromLine = #mainContainer.codeView.lines + end + end +end + +local function pageUp() + scroll(1, mainContainer.codeView.height - 2) +end + +local function pageDown() + scroll(-1, mainContainer.codeView.height - 2) +end + +local function selectWord() + local from, to = getCurrentWordStartingAndEnding(cursor.position.symbol) + if from and to then + mainContainer.codeView.selections[1] = { + from = {symbol = from, line = cursor.position.line}, + to = {symbol = to, line = cursor.position.line}, + } + cursor.position.symbol = to + end +end + +local function removeTabs(text) + local result = text:gsub("\t", string.rep(" ", mainContainer.codeView.indentationWidth)) + return result +end + +local function removeWindowsLineEndings(text) + local result = text:gsub("\r\n", "\n") + return result +end + +local function changeResolution(width, height) + buffer.setResolution(width, height) + calculateSizes() + mainContainer:draw() + buffer.draw() + config.screenResolution.width = width + config.screenResolution.height = height +end + +local function changeResolutionWindow() + mainContainer.settingsContainer.hidden = false + local textBoxesWidth = math.floor(mainContainer.width * 0.3) + local textBoxWidth, x, y = math.floor(textBoxesWidth / 2), math.floor(mainContainer.width / 2 - textBoxesWidth / 2), math.floor(mainContainer.height / 2) - 3 + + mainContainer.settingsContainer:addChild(GUI.label(1, y, mainContainer.width, 1, 0xFFFFFF, localization.changeResolution)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 3 + local inputFieldWidth = mainContainer.settingsContainer:addChild(GUI.input(x, y, textBoxWidth, 3, 0xCCCCCC, 0x777777, 0x777777, 0xCCCCCC, 0x2D2D2D, tostring(config.screenResolution.width))); x = x + textBoxWidth + 2 + local inputFieldHeight = mainContainer.settingsContainer:addChild(GUI.input(x, y, textBoxWidth, 3, 0xCCCCCC, 0x777777, 0x777777, 0xCCCCCC, 0x2D2D2D, tostring(config.screenResolution.height))) + + local maxResolutionWidth, maxResolutionHeight = component.gpu.maxResolution() + inputFieldWidth.validator = function(text) + local number = tonumber(text) + if number and number >= 1 and number <= maxResolutionWidth then return true end + end + inputFieldHeight.validator = function(text) + local number = tonumber(text) + if number and number >= 1 and number <= maxResolutionHeight then return true end + end + + mainContainer.settingsContainer.backgroundPanel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + config.screenResolution.width, config.screenResolution.height = tonumber(inputFieldWidth.text), tonumber(inputFieldHeight.text) + saveConfig() + hideSettingsContainer() + changeResolution(config.screenResolution.width, config.screenResolution.height) + end + end +end + +local function createInputTextBoxForSettingsWindow(title, placeholder, onInputFinishedMethod, validatorMethod) + mainContainer.settingsContainer.hidden = false + local textBoxWidth = math.floor(mainContainer.width * 0.3) + local x, y = math.floor(mainContainer.width / 2 - textBoxWidth / 2), math.floor(mainContainer.height / 2) - 3 + + mainContainer.settingsContainer:addChild(GUI.label(1, y, mainContainer.width, 1, 0xFFFFFF, title)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 3 + mainContainer.settingsContainer.inputField = mainContainer.settingsContainer:addChild(GUI.input(x, y, textBoxWidth, 3, 0xCCCCCC, 0x777777, 0x777777, 0xCCCCCC, 0x2D2D2D, "", placeholder)) + + mainContainer.settingsContainer.inputField.validator = validatorMethod + mainContainer.settingsContainer.inputField.onInputFinished = function(...) + onInputFinishedMethod(...) + hideSettingsContainer() + end +end + +local function newFile() + autocompleteDatabase = {} + mainContainer.codeView.lines = {""} + mainContainer.codeView.maximumLineLength = 1 + setCursorPositionAndClearSelection(1, 1) + mainContainer.leftTreeView.selectedItem = nil + clearBreakpoints() +end + +local function loadFile(path) + newFile() + + local file = io.open(path, "r") + for line in file:lines() do + line = removeWindowsLineEndings(removeTabs(line)) + table.insert(mainContainer.codeView.lines, line) + mainContainer.codeView.maximumLineLength = math.max(mainContainer.codeView.maximumLineLength, unicode.len(line)) + end + file:close() + + if #mainContainer.codeView.lines > 1 then + table.remove(mainContainer.codeView.lines, 1) + end + + mainContainer.leftTreeView.selectedItem = path + updateAutocompleteDatabaseFromFile() +end + +local function saveFile(path) + fs.makeDirectory(fs.path(path)) + local file, reason = io.open(path, "w") + if file then + for line = 1, #mainContainer.codeView.lines do + file:write(mainContainer.codeView.lines[line], "\n") + end + file:close() + else + GUI.error("Failed to open file for writing: " .. tostring(reason)) + end +end + +local function gotoLineWindow() + createInputTextBoxForSettingsWindow(localization.gotoLine, localization.lineNumber, + function() + gotoLine(tonumber(mainContainer.settingsContainer.inputField.text)) + end, + function() + if mainContainer.settingsContainer.inputField.text:match("%d+") then return true end + end + ) +end + +local function openFileWindow() + createInputTextBoxForSettingsWindow(localization.openFile, localization.pathToFile, + function() + loadFile(mainContainer.settingsContainer.inputField.text) + end, + function() + if fs.exists(mainContainer.settingsContainer.inputField.text) then return true end + end + ) +end + +local function saveFileAsWindow() + createInputTextBoxForSettingsWindow(localization.saveAs, localization.pathToFile, + function() + if unicode.len(mainContainer.settingsContainer.inputField.text or "") > 0 then + saveFile(mainContainer.settingsContainer.inputField.text) + mainContainer.leftTreeView:updateFileList() + mainContainer.leftTreeView.selectedItem = mainContainer.leftTreeView.workPath .. mainContainer.settingsContainer.inputField.text + + updateTitle() + mainContainer:draw() + buffer.draw() + end + end + ) +end + +local function saveFileWindow() + saveFile(mainContainer.leftTreeView.selectedItem) + mainContainer.leftTreeView:updateFileList() +end + +local function splitStringIntoLines(s) + s = removeWindowsLineEndings(removeTabs(s)) + + local lines, searchLineEndingFrom, maximumLineLength, lineEndingFoundAt, line = {}, 1, 0 + repeat + lineEndingFoundAt = string.unicodeFind(s, "\n", searchLineEndingFrom) + if lineEndingFoundAt then + line = unicode.sub(s, searchLineEndingFrom, lineEndingFoundAt - 1) + searchLineEndingFrom = lineEndingFoundAt + 1 + else + line = unicode.sub(s, searchLineEndingFrom, -1) + end + + table.insert(lines, line) + maximumLineLength = math.max(maximumLineLength, unicode.len(line)) + until not lineEndingFoundAt + + return lines, maximumLineLength +end + +local function downloadFileFromWeb() + createInputTextBoxForSettingsWindow(localization.getFromWeb, localization.url, + function() + local result, reason = web.request(mainContainer.settingsContainer.inputField.text) + if result then + newFile() + mainContainer.codeView.lines, mainContainer.codeView.maximumLineLength = splitStringIntoLines(result) + else + GUI.error("Failed to connect to URL: " .. tostring(reason)) + end + hideSettingsContainer() + end + ) +end + +------------------------------------------------------------------------------------------------------------------ + +local function getVariables(codePart) + local variables = {} + -- Сначала мы проверяем участок кода на наличие комментариев + if + not codePart:match("^%-%-") and + not codePart:match("^[\t%s]+%-%-") + then + -- Затем заменяем все строковые куски в участке кода на "ничего", чтобы наш "прекрасный" парсер не искал переменных в строках + codePart = codePart:gsub("\"[^\"]+\"", "") + -- Потом разбиваем код на отдельные буквенно-цифровые слова, не забыв точечку с двоеточием + for word in codePart:gmatch("[%a%d%.%:%_]+") do + -- Далее проверяем, не совпадает ли это слово с одним из луа-шаблонов, то бишь, не является ли оно частью синтаксиса + if + word ~= "local" and + word ~= "return" and + word ~= "while" and + word ~= "repeat" and + word ~= "until" and + word ~= "for" and + word ~= "in" and + word ~= "do" and + word ~= "if" and + word ~= "then" and + word ~= "else" and + word ~= "elseif" and + word ~= "end" and + word ~= "function" and + word ~= "true" and + word ~= "false" and + word ~= "nil" and + word ~= "not" and + word ~= "and" and + word ~= "or" and + -- Также проверяем, не число ли это в чистом виде + not word:match("^[%d%.]+$") and + not word:match("^0x%x+$") and + -- Или символ конкатенации, например + not word:match("^%.+$") + then + variables[word] = true + end + end + end + + return variables +end + +local function continue() + -- Готовим экран к запуску + local oldResolutionX, oldResolutionY = component.gpu.getResolution() + MineOSInterface.clearTerminal() + + -- Запускаем + _G.MineCodeIDEDebugInfo = nil + local coroutineResumeSuccess, coroutineResumeReason = coroutine.resume(scriptCoroutine) + + -- Анализируем результат запуска + if coroutineResumeSuccess then + if coroutine.status(scriptCoroutine) == "dead" then + MineOSInterface.waitForPressingAnyKey() + hideErrorContainer() + buffer.setResolution(oldResolutionX, oldResolutionY); mainContainer:draw(); buffer.draw(true) + else + -- Тест на пидора, мало ли у чувака в проге тоже есть yield + if _G.MineCodeIDEDebugInfo then + buffer.setResolution(oldResolutionX, oldResolutionY); mainContainer:draw(); buffer.draw(true) + gotoLine(_G.MineCodeIDEDebugInfo.line) + showBreakpointMessage(_G.MineCodeIDEDebugInfo.variables) + end + end + else + buffer.setResolution(oldResolutionX, oldResolutionY); mainContainer:draw(); buffer.draw(true) + showErrorContainer(debug.traceback(scriptCoroutine, coroutineResumeReason)) + end +end + +local function run() + hideErrorContainer() + + -- Инсертим брейкпоинты + if breakpointLines then + local offset = 0 + for i = 1, #breakpointLines do + local variables = getVariables(mainContainer.codeView.lines[breakpointLines[i] + offset]) + + local breakpointMessage = "_G.MineCodeIDEDebugInfo = {variables = {" + for variable in pairs(variables) do + breakpointMessage = breakpointMessage .. "[\"" .. variable .. "\"] = type(" .. variable .. ") == 'string' and '\"' .. " .. variable .. " .. '\"' or tostring(" .. variable .. "), " + end + breakpointMessage = breakpointMessage .. "}, line = " .. breakpointLines[i] .. "}; coroutine.yield()" + + table.insert(mainContainer.codeView.lines, breakpointLines[i] + offset, breakpointMessage) + offset = offset + 1 + end + end + + -- Лоадим кодыч + local loadSuccess, loadReason = load(table.concat(mainContainer.codeView.lines, "\n")) + + -- Чистим дерьмо вилочкой, чистим + if breakpointLines then + for i = 1, #breakpointLines do + table.remove(mainContainer.codeView.lines, breakpointLines[i]) + end + end + + -- Запускаем кодыч + if loadSuccess then + scriptCoroutine = coroutine.create(loadSuccess) + continue() + else + showErrorContainer(loadReason) + end +end + +local function deleteLine(line) + if #mainContainer.codeView.lines > 1 then + table.remove(mainContainer.codeView.lines, line) + setCursorPositionAndClearSelection(1, cursor.position.line) + + updateAutocompleteDatabaseFromFile() + end +end + +local function deleteSpecifiedData(fromSymbol, fromLine, toSymbol, toLine) + local upperLine = unicode.sub(mainContainer.codeView.lines[fromLine], 1, fromSymbol - 1) + local lowerLine = unicode.sub(mainContainer.codeView.lines[toLine], toSymbol + 1, -1) + for line = fromLine + 1, toLine do + table.remove(mainContainer.codeView.lines, fromLine + 1) + end + mainContainer.codeView.lines[fromLine] = upperLine .. lowerLine + setCursorPositionAndClearSelection(fromSymbol, fromLine) + + updateAutocompleteDatabaseFromFile() +end + +local function deleteSelectedData() + if mainContainer.codeView.selections[1] then + deleteSpecifiedData( + mainContainer.codeView.selections[1].from.symbol, + mainContainer.codeView.selections[1].from.line, + mainContainer.codeView.selections[1].to.symbol, + mainContainer.codeView.selections[1].to.line + ) + + clearSelection() + end +end + +local function copy() + if mainContainer.codeView.selections[1] then + if mainContainer.codeView.selections[1].to.line == mainContainer.codeView.selections[1].from.line then + clipboard = { unicode.sub(mainContainer.codeView.lines[mainContainer.codeView.selections[1].from.line], mainContainer.codeView.selections[1].from.symbol, mainContainer.codeView.selections[1].to.symbol) } + else + clipboard = { unicode.sub(mainContainer.codeView.lines[mainContainer.codeView.selections[1].from.line], mainContainer.codeView.selections[1].from.symbol, -1) } + for line = mainContainer.codeView.selections[1].from.line + 1, mainContainer.codeView.selections[1].to.line - 1 do + table.insert(clipboard, mainContainer.codeView.lines[line]) + end + table.insert(clipboard, unicode.sub(mainContainer.codeView.lines[mainContainer.codeView.selections[1].to.line], 1, mainContainer.codeView.selections[1].to.symbol)) + end + end +end + +local function cut() + if mainContainer.codeView.selections[1] then + copy() + deleteSelectedData() + end +end + +local function pasteSelectedAutocompletion() + local firstPart = unicode.sub(mainContainer.codeView.lines[cursor.position.line], 1, mainContainer.autocompleteWindow.currentWordStarting - 1) + local secondPart = unicode.sub(mainContainer.codeView.lines[cursor.position.line], mainContainer.autocompleteWindow.currentWordEnding + 1, -1) + mainContainer.codeView.lines[cursor.position.line] = firstPart .. mainContainer.autocompleteWindow.matches[mainContainer.autocompleteWindow.currentMatch][1] .. secondPart + setCursorPositionAndClearSelection(unicode.len(firstPart .. mainContainer.autocompleteWindow.matches[mainContainer.autocompleteWindow.currentMatch][1]) + 1, cursor.position.line) + hideAutocompleteWindow() +end + +local function paste(pasteLines) + if pasteLines then + if mainContainer.codeView.selections[1] then + deleteSelectedData() + end + + local firstPart = unicode.sub(mainContainer.codeView.lines[cursor.position.line], 1, cursor.position.symbol - 1) + local secondPart = unicode.sub(mainContainer.codeView.lines[cursor.position.line], cursor.position.symbol, -1) + + if #pasteLines == 1 then + mainContainer.codeView.lines[cursor.position.line] = firstPart .. pasteLines[1] .. secondPart + setCursorPositionAndClearSelection(cursor.position.symbol + unicode.len(pasteLines[1]), cursor.position.line) + else + mainContainer.codeView.lines[cursor.position.line] = firstPart .. pasteLines[1] + for pasteLine = #pasteLines - 1, 2, -1 do + table.insert(mainContainer.codeView.lines, cursor.position.line + 1, pasteLines[pasteLine]) + end + table.insert(mainContainer.codeView.lines, cursor.position.line + #pasteLines - 1, pasteLines[#pasteLines] .. secondPart) + setCursorPositionAndClearSelection(unicode.len(pasteLines[#pasteLines]) + 1, cursor.position.line + #pasteLines - 1) + end + + updateAutocompleteDatabaseFromFile() + end +end + +local function selectAndPasteColor() + local startColor = 0xFF0000 + if mainContainer.codeView.selections[1] and mainContainer.codeView.selections[1].from.line == mainContainer.codeView.selections[1].to.line then + startColor = tonumber(unicode.sub(mainContainer.codeView.lines[mainContainer.codeView.selections[1].from.line], mainContainer.codeView.selections[1].from.symbol, mainContainer.codeView.selections[1].to.symbol)) or startColor + end + + local selectedColor = GUI.palette(math.floor(mainContainer.width / 2 - 35), math.floor(mainContainer.height / 2 - 12), startColor):show() + if selectedColor then + paste({string.format("0x%06X", selectedColor)}) + end +end + +local function pasteRegularChar(unicodeByte, char) + if not keyboard.isControl(unicodeByte) then + paste({char}) + if char == " " then + updateAutocompleteDatabaseFromFile() + end + showAutocompleteWindow() + end +end + +local function pasteAutoBrackets(unicodeByte) + local char = unicode.char(unicodeByte) + local currentSymbol = unicode.sub(mainContainer.codeView.lines[cursor.position.line], cursor.position.symbol, cursor.position.symbol) + + -- Если у нас вообще врублен режим автоскобок, то чекаем их + if config.enableAutoBrackets then + -- Ситуация, когда курсор находится на закрывающей скобке, и нехуй ее еще раз вставлять + if possibleBrackets.closers[char] and currentSymbol == char then + deleteSelectedData() + setCursorPosition(cursor.position.symbol + 1, cursor.position.line) + -- Если нажата открывающая скобка + elseif possibleBrackets.openers[char] then + -- А вот тут мы берем в скобочки уже выделенный текст + if mainContainer.codeView.selections[1] then + local firstPart = unicode.sub(mainContainer.codeView.lines[mainContainer.codeView.selections[1].from.line], 1, mainContainer.codeView.selections[1].from.symbol - 1) + local secondPart = unicode.sub(mainContainer.codeView.lines[mainContainer.codeView.selections[1].from.line], mainContainer.codeView.selections[1].from.symbol, -1) + mainContainer.codeView.lines[mainContainer.codeView.selections[1].from.line] = firstPart .. char .. secondPart + mainContainer.codeView.selections[1].from.symbol = mainContainer.codeView.selections[1].from.symbol + 1 + + if mainContainer.codeView.selections[1].to.line == mainContainer.codeView.selections[1].from.line then + mainContainer.codeView.selections[1].to.symbol = mainContainer.codeView.selections[1].to.symbol + 1 + end + + firstPart = unicode.sub(mainContainer.codeView.lines[mainContainer.codeView.selections[1].to.line], 1, mainContainer.codeView.selections[1].to.symbol) + secondPart = unicode.sub(mainContainer.codeView.lines[mainContainer.codeView.selections[1].to.line], mainContainer.codeView.selections[1].to.symbol + 1, -1) + mainContainer.codeView.lines[mainContainer.codeView.selections[1].to.line] = firstPart .. possibleBrackets.openers[char] .. secondPart + cursor.position.symbol = cursor.position.symbol + 2 + -- А тут мы делаем двойную автоскобку, если можем + elseif possibleBrackets.openers[char] and not currentSymbol:match("[%a%d%_]") then + paste({char .. possibleBrackets.openers[char]}) + setCursorPosition(cursor.position.symbol - 1, cursor.position.line) + cursor.blinkState = false + -- Ну, и если нет ни выделений, ни можем ебануть автоскобочку по регулярке + else + pasteRegularChar(unicodeByte, char) + end + -- Если мы вообще на скобку не нажимали + else + pasteRegularChar(unicodeByte, char) + end + -- Если оффнуты афтоскобки + else + pasteRegularChar(unicodeByte, char) + end +end + +local function backspaceAutoBrackets() + local previousSymbol = unicode.sub(mainContainer.codeView.lines[cursor.position.line], cursor.position.symbol - 1, cursor.position.symbol - 1) + local currentSymbol = unicode.sub(mainContainer.codeView.lines[cursor.position.line], cursor.position.symbol, cursor.position.symbol) + if config.enableAutoBrackets and possibleBrackets.openers[previousSymbol] and possibleBrackets.openers[previousSymbol] == currentSymbol then + deleteSpecifiedData(cursor.position.symbol, cursor.position.line, cursor.position.symbol, cursor.position.line) + end +end + +local function delete() + if mainContainer.codeView.selections[1] then + deleteSelectedData() + else + if cursor.position.symbol < unicode.len(mainContainer.codeView.lines[cursor.position.line]) + 1 then + deleteSpecifiedData(cursor.position.symbol, cursor.position.line, cursor.position.symbol, cursor.position.line) + else + if cursor.position.line > 1 then + deleteSpecifiedData(unicode.len(mainContainer.codeView.lines[cursor.position.line]) + 1, cursor.position.line, 0, cursor.position.line + 1) + end + end + + -- updateAutocompleteDatabaseFromFile() + showAutocompleteWindow() + end +end + +local function backspace() + if mainContainer.codeView.selections[1] then + deleteSelectedData() + else + if cursor.position.symbol > 1 then + backspaceAutoBrackets() + deleteSpecifiedData(cursor.position.symbol - 1, cursor.position.line, cursor.position.symbol - 1, cursor.position.line) + else + if cursor.position.line > 1 then + deleteSpecifiedData(unicode.len(mainContainer.codeView.lines[cursor.position.line - 1]) + 1, cursor.position.line - 1, 0, cursor.position.line) + end + end + + -- updateAutocompleteDatabaseFromFile() + showAutocompleteWindow() + end +end + +local function enter() + local firstPart = unicode.sub(mainContainer.codeView.lines[cursor.position.line], 1, cursor.position.symbol - 1) + local secondPart = unicode.sub(mainContainer.codeView.lines[cursor.position.line], cursor.position.symbol, -1) + mainContainer.codeView.lines[cursor.position.line] = firstPart + table.insert(mainContainer.codeView.lines, cursor.position.line + 1, secondPart) + setCursorPositionAndClearSelection(1, cursor.position.line + 1) +end + +local function selectAll() + mainContainer.codeView.selections[1] = { + from = { + symbol = 1, line = 1 + }, + to = { + symbol = unicode.len(mainContainer.codeView.lines[#mainContainer.codeView.lines]), line = #mainContainer.codeView.lines + } + } +end + +local function isLineCommented(line) + if mainContainer.codeView.lines[line] == "" or mainContainer.codeView.lines[line]:match("%-%-%s?") then return true end +end + +local function commentLine(line) + mainContainer.codeView.lines[line] = "-- " .. mainContainer.codeView.lines[line] +end + +local function uncommentLine(line) + local countOfReplaces + mainContainer.codeView.lines[line], countOfReplaces = mainContainer.codeView.lines[line]:gsub("%-%-%s?", "", 1) + return countOfReplaces +end + +local function toggleComment() + if mainContainer.codeView.selections[1] then + local allLinesAreCommented = true + + for line = mainContainer.codeView.selections[1].from.line, mainContainer.codeView.selections[1].to.line do + if not isLineCommented(line) then + allLinesAreCommented = false + break + end + end + + for line = mainContainer.codeView.selections[1].from.line, mainContainer.codeView.selections[1].to.line do + if allLinesAreCommented then + uncommentLine(line) + else + commentLine(line) + end + end + + local modifyer = 3 + if allLinesAreCommented then modifyer = -modifyer end + setCursorPosition(cursor.position.symbol + modifyer, cursor.position.line) + mainContainer.codeView.selections[1].from.symbol, mainContainer.codeView.selections[1].to.symbol = mainContainer.codeView.selections[1].from.symbol + modifyer, mainContainer.codeView.selections[1].to.symbol + modifyer + else + if isLineCommented(cursor.position.line) then + if uncommentLine(cursor.position.line) > 0 then + setCursorPositionAndClearSelection(cursor.position.symbol - 3, cursor.position.line) + end + else + commentLine(cursor.position.line) + setCursorPositionAndClearSelection(cursor.position.symbol + 3, cursor.position.line) + end + end +end + +local function indentLine(line) + mainContainer.codeView.lines[line] = string.rep(" ", mainContainer.codeView.indentationWidth) .. mainContainer.codeView.lines[line] +end + +local function unindentLine(line) + mainContainer.codeView.lines[line], countOfReplaces = string.gsub(mainContainer.codeView.lines[line], "^" .. string.rep("%s", mainContainer.codeView.indentationWidth), "") + return countOfReplaces +end + +local function indentOrUnindent(isIndent) + if mainContainer.codeView.selections[1] then + local countOfReplacesInFirstLine, countOfReplacesInLastLine + + for line = mainContainer.codeView.selections[1].from.line, mainContainer.codeView.selections[1].to.line do + if isIndent then + indentLine(line) + else + local countOfReplaces = unindentLine(line) + if line == mainContainer.codeView.selections[1].from.line then + countOfReplacesInFirstLine = countOfReplaces + elseif line == mainContainer.codeView.selections[1].to.line then + countOfReplacesInLastLine = countOfReplaces + end + end + end + + if isIndent then + setCursorPosition(cursor.position.symbol + mainContainer.codeView.indentationWidth, cursor.position.line) + mainContainer.codeView.selections[1].from.symbol, mainContainer.codeView.selections[1].to.symbol = mainContainer.codeView.selections[1].from.symbol + mainContainer.codeView.indentationWidth, mainContainer.codeView.selections[1].to.symbol + mainContainer.codeView.indentationWidth + else + if countOfReplacesInFirstLine > 0 then + mainContainer.codeView.selections[1].from.symbol = mainContainer.codeView.selections[1].from.symbol - mainContainer.codeView.indentationWidth + if cursor.position.line == mainContainer.codeView.selections[1].from.line then + setCursorPosition(cursor.position.symbol - mainContainer.codeView.indentationWidth, cursor.position.line) + end + end + + if countOfReplacesInLastLine > 0 then + mainContainer.codeView.selections[1].to.symbol = mainContainer.codeView.selections[1].to.symbol - mainContainer.codeView.indentationWidth + if cursor.position.line == mainContainer.codeView.selections[1].to.line then + setCursorPosition(cursor.position.symbol - mainContainer.codeView.indentationWidth, cursor.position.line) + end + end + end + else + if isIndent then + indentLine(cursor.position.line) + setCursorPositionAndClearSelection(cursor.position.symbol + mainContainer.codeView.indentationWidth, cursor.position.line) + else + if unindentLine(cursor.position.line) > 0 then + setCursorPositionAndClearSelection(cursor.position.symbol - mainContainer.codeView.indentationWidth, cursor.position.line) + end + end + end +end + +local function updateRAMProgressBar() + if not mainContainer.topToolBar.hidden then + local totalMemory = computer.totalMemory() + mainContainer.RAMUsageProgressBar.value = math.ceil((totalMemory - computer.freeMemory()) / totalMemory * 100) + end +end + +local function find() + if not mainContainer.bottomToolBar.hidden and mainContainer.bottomToolBar.inputField.text ~= "" then + findStartFrom = findStartFrom + 1 + + for line = findStartFrom, #mainContainer.codeView.lines do + local whereToFind, whatToFind = mainContainer.codeView.lines[line], mainContainer.bottomToolBar.inputField.text + if not mainContainer.bottomToolBar.caseSensitiveButton.pressed then + whereToFind, whatToFind = unicode.lower(whereToFind), unicode.lower(whatToFind) + end + + local success, starting, ending = pcall(string.unicodeFind, whereToFind, whatToFind) + if success then + if starting then + mainContainer.codeView.selections[1] = { + from = {symbol = starting, line = line}, + to = {symbol = ending, line = line}, + color = 0xCC9200 + } + findStartFrom = line + gotoLine(line) + return + end + else + GUI.error("Wrong searching regex") + end + end + + findStartFrom = 0 + end +end + +local function findFromFirstDisplayedLine() + findStartFrom = mainContainer.codeView.fromLine + find() +end + +local function toggleBottomToolBar() + mainContainer.bottomToolBar.hidden = not mainContainer.bottomToolBar.hidden + mainContainer.toggleBottomToolBarButton.pressed = not mainContainer.bottomToolBar.hidden + calculateSizes() + + if not mainContainer.bottomToolBar.hidden then + mainContainer:draw() + findFromFirstDisplayedLine() + end +end + +local function toggleTopToolBar() + mainContainer.topToolBar.hidden = not mainContainer.topToolBar.hidden + mainContainer.toggleTopToolBarButton.pressed = not mainContainer.topToolBar.hidden + calculateSizes() +end + +local function createEditOrRightClickMenu(x, y) + local editOrRightClickMenu = GUI.contextMenu(x, y) + editOrRightClickMenu:addItem(localization.cut, not mainContainer.codeView.selections[1], "^X").onTouch = function() + cut() + end + editOrRightClickMenu:addItem(localization.copy, not mainContainer.codeView.selections[1], "^C").onTouch = function() + copy() + end + editOrRightClickMenu:addItem(localization.paste, not clipboard, "^V").onTouch = function() + paste(clipboard) + end + editOrRightClickMenu:addSeparator() + editOrRightClickMenu:addItem(localization.comment, false, "^/").onTouch = function() + toggleComment() + end + editOrRightClickMenu:addItem(localization.indent, false, "Tab").onTouch = function() + indentOrUnindent(true) + end + editOrRightClickMenu:addItem(localization.unindent, false, "⇧Tab").onTouch = function() + indentOrUnindent(false) + end + editOrRightClickMenu:addItem(localization.deleteLine, false, "^Del").onTouch = function() + deleteLine(cursor.position.line) + end + editOrRightClickMenu:addSeparator() + editOrRightClickMenu:addItem(localization.addBreakpoint, false, "F9").onTouch = function() + addBreakpoint() + mainContainer:draw() + buffer.draw() + end + editOrRightClickMenu:addItem(localization.clearBreakpoints, not breakpointLines, "^F9").onTouch = function() + clearBreakpoints() + end + editOrRightClickMenu:addSeparator() + editOrRightClickMenu:addItem(localization.selectAndPasteColor, false, "^⇧C").onTouch = function() + selectAndPasteColor() + end + editOrRightClickMenu:addItem(localization.selectWord).onTouch = function() + selectWord() + end + editOrRightClickMenu:addItem(localization.selectAll, false, "^A").onTouch = function() + selectAll() + end + editOrRightClickMenu:show() +end + +local function tick() + updateTitle() + updateRAMProgressBar() + mainContainer:draw() + + if cursor.blinkState and mainContainer.settingsContainer.hidden then + local x, y = convertTextPositionToScreenCoordinates(cursor.position.symbol, cursor.position.line) + if + x >= mainContainer.codeView.codeAreaPosition + 1 and + y >= mainContainer.codeView.y and + x <= mainContainer.codeView.codeAreaPosition + mainContainer.codeView.codeAreaWidth - 2 and + y <= mainContainer.codeView.y + mainContainer.codeView.height - 2 + then + buffer.text(x, y, config.cursorColor, config.cursorSymbol) + end + end + + buffer.draw() +end + +local function createMainContainer() + mainContainer = GUI.fullScreenContainer() + + mainContainer.codeView = mainContainer:addChild(GUI.codeView(1, 1, 1, 1, {""}, 1, 1, 1, {}, {}, config.highlightLuaSyntax, 2)) + mainContainer.codeView.scrollBars.vertical.onTouch = function() + mainContainer.codeView.fromLine = mainContainer.codeView.scrollBars.vertical.value + end + mainContainer.codeView.scrollBars.horizontal.onTouch = function() + mainContainer.codeView.fromSymbol = mainContainer.codeView.scrollBars.horizontal.value + end + + mainContainer.topMenu = mainContainer:addChild(GUI.menu(1, 1, 1, colors.topMenu.backgroundColor, colors.topMenu.textColor, colors.topMenu.backgroundPressedColor, colors.topMenu.textPressedColor)) + + local item1 = mainContainer.topMenu:addItem("MineCode", 0x0) + item1.onTouch = function() + local menu = GUI.contextMenu(item1.x, item1.y + 1) + menu:addItem(localization.about).onTouch = function() + mainContainer.settingsContainer.hidden = false + local y = math.floor(mainContainer.settingsContainer.height / 2 - #about / 2) + mainContainer.settingsContainer:addChild(GUI.textBox(1, y, mainContainer.settingsContainer.width, #about, nil, 0xEEEEEE, about, 1)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + end + menu:addItem(localization.quit, false, "^W").onTouch = function() + mainContainer:stopEventHandling() + end + menu:show() + end + + local item2 = mainContainer.topMenu:addItem(localization.file) + item2.onTouch = function() + local menu = GUI.contextMenu(item2.x, item2.y + 1) + menu:addItem(localization.new, false, "^N").onTouch = function() + newFile() + mainContainer:draw() + buffer.draw() + end + menu:addItem(localization.open, false, "^O").onTouch = function() + openFileWindow() + end + if component.isAvailable("internet") then + menu:addItem(localization.getFromWeb, false, "^U").onTouch = function() + downloadFileFromWeb() + end + end + menu:addSeparator() + menu:addItem(localization.save, not mainContainer.leftTreeView.selectedItem, "^S").onTouch = function() + saveFileWindow() + end + menu:addItem(localization.saveAs, false, "^⇧S").onTouch = function() + saveFileAsWindow() + end + menu:show() + end + + local item3 = mainContainer.topMenu:addItem(localization.edit) + item3.onTouch = function() + createEditOrRightClickMenu(item3.x, item3.y + 1) + end + + local item4 = mainContainer.topMenu:addItem(localization.properties) + item4.onTouch = function() + local menu = GUI.contextMenu(item4.x, item4.y + 1) + menu:addItem(localization.colorScheme).onTouch = function() + mainContainer.settingsContainer.hidden = false + + local colorSelectorsCount, colorSelectorCountX = 0, 4; for key in pairs(config.syntaxColorScheme) do colorSelectorsCount = colorSelectorsCount + 1 end + local colorSelectorCountY = math.ceil(colorSelectorsCount / colorSelectorCountX) + local colorSelectorWidth, colorSelectorHeight, colorSelectorSpaceX, colorSelectorSpaceY = math.floor(mainContainer.settingsContainer.width / colorSelectorCountX * 0.8), 3, 2, 1 + + local startX, y = math.floor(mainContainer.settingsContainer.width / 2 - (colorSelectorCountX * (colorSelectorWidth + colorSelectorSpaceX) - colorSelectorSpaceX) / 2), math.floor(mainContainer.settingsContainer.height / 2 - (colorSelectorCountY * (colorSelectorHeight + colorSelectorSpaceY) - colorSelectorSpaceY + 3) / 2) + mainContainer.settingsContainer:addChild(GUI.label(1, y, mainContainer.settingsContainer.width, 1, 0xFFFFFF, localization.colorScheme)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 3 + local x, counter = startX, 1 + + local colors = {} + for key in pairs(config.syntaxColorScheme) do + table.insert(colors, {key}) + end + + aplhabeticalSort(colors) + + for i = 1, #colors do + local colorSelector = mainContainer.settingsContainer:addChild(GUI.colorSelector(x, y, colorSelectorWidth, colorSelectorHeight, config.syntaxColorScheme[colors[i][1]], colors[i][1])) + colorSelector.onTouch = function() + config.syntaxColorScheme[colors[i][1]] = colorSelector.color + syntax.colorScheme = config.syntaxColorScheme + saveConfig() + end + + x, counter = x + colorSelectorWidth + colorSelectorSpaceX, counter + 1 + if counter > colorSelectorCountX then + x, y, counter = startX, y + colorSelectorHeight + colorSelectorSpaceY, 1 + end + end + end + menu:addItem(localization.cursorProperties).onTouch = function() + mainContainer.settingsContainer.hidden = false + + local elementWidth = math.floor(mainContainer.width * 0.3) + local x, y = math.floor(mainContainer.width / 2 - elementWidth / 2), math.floor(mainContainer.height / 2) - 7 + mainContainer.settingsContainer:addChild(GUI.label(1, y, mainContainer.settingsContainer.width, 1, 0xFFFFFF, localization.cursorProperties)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 3 + local inputField = mainContainer.settingsContainer:addChild(GUI.input(x, y, elementWidth, 3, 0xCCCCCC, 0x777777, 0x777777, 0xCCCCCC, 0x2D2D2D, config.cursorSymbol, localization.cursorSymbol)); y = y + 5 + inputField.validator = function(text) + if unicode.len(text) == 1 then return true end + end + inputField.onInputFinished = function() + config.cursorSymbol = inputField.text; saveConfig() + end + local colorSelector = mainContainer.settingsContainer:addChild(GUI.colorSelector(x, y, elementWidth, 3, config.cursorColor, localization.cursorColor)); y = y + 5 + colorSelector.onTouch = function() + config.cursorColor = colorSelector.color; saveConfig() + end + local horizontalSlider = mainContainer.settingsContainer:addChild(GUI.slider(x, y, elementWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xDDDDDD, 1, 1000, config.cursorBlinkDelay * 1000, false, localization.cursorBlinkDelay .. ": ", " ms")) + horizontalSlider.onValueChanged = function() + config.cursorBlinkDelay = horizontalSlider.value / 1000; saveConfig() + end + end + + if mainContainer.topToolBar.hidden then + menu:addItem(localization.toggleTopToolBar).onTouch = function() + toggleTopToolBar() + end + end + menu:addSeparator() + menu:addItem(config.enableAutoBrackets and localization.disableAutoBrackets or localization.enableAutoBrackets, false, "^]").onTouch = function() + config.enableAutoBrackets = not config.enableAutoBrackets + saveConfig() + end + menu:addItem(config.enableAutocompletion and localization.disableAutocompletion or localization.enableAutocompletion, false, "^I").onTouch = function() + toggleEnableAutocompleteDatabase() + end + menu:addSeparator() + menu:addItem(localization.changeResolution, false, "^R").onTouch = function() + changeResolutionWindow() + end + menu:show() + end + + local item5 = mainContainer.topMenu:addItem(localization.gotoCyka) + item5.onTouch = function() + local menu = GUI.contextMenu(item5.x, item5.y + 1) + menu:addItem(localization.pageUp, false, "PgUp").onTouch = function() + pageUp() + end + menu:addItem(localization.pageDown, false, "PgDn").onTouch = function() + pageDown() + end + menu:addItem(localization.gotoStart, false, "Home").onTouch = function() + setCursorPositionToHome() + end + menu:addItem(localization.gotoEnd, false, "End").onTouch = function() + setCursorPositionToEnd() + end + menu:addSeparator() + menu:addItem(localization.gotoLine, false, "^L").onTouch = function() + gotoLineWindow() + end + menu:show() + end + + mainContainer.topToolBar = mainContainer:addChild(GUI.container(1, 2, 1, 3)) + mainContainer.topToolBar.backgroundPanel = mainContainer.topToolBar:addChild(GUI.panel(1, 1, 1, 3, colors.topToolBar)) + mainContainer.titleTextBox = mainContainer.topToolBar:addChild(GUI.textBox(1, 1, 1, 3, 0x0, 0x0, {}, 1):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) + local titleTextBoxOldDraw = mainContainer.titleTextBox.draw + mainContainer.titleTextBox.draw = function(titleTextBox) + titleTextBoxOldDraw(titleTextBox) + local sidesColor = mainContainer.errorContainer.hidden and colors.title.default.sides or colors.title.onError.sides + buffer.square(titleTextBox.x, titleTextBox.y, 1, titleTextBox.height, sidesColor, titleTextBox.colors.text, " ") + buffer.square(titleTextBox.x + titleTextBox.width - 1, titleTextBox.y, 1, titleTextBox.height, sidesColor, titleTextBox.colors.text, " ") + end + + mainContainer.RAMUsageProgressBar = mainContainer.topToolBar:addChild(GUI.progressBar(1, 2, 1, 0x777777, 0xBBBBBB, 0xAAAAAA, 50, true, true, "RAM: ", "%")) + + --☯◌☺ + mainContainer.addBreakpointButton = mainContainer.topToolBar:addChild(GUI.adaptiveButton(1, 1, 3, 1, 0x878787, 0xEEEEEE, 0xCCCCCC, 0x444444, "x")) + mainContainer.addBreakpointButton.onTouch = function() + addBreakpoint() + mainContainer:draw() + buffer.draw() + end + + mainContainer.toggleSyntaxHighlightingButton = mainContainer.topToolBar:addChild(GUI.adaptiveButton(1, 1, 3, 1, 0xCCCCCC, 0x444444, 0x696969, 0xEEEEEE, "◌")) + mainContainer.toggleSyntaxHighlightingButton.switchMode, mainContainer.toggleSyntaxHighlightingButton.pressed = true, true + mainContainer.toggleSyntaxHighlightingButton.onTouch = function() + mainContainer.codeView.highlightLuaSyntax = not mainContainer.codeView.highlightLuaSyntax + config.highlightLuaSyntax = mainContainer.codeView.highlightLuaSyntax + saveConfig() + mainContainer:draw() + buffer.draw() + end + + mainContainer.runButton = mainContainer.topToolBar:addChild(GUI.adaptiveButton(1, 1, 3, 1, 0x4B4B4B, 0xEEEEEE, 0xCCCCCC, 0x444444, "▷")) + mainContainer.runButton.onTouch = function() + run() + end + + mainContainer.toggleLeftToolBarButton = mainContainer.topToolBar:addChild(GUI.adaptiveButton(1, 1, 3, 1, 0xCCCCCC, 0x444444, 0x4B4B4B, 0xEEEEEE, "⇦")) + mainContainer.toggleLeftToolBarButton.switchMode, mainContainer.toggleLeftToolBarButton.pressed = true, true + mainContainer.toggleLeftToolBarButton.onTouch = function() + mainContainer.leftTreeView.hidden = not mainContainer.toggleLeftToolBarButton.pressed + mainContainer.leftTreeViewResizer.hidden = mainContainer.leftTreeView.hidden + calculateSizes() + mainContainer:draw() + buffer.draw() + end + + mainContainer.toggleBottomToolBarButton = mainContainer.topToolBar:addChild(GUI.adaptiveButton(1, 1, 3, 1, 0xCCCCCC, 0x444444, 0x696969, 0xEEEEEE, "⇩")) + mainContainer.toggleBottomToolBarButton.switchMode, mainContainer.toggleBottomToolBarButton.pressed = true, false + mainContainer.toggleBottomToolBarButton.onTouch = function() + mainContainer.bottomToolBar.hidden = not mainContainer.toggleBottomToolBarButton.pressed + calculateSizes() + mainContainer:draw() + buffer.draw() + end + + mainContainer.toggleTopToolBarButton = mainContainer.topToolBar:addChild(GUI.adaptiveButton(1, 1, 3, 1, 0xCCCCCC, 0x444444, 0x878787, 0xEEEEEE, "⇧")) + mainContainer.toggleTopToolBarButton.switchMode, mainContainer.toggleTopToolBarButton.pressed = true, true + mainContainer.toggleTopToolBarButton.onTouch = function() + mainContainer.topToolBar.hidden = not mainContainer.toggleTopToolBarButton.pressed + calculateSizes() + mainContainer:draw() + buffer.draw() + end + + mainContainer.bottomToolBar = mainContainer:addChild(GUI.container(1, 1, 1, 3)) + mainContainer.bottomToolBar.caseSensitiveButton = mainContainer.bottomToolBar:addChild(GUI.adaptiveButton(1, 1, 2, 1, 0x3C3C3C, 0xEEEEEE, 0xBBBBBB, 0x2D2D2D, "Aa")) + mainContainer.bottomToolBar.caseSensitiveButton.switchMode = true + mainContainer.bottomToolBar.onTouch = function() + find() + end + mainContainer.bottomToolBar.inputField = mainContainer.bottomToolBar:addChild(GUI.input(7, 1, 10, 3, 0xCCCCCC, 0x999999, 0x999999, 0xCCCCCC, 0x2D2D2D, "", localization.findSomeShit)) + mainContainer.bottomToolBar.inputField.onInputFinished = function() + findFromFirstDisplayedLine() + end + mainContainer.bottomToolBar.findButton = mainContainer.bottomToolBar:addChild(GUI.adaptiveButton(1, 1, 3, 1, 0x3C3C3C, 0xEEEEEE, 0xBBBBBB, 0x2D2D2D, localization.find)) + mainContainer.bottomToolBar.findButton.onTouch = function() + find() + end + mainContainer.bottomToolBar.hidden = true + + mainContainer.leftTreeView = mainContainer:addChild(GUI.filesystemTree(1, 1, config.leftTreeViewWidth, 1, 0xCCCCCC, 0x3C3C3C, 0x3C3C3C, 0x999999, 0x3C3C3C, 0xE1E1E1, 0xBBBBBB, 0xAAAAAA, 0xBBBBBB, 0x444444, GUI.filesystemModes.both, GUI.filesystemModes.file)) + mainContainer.leftTreeView.onItemSelected = function(path) + loadFile(path) + + updateTitle() + mainContainer:draw() + buffer.draw() + end + mainContainer.leftTreeView:updateFileList() + mainContainer.leftTreeViewResizer = mainContainer:addChild(GUI.resizer(1, 1, 3, 5, 0x888888, 0x0)) + mainContainer.leftTreeViewResizer.onResize = function(mainContainer, object, eventData, dragWidth, dragHeight) + mainContainer.leftTreeView.width = mainContainer.leftTreeView.width + dragWidth + calculateSizes() + end + + mainContainer.leftTreeViewResizer.onResizeFinished = function() + config.leftTreeViewWidth = mainContainer.leftTreeView.width + saveConfig() + end + + mainContainer.errorContainer = mainContainer:addChild(GUI.container(1, 1, 1, 1)) + mainContainer.errorContainer.backgroundPanel = mainContainer.errorContainer:addChild(GUI.panel(1, 1, 1, 1, 0xFFFFFF, 0.3)) + mainContainer.errorContainer.errorTextBox = mainContainer.errorContainer:addChild(GUI.textBox(3, 2, 1, 1, nil, 0x4B4B4B, {}, 1)) + mainContainer.errorContainer.breakpointExitButton = mainContainer.errorContainer:addChild(GUI.button(1, 1, 1, 1, 0x3C3C3C, 0xCCCCCC, 0x2D2D2D, 0x888888, localization.finishDebug)) + mainContainer.errorContainer.breakpointContinueButton = mainContainer.errorContainer:addChild(GUI.button(1, 1, 1, 1, 0x444444, 0xCCCCCC, 0x2D2D2D, 0x888888, localization.continueDebug)) + mainContainer.errorContainer.breakpointExitButton.onTouch = hideErrorContainer + mainContainer.errorContainer.breakpointContinueButton.onTouch = continue + hideErrorContainer() + + mainContainer.settingsContainer = mainContainer:addChild(GUI.container(1, 1, 1, 1)) + mainContainer.settingsContainer.backgroundPanel = mainContainer.settingsContainer:addChild(GUI.panel(1, 1, mainContainer.settingsContainer.width, mainContainer.settingsContainer.height, 0x0, 0.3)) + mainContainer.settingsContainer.backgroundPanel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + hideSettingsContainer() + end + end + mainContainer.settingsContainer.hidden = true + + mainContainer.autocompleteWindow = mainContainer:addChild(GUI.object(1, 1, 40, 1)) + mainContainer.autocompleteWindow.maximumHeight = 8 + mainContainer.autocompleteWindow.matches = {} + mainContainer.autocompleteWindow.fromMatch = 1 + mainContainer.autocompleteWindow.currentMatch = 1 + mainContainer.autocompleteWindow.hidden = true + mainContainer.autocompleteWindow.draw = function(object) + mainContainer.autocompleteWindow.x, mainContainer.autocompleteWindow.y = convertTextPositionToScreenCoordinates(mainContainer.autocompleteWindow.currentWordStarting, cursor.position.line) + mainContainer.autocompleteWindow.x, mainContainer.autocompleteWindow.y = mainContainer.autocompleteWindow.x, mainContainer.autocompleteWindow.y + 1 + + object.height = object.maximumHeight + if object.height > #object.matches then object.height = #object.matches end + + buffer.square(object.x, object.y, object.width, object.height, 0xFFFFFF, 0x0, " ") + + local y = object.y + for i = object.fromMatch, #object.matches do + local firstColor, secondColor = 0x3C3C3C, 0x999999 + + if i == object.currentMatch then + buffer.square(object.x, y, object.width, 1, 0x2D2D2D, 0xEEEEEE, " ") + firstColor, secondColor = 0xEEEEEE, 0x999999 + end + + buffer.text(object.x + 1, y, secondColor, unicode.sub(object.matches[i][1], 1, object.width - 2)) + buffer.text(object.x + 1, y, firstColor, unicode.sub(object.matches[i][2], 1, object.width - 2)) + + y = y + 1 + if y > object.y + object.height - 1 then break end + end + + if object.height < #object.matches then + GUI.scrollBar(object.x + object.width - 1, object.y, 1, object.height, 0x444444, 0x00DBFF, 1, #object.matches, object.currentMatch, object.height, 1, true):draw() + end + end + + mainContainer.codeView.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + if eventData[5] == 1 then + createEditOrRightClickMenu(eventData[3], eventData[4]) + else + setCursorPositionAndClearSelection(convertScreenCoordinatesToTextPosition(eventData[3], eventData[4])) + end + + cursor.blinkState = true + tick() + elseif eventData[1] == "double_touch" then + cursor.blinkState = true + selectWord() + + mainContainer:draw() + buffer.draw() + elseif eventData[1] == "drag" then + if eventData[5] ~= 1 then + mainContainer.codeView.selections[1] = mainContainer.codeView.selections[1] or {from = {}, to = {}} + mainContainer.codeView.selections[1].from.symbol, mainContainer.codeView.selections[1].from.line = cursor.position.symbol, cursor.position.line + mainContainer.codeView.selections[1].to.symbol, mainContainer.codeView.selections[1].to.line = fixCursorPosition(convertScreenCoordinatesToTextPosition(eventData[3], eventData[4])) + + if mainContainer.codeView.selections[1].from.line > mainContainer.codeView.selections[1].to.line then + mainContainer.codeView.selections[1].from.line, mainContainer.codeView.selections[1].to.line = mainContainer.codeView.selections[1].to.line, mainContainer.codeView.selections[1].from.line + mainContainer.codeView.selections[1].from.symbol, mainContainer.codeView.selections[1].to.symbol = mainContainer.codeView.selections[1].to.symbol, mainContainer.codeView.selections[1].from.symbol + elseif mainContainer.codeView.selections[1].from.line == mainContainer.codeView.selections[1].to.line then + if mainContainer.codeView.selections[1].from.symbol > mainContainer.codeView.selections[1].to.symbol then + mainContainer.codeView.selections[1].from.symbol, mainContainer.codeView.selections[1].to.symbol = mainContainer.codeView.selections[1].to.symbol, mainContainer.codeView.selections[1].from.symbol + end + end + end + + cursor.blinkState = true + tick() + elseif eventData[1] == "key_down" then + -- Ctrl or CMD + if keyboard.isKeyDown(29) or keyboard.isKeyDown(219) then + -- Slash + if eventData[4] == 53 then + toggleComment() + -- ] + elseif eventData[4] == 27 then + config.enableAutoBrackets = not config.enableAutoBrackets + saveConfig() + -- I + elseif eventData[4] == 23 then + toggleEnableAutocompleteDatabase() + -- A + elseif eventData[4] == 30 then + selectAll() + -- C + elseif eventData[4] == 46 then + -- Shift + if keyboard.isKeyDown(42) then + selectAndPasteColor() + else + copy() + end + -- V + elseif eventData[4] == 47 then + paste(clipboard) + -- X + elseif eventData[4] == 45 then + cut() + -- W + elseif eventData[4] == 17 then + mainContainer:stopEventHandling() + -- N + elseif eventData[4] == 49 then + newFile() + -- O + elseif eventData[4] == 24 then + openFileWindow() + -- U + elseif eventData[4] == 22 and component.isAvailable("internet") then + downloadFileFromWeb() + -- S + elseif eventData[4] == 31 then + -- Shift + if mainContainer.leftTreeView.selectedItem and not keyboard.isKeyDown(42) then + saveFileWindow() + else + saveFileAsWindow() + end + -- F + elseif eventData[4] == 33 then + toggleBottomToolBar() + -- G + elseif eventData[4] == 34 then + find() + -- L + elseif eventData[4] == 38 then + gotoLineWindow() + -- Backspace + elseif eventData[4] == 14 then + deleteLine(cursor.position.line) + -- Delete + elseif eventData[4] == 211 then + deleteLine(cursor.position.line) + -- R + elseif eventData[4] == 19 then + changeResolutionWindow() + end + -- Arrows up, down, left, right + elseif eventData[4] == 200 then + moveCursor(0, -1) + elseif eventData[4] == 208 then + moveCursor(0, 1) + elseif eventData[4] == 203 then + moveCursor(-1, 0) + elseif eventData[4] == 205 then + moveCursor(1, 0) + -- Backspace + elseif eventData[4] == 14 then + backspace() + -- Tab + elseif eventData[4] == 15 then + if keyboard.isKeyDown(42) then + indentOrUnindent(false) + else + indentOrUnindent(true) + end + -- Enter + elseif eventData[4] == 28 then + if mainContainer.autocompleteWindow.hidden then + enter() + else + pasteSelectedAutocompletion() + end + -- F5 + elseif eventData[4] == 63 then + run() + -- F9 + elseif eventData[4] == 67 then + -- Shift + if keyboard.isKeyDown(42) then + clearBreakpoints() + else + addBreakpoint() + end + -- Home + elseif eventData[4] == 199 then + setCursorPositionToHome() + -- End + elseif eventData[4] == 207 then + setCursorPositionToEnd() + -- Page Up + elseif eventData[4] == 201 then + pageUp() + -- Page Down + elseif eventData[4] == 209 then + pageDown() + -- Delete + elseif eventData[4] == 211 then + delete() + else + pasteAutoBrackets(eventData[3]) + end + + cursor.blinkState = true + tick() + elseif eventData[1] == "scroll" then + scroll(eventData[5], config.scrollSpeed) + tick() + elseif eventData[1] == "clipboard" then + paste(splitStringIntoLines(eventData[3])) + tick() + elseif not eventData[1] then + cursor.blinkState = not cursor.blinkState + tick() + end + end +end + +---------------------------------------------------- RUSH B! ---------------------------------------------------- + +loadConfig() +createMainContainer() +changeResolution(config.screenResolution.width, config.screenResolution.height) +updateTitle() +updateRAMProgressBar() +mainContainer:draw() + +if args[1] and fs.exists(args[1]) then + loadFile(args[1]) +else + newFile() +end + +mainContainer:draw() +buffer.draw() +mainContainer:startEventHandling(config.cursorBlinkDelay) + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/MineCode IDE.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/MineCode IDE.app/Resources/About/Russian.txt new file mode 100755 index 00000000..8d91824a --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/MineCode IDE.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +MineCode IDE - это мощный инстурмент для разработки приложений с богатым функционалом: от подсветки синтаксиса Lua, выделения текста и работы с буфером обмена до поддержки пользовательских цветовых схем. Удобный файловый менеджер также прилагается. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/MineCode IDE.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/MineCode IDE.app/Resources/Icon.pic new file mode 100755 index 00000000..f913804b Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/MineCode IDE.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/MineCode IDE.app/Resources/Localization/English.lang b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/MineCode IDE.app/Resources/Localization/English.lang new file mode 100755 index 00000000..cbe064d8 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/MineCode IDE.app/Resources/Localization/English.lang @@ -0,0 +1,61 @@ +{ + addBreakpoint = "Add breakpoint", + clearBreakpoints = "Clear breakpoints", + finishDebug = "Stop", + continueDebug = "Continue", + gotoLine = "Goto line", + lineNumber = "Line", + enableAutocompletion = "Enable autocompletion", + disableAutocompletion = "Disable autocompletion", + selectAndPasteColor = "Select and paste color", + enableAutoBrackets = "Enable autobrackets", + disableAutoBrackets = "Disable autobrackets", + url = "http://example.com/something.lua", + getFromWeb = "Download from URL", + debugging = "Debugger on line ", + runtimeError = "Runtime error", + variablesNotAvailable = "No variables found", + variables = "Values of the variables:", + changeResolution = "Change screen resolution", + pathToFile = "Path to file", + selectWord = "Select current word", + gotoCyka = "Goto", + gotoEnd = "Scroll to end", + gotoStart = "Scroll to start", + pageDown = "Page down", + pageUp = "Page up", + deleteLine = "Delete current line", + cursorProperties = "Cursor properties", + cursorSymbol = "Symbol", + cursorColor = "Color", + cursorBlinkDelay = "Blink delay", + selection = "Selection: ", + none = "none", + properties = "Properties", + about = "About", + quit = "Quit from MineCode", + line = " line, ", + symbol = " symbol", + lines = " lines, ", + symbols = " symbols", + file = "File", + cursor = "Cursor: ", + new = "New", + open = "Open", + openFile = "Open file", + save = "Save", + saveAs = "Save as", + colorScheme = "Color scheme", + color = "Color", + toggleTopToolBar = "Show top toolbar", + find = "Find", + findSomeShit = "Let's find some shit…", + cut = "Cut", + copy = "Copy", + paste = "Paste", + selectAll = "Select all", + edit = "Edit", + comment = "Toggle comment", + indent = "Indent", + unindent = "Unindent", +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/MineCode IDE.app/Resources/Localization/Russian.lang b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/MineCode IDE.app/Resources/Localization/Russian.lang new file mode 100755 index 00000000..e5a44fb2 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/MineCode IDE.app/Resources/Localization/Russian.lang @@ -0,0 +1,61 @@ +{ + addBreakpoint = "Точка останова", + clearBreakpoints = "Удалить точки останова", + finishDebug = "Стоп", + continueDebug = "Продолжить", + gotoLine = "Перейти к строке", + lineNumber = "Номер строки", + enableAutocompletion = "Включить автодополнение", + disableAutocompletion = "Отключить автодополнение", + selectAndPasteColor = "Выбрать и вставить цвет", + enableAutoBrackets = "Включить авто-скобки", + disableAutoBrackets = "Отключить авто-скобки", + url = "http://example.com/something.lua", + getFromWeb = "Загрузить по URL", + debugging = "Отладчик на строке ", + runtimeError = "Ошибка при выполнении программы", + variablesNotAvailable = "Не найдено возможных переменных", + variables = "Значения переменных:", + changeResolution = "Изменить разрешение экрана", + pathToFile = "Путь к файлу", + selectWord = "Выделить текущее слово", + gotoCyka = "Переход", + gotoEnd = "В конец", + gotoStart = "В начало", + pageDown = "На страницу ниже", + pageUp = "На страницу выше", + deleteLine = "Удалить текущую строку", + cursorProperties = "Параметры курсора", + cursorSymbol = "Символ", + cursorColor = "Цвет", + cursorBlinkDelay = "Время мигания", + selection = "Выделение: ", + none = "нет", + properties = "Настройки", + about = "О программе", + quit = "Выйти из MineCode", + line = " строка, ", + symbol = " символ", + lines = " строк, ", + symbols = " символов", + file = "Файл", + cursor = "Курсор: ", + new = "Новый", + open = "Открыть", + openFile = "Открыть файл", + save = "Сохранить", + saveAs = "Сохранить как", + colorScheme = "Цветовая схема", + color = "Цвет", + toggleTopToolBar = "Показать панель инстурментов", + find = "Найти", + findSomeShit = "Давай найдем какую-нибудь хуйню…", + cut = "Вырезать", + copy = "Копировать", + paste = "Вставить", + selectAll = "Выделить все", + edit = "Редактировать", + comment = "Комментировать", + indent = "Табулировать", + unindent = "Детабулировать", +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Palette.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Palette.app/Main.lua new file mode 100755 index 00000000..22ef415b --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Palette.app/Main.lua @@ -0,0 +1,15 @@ + +local MineOSInterface = require("MineOSInterface") + +local mainContainer, window = MineOSInterface.addWindow( + MineOSInterface.windowFromContainer( + require("GUI").palette(1, 1, 0x9900FF) + ) +) + +window.OKButton.onTouch = function() + window:close() + MineOSInterface.OSDraw() +end + +window.cancelButton.onTouch = window.OKButton.onTouch \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Palette.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Palette.app/Resources/Icon.pic new file mode 100755 index 00000000..bb47d9e3 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Palette.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Photoshop.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Photoshop.app/Main.lua new file mode 100755 index 00000000..345df3c0 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Photoshop.app/Main.lua @@ -0,0 +1,1381 @@ + +------------------------------------------------ Информешйн, епта -------------------------------------------------------------- + +local photoshopVersion = "Photoshop v6.6" + +------------------------------------------------ Библиотеки -------------------------------------------------------------- + +local ecs = require("ECSAPI") +local MineOSCore = require("MineOSCore") +local GUI = require("GUI") +local fs = require("filesystem") +local unicode = require("unicode") +local image = require("image") +local component = require("component") +local keyboard = require("keyboard") +local buffer = require("doubleBuffering") +local color = require("color") +local event = require("event") + +------------------------------------------------ Переменные -------------------------------------------------------------- + +--Инициализируем библиотеку двойного буфера +buffer.flush() + +--Массив локалиации +local localization = MineOSCore.getCurrentApplicationLocalization() + +--Массив инфы о выделении +local selection + +--Получаем аргументы программы +local args = {...} + +--Массив главного изображения +local masterPixels = { + 0, + 0, +} + +--Базовая цветовая схема программы +local colors = { + leftToolbar = 0x3c3c3c, + leftToolbarButton = 0x2d2d2d, + leftToolbarButtonText = 0xeeeeee, + topToolbar = 0x4b4b4b, + drawingArea = 0x1e1e1e, + console = 0x2d2d2d, + consoleText = 0x999999, + transparencyWhite = 0xffffff, + transparencyGray = 0xcccccc, + transparencyVariable = 0xffffff, + oldBackground = 0x0, + oldForeground = 0x0, + topMenu = 0xeeeeee, + topMenuText = 0x262626, +} + +--Различные константы и размеры тулбаров и кликабельных зон +local sizes = { + widthOfLeftBar = 6, +} +sizes.xStartOfDrawingArea = sizes.widthOfLeftBar + 1 +sizes.xEndOfDrawingArea = buffer.getWidth() +sizes.yStartOfDrawingArea = 2 +sizes.yEndOfDrawingArea = buffer.getHeight() - 1 +sizes.widthOfDrawingArea = sizes.xEndOfDrawingArea - sizes.xStartOfDrawingArea + 1 +sizes.heightOfDrawingArea = sizes.yEndOfDrawingArea - sizes.yStartOfDrawingArea + 1 +sizes.heightOfLeftBar = buffer.getHeight() - 1 +sizes.sizeOfPixelData = 4 + +--Для изображения +local function reCalculateImageSizes(x, y) + sizes.xStartOfImage = x or 9 + sizes.yStartOfImage = y or 6 + sizes.xEndOfImage = sizes.xStartOfImage + image.getWidth(masterPixels) - 1 + sizes.yEndOfImage = sizes.yStartOfImage + image.getHeight(masterPixels) - 1 +end +reCalculateImageSizes() + +--Инструменты +local instruments = { + "M", + "B", + "E", + "F", + "T", + "S", +} +sizes.heightOfInstrument = 3 +sizes.yStartOfInstruments = 2 +local currentInstrument = 2 +local currentBackground = 0x000000 +local currentForeground = 0xFFFFFF +local currentAlpha = 0x00 +local currentSymbol = " " +local currentBrushSize = 1 +local savePath +local currentShape +local currentPolygonCountOfEdges +local showTransparencyGrid = true + +------------------------------------------------ Функции отрисовки -------------------------------------------------------------- + +--Объекты для тача +local obj = {} +local function newObj(class, name, ...) + obj[class] = obj[class] or {} + obj[class][name] = {...} +end + +--Функция-сваппер переменных, пока что юзается только в выделении +--А, не, наебал! +--Вон, ниже тоже юзается! Ха, удобненько +local function swap(a, b) + return b, a +end + +--Адекватное округление, ибо в луашке нет такого, ХАХ +local function round(num) + if num >= 0 then + return math.floor(num + 0.5) + else + return math.ceil(num - 0.5) + end +end + +--Отрисовка "прозрачной зоны", этакая сеточка чередующаяся +local function drawTransparentZone(x, y) + if showTransparencyGrid then + y = y - 1 + + local stro4ka1 = "" + local stro4ka2 = "" + if image.getWidth(masterPixels) % 2 == 0 then + stro4ka1 = string.rep("▒ ", math.floor(image.getWidth(masterPixels) / 2)) + stro4ka2 = stro4ka1 + else + stro4ka1 = string.rep("▒ ", math.floor(image.getWidth(masterPixels) / 2)) + stro4ka2 = stro4ka1 .. "▒" + end + + for i = 1, image.getHeight(masterPixels) do + if i % 2 == 0 then + buffer.square(x, y + i, image.getWidth(masterPixels), 1, colors.transparencyWhite, colors.transparencyGray, " ") + buffer.text(x + 1, y + i, colors.transparencyGray, stro4ka1) + else + buffer.square(x, y + i, image.getWidth(masterPixels), 1, colors.transparencyWhite, colors.transparencyGray, " ") + buffer.text(x, y + i, colors.transparencyGray, stro4ka2) + end + end + else + buffer.square(x, y, image.getWidth(masterPixels), image.getHeight(masterPixels), colors.transparencyWhite, 0x000000, " ") + end +end + +--Банальная заливка фона +local function drawBackground() + buffer.square(sizes.xStartOfDrawingArea, sizes.yStartOfDrawingArea, sizes.widthOfDrawingArea, sizes.heightOfDrawingArea + 1, colors.drawingArea, 0xFFFFFF, " ") +end + +--Отрисовка цветов +local function drawColors() + local xPos, yPos = 2, buffer.getHeight() - 4 + buffer.square(xPos, yPos, 3, 2, currentBackground, 0xFFFFFF, " ") + buffer.square(xPos + 3, yPos + 1, 1, 2, currentForeground, 0xFFFFFF, " ") + buffer.square(xPos + 1, yPos + 2, 2, 1, currentForeground, 0xFFFFFF, " ") + buffer.text(xPos + 1, yPos + 3, 0xaaaaaa, "←→") + + newObj("Colors", 1, xPos, yPos, xPos + 2, yPos + 1) + newObj("Colors", 2, xPos + 3, yPos + 1, xPos + 3, yPos + 2) + newObj("Colors", 3, xPos + 1, yPos + 2, xPos + 3, yPos + 2) + newObj("Colors", 4, xPos + 1, yPos + 3, xPos + 2, yPos + 3) +end + +--Отрисовка панели инструментов слева +local function drawLeftBar() + --Рисуем подложечку + buffer.square(1, 5, sizes.widthOfLeftBar, sizes.heightOfLeftBar, colors.leftToolbar, 0xFFFFFF, " ") + --Рисуем инструменты + local yPos = sizes.yStartOfInstruments + for i = 1, #instruments do + if currentInstrument == i then + buffer.square(1, yPos, sizes.widthOfLeftBar, sizes.heightOfInstrument, colors.leftToolbarButton, 0xFFFFFF, " ") + else + buffer.square(1, yPos, sizes.widthOfLeftBar, sizes.heightOfInstrument, colors.leftToolbar, 0xFFFFFF, " ") + end + buffer.text(3, yPos + 1, colors.leftToolbarButtonText, instruments[i]) + + newObj("Instruments", i, 1, yPos, sizes.widthOfLeftBar, yPos + sizes.heightOfInstrument - 1) + + yPos = yPos + sizes.heightOfInstrument + end + --И цвета + drawColors() +end + +--Отрисовка верхнего меню +local function drawTopMenu() + obj.menu = GUI.menu(1, 1, buffer.getWidth(), colors.topMenu, colors.topMenuText, 0x3366CC, 0xFFFFFF, 0) + obj.menu:addItem("PS", ecs.colors.blue) + obj.menu:addItem(localization.file) + obj.menu:addItem(localization.image) + obj.menu:addItem(localization.view) + obj.menu:addItem(localization.hotkeys) + obj.menu:addItem(localization.about) + obj.menu:draw() +end + +--Функция, создающая пустой массив изображения на основе указанных ранее длины и ширины +local function createEmptyMasterPixels() + --Создаем пустой мастерпиксельс + for j = 1, image.getHeight(masterPixels) * image.getWidth(masterPixels) do + table.insert(masterPixels, 0x010101) + table.insert(masterPixels, 0x010101) + table.insert(masterPixels, 1.0) + table.insert(masterPixels, " ") + end +end + +--Мини-консолька для отладки, сообщающая снизу, че происходит ваще +local function console(text) + buffer.square(sizes.xStartOfDrawingArea, buffer.getHeight(), sizes.widthOfDrawingArea, 1, colors.console, colors.consoleText, " ") + + local _, total, used = ecs.getInfoAboutRAM() + local RAMText = used .. "/" .. total .. " KB RAM" + buffer.text(sizes.xEndOfDrawingArea - unicode.len(RAMText), buffer.getHeight(), colors.consoleText, RAMText) + + buffer.text(sizes.xStartOfDrawingArea + 1, buffer.getHeight(), colors.consoleText, text) +end + +--Функция, берущая указанный пиксель из массива изображения и рисующая его в буфере корректно, +--т.е. с учетом прозрачности и т.п. +local function drawPixel(x, y, xPixel, yPixel, iterator) + --Получаем тукущие данные о пикселе + local background, foreground, alpha, symbol = masterPixels[iterator], masterPixels[iterator + 1], masterPixels[iterator + 2], masterPixels[iterator + 3] + --Если пиксель не прозрачный + if alpha == 0 then + buffer.set(x, y, background, foreground, symbol) + --Если пиксель прозрачнее непрозрачного + elseif alpha > 0 then + local blendColor + if xPixel % 2 == 0 then + if yPixel % 2 == 0 then + blendColor = colors.transparencyGray + else + blendColor = colors.transparencyWhite + end + else + if yPixel % 2 == 0 then + blendColor = colors.transparencyWhite + else + blendColor = colors.transparencyGray + end + end + + buffer.set(x, y, color.blend(blendColor, background, alpha), foreground, symbol) + end + background, foreground, alpha, symbol = nil, nil, nil, nil +end + +--Пиздюлинка, показывающая размер текста и тыпы +local function drawTooltip(x, y, ...) + local texts = {...} + --Рассчитываем ширину пиздюлинки + local maxWidth = 0; for i = 1, #texts do maxWidth = math.max(maxWidth, unicode.len(texts[i])) end + --Рисуем пиздюлинку + buffer.square(x, y, maxWidth + 2, #texts, 0x000000, 0xFFFFFF, " ", 0.69); x = x + 1 + for i = 1, #texts do buffer.text(x, y, 0xFFFFFF, texts[i]); y = y + 1 end +end + +--Функция для отрисовки выделения соотв. инструментом +local function drawSelection() + local color = 0x000000 + local xStart, yStart = sizes.xStartOfImage + selection.x - 1, sizes.yStartOfImage + selection.y - 1 + local xEnd, yEnd = xStart + selection.width - 1, yStart + selection.height - 1 + local currentBackground + + local function nextColor() + if color == 0x000000 then color = 0xFFFFFF else color = 0x000000 end + end + + --"━" + --"┃" + + local function drawSelectionSquare(x1, y1, x2, y2, xStep, yStep, symbol) + for y = y1, y2, yStep do + for x = x1, x2, xStep do + local background = buffer.get(x, y) + buffer.set(x, y, background, color, symbol) + nextColor() + end + end + end + + local function drawCornerPoint(x, y, symbol) + local background = buffer.get(x, y) + buffer.set(x, y, background, color, symbol) + nextColor() + end + + if selection.width > 1 and selection.height > 1 then + drawCornerPoint(xStart, yStart, "┏") + drawSelectionSquare(xStart + 1, yStart, xEnd - 1, yStart, 1, 1, "━") + drawCornerPoint(xEnd, yStart, "┓") + drawSelectionSquare(xEnd, yStart + 1, xEnd, yEnd - 1, 1, 1, "┃") + drawCornerPoint(xEnd, yEnd, "┛") + drawSelectionSquare(xEnd - 1, yEnd, xStart + 1, yEnd, -1, 1, "━") + drawCornerPoint(xStart, yEnd, "┗") + drawSelectionSquare(xStart, yEnd - 1, xStart, yStart + 1, 1, -1, "┃") + else + if selection.width == 1 then + drawSelectionSquare(xStart, yStart, xStart, yEnd, 1, 1, "┃") + elseif selection.height == 1 then + drawSelectionSquare(xStart, yStart, xEnd, yStart, 1, 1, "━") + end + end + + drawTooltip(xEnd + 2, yEnd - 1, localization.w .. ": " .. selection.width .. " px", localization.h .. ": " .. selection.height .. " px") + -- drawTooltip(xEnd + 2, yEnd - 1, "Ш: " .. selection.width .. " px", "В: " .. selection.height .. " px", "S: " .. xStart .. "x" .. yStart, "E: " .. xEnd .. "x" .. yEnd) +end + +local function line(x0, y0, x1, y1, background, applyToMasterPixels) + local steep = false; + + if math.abs(x0 - x1) < math.abs(y0 - y1 ) then + x0, y0 = swap(x0, y0) + x1, y1 = swap(x1, y1) + steep = true; + end + + if (x0 > x1) then + x0, x1 = swap(x0, x1) + y0, y1 = swap(y0, y1) + end + + local dx = x1 - x0; + local dy = y1 - y0; + local derror2 = math.abs(dy) * 2 + local error2 = 0; + local y = y0; + + for x = x0, x1, 1 do + if steep then + if applyToMasterPixels then + image.set(masterPixels, y, x, background, 0x000000, 0x00, " ") + else + buffer.set(y, x, background, 0x000000, " ") + end + else + if applyToMasterPixels then + image.set(masterPixels, x, y, background, 0x000000, 0x00, " ") + else + buffer.set(x, y, background, 0x000000, " ") + end + end + + error2 = error2 + derror2; + + if error2 > dx then + y = y + (y1 > y0 and 1 or -1); + error2 = error2 - dx * 2; + end + end +end + +local function drawShapeCornerPoints(xStart, yStart, xEnd, yEnd) + buffer.set(xStart, yStart, 0x99FF80, 0x000000, " ") + buffer.set(xEnd, yEnd, 0x99FF80, 0x000000, " ") +end + +local function drawLineShape() + local xStart, yStart = sizes.xStartOfImage + selection.xStart - 1, sizes.yStartOfImage + selection.yStart - 1 + local xEnd, yEnd = sizes.xStartOfImage + selection.xEnd - 1, sizes.yStartOfImage + selection.yEnd - 1 + + line(xStart, yStart, xEnd, yEnd, currentBackground) + drawShapeCornerPoints(xStart, yStart, xEnd, yEnd) + drawTooltip(xEnd + 2, yEnd - 3, localization.w .. ": " .. selection.width .. " px", localization.h .. ": " .. selection.height .. " px", " ", localization.accept) +end + +--Функция для обводки выделенной зоны +local function stroke(x, y, width, height, color, applyToMasterPixels) + if applyToMasterPixels then + local iterator + for i = x, x + width - 1 do + iterator = image.getImageIndexByCoordinates(i, y, image.getWidth(masterPixels)) + masterPixels[iterator] = color; masterPixels[iterator + 1] = 0x0; masterPixels[iterator + 2] = 0x0; masterPixels[iterator + 3] = " " + + iterator = image.getImageIndexByCoordinates(i, y + height - 1, image.getWidth(masterPixels)) + masterPixels[iterator] = color; masterPixels[iterator + 1] = 0x0; masterPixels[iterator + 2] = 0x0; masterPixels[iterator + 3] = " " + end + + for i = y, y + height - 1 do + iterator = image.getImageIndexByCoordinates(x, i, image.getWidth(masterPixels)) + masterPixels[iterator] = color; masterPixels[iterator + 1] = 0x0; masterPixels[iterator + 2] = 0x0; masterPixels[iterator + 3] = " " + + iterator = image.getImageIndexByCoordinates(x + width - 1, i, image.getWidth(masterPixels)) + masterPixels[iterator] = color; masterPixels[iterator + 1] = 0x0; masterPixels[iterator + 2] = 0x0; masterPixels[iterator + 3] = " " + end + else + buffer.square(x, y, width, 1, color, 0x000000, " ") + buffer.square(x, y + height - 1, width, 1, color, 0x000000, " ") + + buffer.square(x, y, 1, height, color, 0x000000, " ") + buffer.square(x + width - 1, y, 1, height, color, 0x000000, " ") + end +end + +local function ellipse(xStart, yStart, width, height, color, applyToMasterPixels) + --helper function, draws pixel and mirrors it + local function setpixel4(centerX, centerY, deltaX, deltaY, color) + if applyToMasterPixels then + image.set(masterPixels, centerX + deltaX, centerY + deltaY, color, 0x000000, 0x00, " ") + image.set(masterPixels, centerX - deltaX, centerY + deltaY, color, 0x000000, 0x00, " ") + image.set(masterPixels, centerX + deltaX, centerY - deltaY, color, 0x000000, 0x00, " ") + image.set(masterPixels, centerX - deltaX, centerY - deltaY, color, 0x000000, 0x00, " ") + else + buffer.set(centerX + deltaX, centerY + deltaY, color, 0x000000, " ") + buffer.set(centerX - deltaX, centerY + deltaY, color, 0x000000, " ") + buffer.set(centerX + deltaX, centerY - deltaY, color, 0x000000, " ") + buffer.set(centerX - deltaX, centerY - deltaY, color, 0x000000, " ") + end + end + + --red ellipse, 2*10px border + local centerX = math.floor(xStart + width / 2) + local centerY = math.floor(yStart + height / 2) + local radiusX = math.floor(width / 2) + local radiusY = math.floor(height / 2) + local radiusX2 = radiusX ^ 2 + local radiusY2 = radiusY ^ 2 + + --upper and lower halves + local quarter = math.floor(radiusX2 / math.sqrt(radiusX2 + radiusY2)) + for x = 0, quarter do + local y = radiusY * math.sqrt(1 - x^2 / radiusX2) + setpixel4(centerX, centerY, x, math.floor(y), color); + end + + --right and left halves + quarter = math.floor(radiusY2 / math.sqrt(radiusX2 + radiusY2)); + for y = 0, quarter do + x = radiusX * math.sqrt(1 - y^2 / radiusY2); + setpixel4(centerX, centerY, math.floor(x), y, color); + end +end + +local function polygon(xCenter, yCenter, xStart, yStart, countOfEdges, color) + local degreeStep = 360 / countOfEdges + + local deltaX, deltaY = xStart - xCenter, yStart - yCenter + local radius = math.sqrt(deltaX ^ 2 + deltaY ^ 2) + local halfRadius = radius / 2 + local startDegree = math.deg(math.asin(deltaX / radius)) + + local function calculatePosition(degree) + local radDegree = math.rad(degree) + local deltaX2 = math.sin(radDegree) * radius + local deltaY2 = math.cos(radDegree) * radius + return round(xCenter + deltaX2), round(yCenter + (deltaY >= 0 and deltaY2 or -deltaY2)) + end + + local xOld, yOld, xNew, yNew = calculatePosition(startDegree) + + for degree = (startDegree + degreeStep - 1), (startDegree + 360), degreeStep do + xNew, yNew = calculatePosition(degree) + buffer.line(xOld, yOld, xNew, yNew, color, 0x000000, " ") + xOld, yOld = xNew, yNew + end +end + +local function drawPolygonShape() + local xStart, yStart = sizes.xStartOfImage + selection.xStart - 1, sizes.yStartOfImage + selection.yStart - 1 + local xEnd, yEnd = sizes.xStartOfImage + selection.xEnd - 1, sizes.yStartOfImage + selection.yEnd - 1 + + local radius = math.floor(math.sqrt(selection.width ^ 2 + (selection.height*2) ^ 2)) + polygon(xStart, yStart, xEnd, yEnd, currentPolygonCountOfEdges, currentBackground) + + drawShapeCornerPoints(xStart, yStart, xEnd, yEnd) + drawTooltip(xEnd + 2, yEnd - 3, localization.radius .. ": " .. radius .. " px", localization.edges .. ": " .. currentPolygonCountOfEdges, " ", localization.accept) +end + +local function drawSquareShape(type) + local xStart, yStart = sizes.xStartOfImage + selection.x - 1, sizes.yStartOfImage + selection.y - 1 + local xEnd, yEnd = xStart + selection.width - 1, yStart + selection.height - 1 + + if type == "filledSquare" then + buffer.square(xStart, yStart, selection.width, selection.height, currentBackground, 0x000000, " ") + elseif type == "frame" then + stroke(xStart, yStart, selection.width, selection.height, currentBackground, false) + elseif type == "ellipse" then + ellipse(xStart, yStart, selection.width, selection.height, currentBackground, false) + end + + drawShapeCornerPoints(xStart, yStart, xEnd, yEnd) + drawTooltip(xEnd + 2, yEnd - 3, localization.w .. ": " .. selection.width .. " px", localization.h .. ": " .. selection.height .. " px", " ", localization.accept) +end + +local function drawMultiPointInstrument() + if selection and selection.finished == true then + if instruments[currentInstrument] == "M" then + drawSelection() + elseif instruments[currentInstrument] == "S" then + if currentShape == localization.line then + drawLineShape() + elseif currentShape == localization.ellipse then + drawSquareShape("ellipse") + elseif currentShape == localization.rectangle then + drawSquareShape("filledSquare") + elseif currentShape == localization.border then + drawSquareShape("frame") + elseif currentShape == localization.polygon then + drawPolygonShape() + end + end + end +end + +--Отрисовка изображения +local function drawImage() + --Стартовые нужности + local xPixel, yPixel = 1, 1 + local xPos, yPos = sizes.xStartOfImage, sizes.yStartOfImage + + --Устанавливаем ограничение прорисовки, чтобы картинка не съебывала за дозволенную зону + buffer.setDrawLimit(sizes.xStartOfDrawingArea, sizes.yStartOfDrawingArea, sizes.widthOfDrawingArea, sizes.heightOfDrawingArea) + + --Рисуем прозрачную зону + drawTransparentZone(xPos, yPos) + + --Перебираем массив мастерпиксельса + for i = 3, #masterPixels, 4 do + --Рисуем пиксель, если у него прозрачность не абсолютная, ЛИБО имеется какой-то символ + --Т.е. даже если прозрачность и охуела, но символ есть, то рисуем его + if masterPixels[i + 2] ~= 1 or masterPixels[i + 3] ~= " " then + drawPixel(xPos, yPos, xPixel, yPixel, i) + end + --Всякие расчеты координат + xPixel = xPixel + 1 + xPos = xPos + 1 + if xPixel > image.getWidth(masterPixels) then xPixel = 1; xPos = sizes.xStartOfImage; yPixel = yPixel + 1; yPos = yPos + 1 end + end + + if image.getWidth(masterPixels) > 0 and image.getHeight(masterPixels) > 0 then + local text = localization.size .. ": " .. image.getWidth(masterPixels) .. "x" .. image.getHeight(masterPixels) .. " px" + xPos = math.floor(sizes.xStartOfImage + image.getWidth(masterPixels) / 2 - unicode.len(text) / 2) + buffer.text(xPos, sizes.yEndOfImage + 1, 0xFFFFFF, text) + end + + --Рисуем мультиинструмент + drawMultiPointInstrument() + --Убираем ограничение отрисовки + buffer.resetDrawLimit() +end + +--Просто для удобства +local function drawBackgroundAndImage() + drawBackground() + drawImage() +end + +--Функция, рисующая ВСЕ, абсолютли, епта +local function drawAll() + drawBackground() + drawLeftBar() + drawTopMenu() + drawBackgroundAndImage() + + buffer.draw() +end + +------------------------------------------------ Вспомогательные функции для работы с изображением и прочим -------------------------------------------------------------- + +--Смена инструмента на указанный номер +local function changeInstrumentTo(ID) + currentInstrument = ID + selection = nil + drawAll() +end + +--Перемещалка картинки в указанном направлении, поддерживающая все инструменты +local function move(direction) + if instruments[currentInstrument] == "M" and selection and selection.finished == true then + if direction == "up" then + selection.y = selection.y - 1 + if selection.y < 1 then selection.y = 1 end + elseif direction == "down" then + selection.y = selection.y + 1 + if selection.y + selection.height - 1 > image.getHeight(masterPixels) then selection.y = selection.y - 1 end + elseif direction == "left" then + selection.x = selection.x - 1 + if selection.x < 1 then selection.x = 1 end + elseif direction == "right" then + selection.x = selection.x + 1 + if selection.x + selection.width - 1 > image.getWidth(masterPixels) then selection.x = selection.x - 1 end + end + else + local howMuchUpDown = 2 + local howMuchLeftRight = 4 + if direction == "up" then + reCalculateImageSizes(sizes.xStartOfImage, sizes.yStartOfImage - howMuchUpDown) + elseif direction == "down" then + reCalculateImageSizes(sizes.xStartOfImage, sizes.yStartOfImage + howMuchUpDown) + elseif direction == "left" then + reCalculateImageSizes(sizes.xStartOfImage - howMuchLeftRight, sizes.yStartOfImage) + elseif direction == "right" then + reCalculateImageSizes(sizes.xStartOfImage + howMuchLeftRight, sizes.yStartOfImage) + end + end + drawBackgroundAndImage() + buffer.draw() +end + +--Просто более удобная установка пикселя, а то все эти плюсы, минусы, бррр +local function setPixel(iterator, background, foreground, alpha, symbol) + masterPixels[iterator] = background + masterPixels[iterator + 1] = foreground + masterPixels[iterator + 2] = alpha + masterPixels[iterator + 3] = symbol +end + +--Функция, меняющая цвета местами +local function swapColors() + currentBackground, currentForeground = swap(currentBackground, currentForeground) + drawColors() + console("Цвета поменяны местами") +end + +--Ух, сука! Функция для работы инструмента текста +--Лютая дичь, спиздил со старого фш, но, вроде, пашет нормас +--Правда, чет есть предчувствие, что костыльная и багованная она, ну да похуй +local function inputText(x, y, limit) + local oldPixels = ecs.rememberOldPixels(x,y-1,x+limit-1,y+1) + local text = "" + local inputPos = 1 + + local function drawThisShit() + for i = 1, inputPos do + ecs.invertedText(x + i - 1, y + 1, "─") + ecs.adaptiveText(x + i - 1, y - 1, " ", currentBackground) + end + ecs.invertedText(x + inputPos - 1, y + 1, "▲")--"▲","▼" + ecs.invertedText(x + inputPos - 1, y - 1, "▼") + ecs.adaptiveText(x, y, ecs.stringLimit("start", text, limit, false), currentBackground) + end + + drawThisShit() + + while true do + local e = {event.pull()} + if e[1] == "key_down" then + if e[4] == 14 then + if unicode.len(text) >= 1 then + text = unicode.sub(text, 1, -2) + if unicode.len(text) < (limit - 1) then + inputPos = inputPos - 1 + end + ecs.drawOldPixels(oldPixels) + drawThisShit() + end + elseif e[4] == 28 then + break + elseif e[4] == 200 then + text = text .. "▀" + if unicode.len(text) < limit then + inputPos = inputPos + 1 + end + drawThisShit() + elseif e[4] == 208 then + text = text .. "▄" + if unicode.len(text) < limit then + inputPos = inputPos + 1 + end + drawThisShit() + else + local symbol = ecs.convertCodeToSymbol(e[3]) + if symbol ~= nil then + text = text .. symbol + if unicode.len(text) < limit then + inputPos = inputPos + 1 + end + drawThisShit() + end + end + elseif e[1] == "clipboard" then + if e[3] then + text = text .. e[3] + if unicode.len(text) < limit then + inputPos = inputPos + unicode.len(e[3]) + end + drawThisShit() + end + end + end + + ecs.drawOldPixels(oldPixels) + if text == "" then text = " " end + return text +end + +--Функция-применятор текста к массиву изображения +local function saveTextToPixels(x, y, text) + local sText = unicode.len(text) + local iterator + x = x - 1 + for i = 1, sText do + if x + i > image.getWidth(masterPixels) then break end + iterator = image.getImageIndexByCoordinates(x + i, y, image.getWidth(masterPixels)) + setPixel(iterator, masterPixels[iterator], currentBackground, masterPixels[iterator + 2], unicode.sub(text, i, i)) + end +end + +--Функция-центратор картинки по центру моника +local function tryToFitImageOnCenterOfScreen() + reCalculateImageSizes() + + local x, y = sizes.xStartOfImage, sizes.yStartOfImage + if image.getWidth(masterPixels) < sizes.widthOfDrawingArea then + x = math.floor(sizes.xStartOfDrawingArea + sizes.widthOfDrawingArea / 2 - image.getWidth(masterPixels) / 2) - 1 + end + + if image.getHeight(masterPixels) < sizes.heightOfDrawingArea then + y = math.floor(sizes.yStartOfDrawingArea + sizes.heightOfDrawingArea / 2 - image.getHeight(masterPixels) / 2) + end + + reCalculateImageSizes(x, y) +end + +--Функция, спрашивающая юзверя, какого размера пикчу он хочет создать - ну, и создает ее +local function new() + selection = nil + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, {"EmptyLine"}, {"CenterText", 0x262626, localization.newDocument}, {"EmptyLine"}, {"Input", 0x262626, 0x880000, localization.width}, {"Input", 0x262626, 0x880000, localization.height}, {"EmptyLine"}, {"Button", {0x999999, 0xffffff, "OK"}}) + + data[1] = tonumber(data[1]) or 51 + data[2] = tonumber(data[2]) or 19 + + masterPixels = {} + masterPixels[1], masterPixels[2] = data[1], data[2] + createEmptyMasterPixels() + tryToFitImageOnCenterOfScreen() + drawAll() +end + +--Обычная рекурсивная заливка, алгоритм спизжен с вики +--Есть инфа, что выжирает стек, но Луа, вроде, не особо ругается, так что заебок все +local function fill(x, y, startColor, fillColor) + local function doFill(xStart, yStart) + local iterator = image.getImageIndexByCoordinates(xStart, yStart, image.getWidth(masterPixels)) + + --Завершаем функцию, если цвет в массиве не такой, какой мы заливаем + if masterPixels[iterator] ~= startColor or masterPixels[iterator] == fillColor then return end + + --Заливаем в память + masterPixels[iterator] = fillColor + masterPixels[iterator + 2] = currentAlpha + + doFill(xStart + 1, yStart) + doFill(xStart - 1, yStart) + doFill(xStart, yStart + 1) + doFill(xStart, yStart - 1) + + iterator = nil + end + doFill(x, y) +end + +--Кисть, КИИИИСТЬ +local function brush(x, y, background, foreground, alpha, symbol) + --Смещение влево и вправо относительно указанного центра кисти + --КОРОЧ, НЕ ТУПИ + --Чтобы кисточка была по центру мыши, ну + local position = math.floor(currentBrushSize / 2) + x, y = x - position, y - position + --Хуевинка для рисования + local newIterator + --Перебираем кисть по ширине и высоте + for cyka = 1, currentBrushSize do + for pidor = 1, currentBrushSize do + --Если этот кусочек входит в границы рисовабельной зоны, то + if x >= 1 and x <= image.getWidth(masterPixels) and y >= 1 and y <= image.getHeight(masterPixels) then + + --Считаем итератор для кусочка кисти + newIterator = image.getImageIndexByCoordinates(x, y, image.getWidth(masterPixels)) + + --Если прозрачности кисти ВАЩЕ НЕТ, то просто рисуем как обычненько все + if alpha == 0 then + setPixel(newIterator, background, foreground, alpha, symbol) + --Если прозрачности кисти есть какая-то, но она не абсолютная + elseif alpha < 1 and alpha > 0 then + --Если пиксель в массиве ни хуя не прозрачный, то оставляем его таким же, разве что цвет меняем на сблендированный + if masterPixels[newIterator + 2] == 0 then + local gettedBackground = color.blend(masterPixels[newIterator], background, alpha) + setPixel(newIterator, gettedBackground, foreground, 0, symbol) + --А если прозрачный, то смешиваем прозрачности + --Пиздануться вообще, сук + else + --Если его прозрачность максимальная + if masterPixels[newIterator + 2] == 1 then + setPixel(newIterator, background, foreground, alpha, symbol) + --Если не максимальная + else + local newAlpha = masterPixels[newIterator + 2] - (1 - alpha) + if newAlpha < 0 then newAlpha = 0 end + setPixel(newIterator, background, foreground, newAlpha, symbol) + end + end + --Если указанная прозрачность максимальна, т.е. равна 0xFF + else + setPixel(newIterator, 0x000000, 0x000000, 1, " ") + end + + --Рисуем пиксель из мастерпиксельса + drawPixel(x + sizes.xStartOfImage - 1, y + sizes.yStartOfImage - 1, x, y, newIterator) + end + + x = x + 1 + end + x = x - currentBrushSize + y = y + 1 + end +end + +--Функция-обрезчик картинки +local function crop() + if selection then + masterPixels = image.crop(masterPixels, selection.x, selection.y, selection.width, selection.height) + selection = nil + tryToFitImageOnCenterOfScreen() + drawAll() + end +end + +--Функция-расширитель картинки +local function expand() + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x262626, localization.expand}, + {"EmptyLine"}, + {"Input", 0x262626, 0x880000, localization.countOfPixels}, + {"Selector", 0x262626, 0x880000, localization.fromBottom, localization.fromTop, localization.fromLeft, localization.fromRight}, + {"EmptyLine"}, + {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} + ) + + if data[3] == "OK" then + local countOfPixels = tonumber(data[1]) + if countOfPixels then + masterPixels = image.expand(masterPixels, + data[2] == localization.fromTop and countOfPixels or 0, + data[2] == localization.fromBottom and countOfPixels or 0, + data[2] == localization.fromLeft and countOfPixels or 0, + data[2] == localization.fromRight and countOfPixels or 0, + 0x010101, 0x010101, 1, " " + ) + reCalculateImageSizes(sizes.xStartOfImage, sizes.yStartOfImage) + drawAll() + end + end +end + +--Функция-загрузчик картинки из файла +local function loadImageFromFile(path) + if fs.exists(path) then + selection = nil + masterPixels = image.load(path) + savePath = path + tryToFitImageOnCenterOfScreen() + else + ecs.error("Файл \"" .. path .. "\" не существует") + end +end + +--Функция-заполнитель выделенной зоны какими-либо данными +local function fillSelection(background, foreground, alpha, symbol) + for j = selection.y, selection.y + selection.height - 1 do + for i = selection.x, selection.x + selection.width - 1 do + local iterator = image.getImageIndexByCoordinates(i, j, image.getWidth(masterPixels)) + masterPixels[iterator] = background + masterPixels[iterator + 1] = foreground + masterPixels[iterator + 2] = alpha + masterPixels[iterator + 3] = symbol + end + end + + drawAll() +end + +local function applyShapeToMasterPixels() + if currentShape == localization.line then + line(selection.xStart, selection.yStart, selection.xEnd, selection.yEnd, currentBackground, true) + elseif currentShape == localization.rectangle then + fillSelection(currentBackground, 0x00000, 0x00, " ") + elseif currentShape == localization.border then + stroke(selection.x, selection.y, selection.width, selection.height, currentBackground, true) + elseif currentShape == localization.ellipse then + ellipse(selection.x, selection.y, selection.width, selection.height, currentBackground, true) + end + + selection = nil + drawBackgroundAndImage() + buffer.draw() +end + +------------------------------------------------ Старт программы -------------------------------------------------------------- + +--Рисуем весь интерфейс чисто для красоты +drawAll() + +--Открываем файлы по аргументам программы +if args[1] and fs.exists(args[1]) then + loadImageFromFile(args[1]) +else + new() +end + +--Отрисовываем интерфейс снова, поскольку у нас либо создался новый документ, либо открылся имеющийся файл +drawAll() + +--Анализируем ивенты +while true do + local e = {event.pull()} + if e[1] == "touch" or e[1] == "drag" or e[1] == "drop" then + --Левый клик + if e[5] == 0 then + --Если кликнули на рисовабельную зонку + if ecs.clickedAtArea(e[3], e[4], sizes.xStartOfImage, sizes.yStartOfImage, sizes.xEndOfImage, sizes.yEndOfImage) then + + --Получаем координаты в изображении и итератор + local x, y = e[3] - sizes.xStartOfImage + 1, e[4] - sizes.yStartOfImage + 1 + local iterator = image.getImageIndexByCoordinates(x, y, image.getWidth(masterPixels)) + + --Все для инструментов мультиточечного рисования + if instruments[currentInstrument] == "M" or instruments[currentInstrument] == "S" then + if e[1] == "touch" then + selection = {} + selection.xStart, selection.yStart = x, y + + elseif e[1] == "drag" and selection then + local x1, y1 = selection.xStart, selection.yStart + local x2, y2 = x, y + if x1 > x2 then + x1, x2 = swap(x1, x2) + end + if y1 > y2 then + y1, y2 = swap(y1, y2) + end + + selection.x, selection.y = x1, y1 + selection.x2, selection.y2 = x2, y2 + selection.xEnd, selection.yEnd = x, y + selection.width = selection.x2 - selection.x + 1 + selection.height = selection.y2 - selection.y + 1 + + selection.finished = true + end + + --Если выделение полностью завершено, то отдаем контроль отрисовочным функциям + -- if instruments[currentInstrument] == "M" then + drawBackgroundAndImage() + buffer.draw() + -- end + --Кисть + elseif instruments[currentInstrument] == "B" then + + --Если нажата клавиша альт + if keyboard.isKeyDown(56) then + local _, gettedForeground, gettedBackground = component.gpu.get(e[3], e[4]) + currentBackground = gettedBackground + currentForeground = gettedForeground + drawColors() + buffer.draw() + + --Если обычная кисть, просто кисть, вообще всем кистям кисть + else + brush(x, y, currentBackground, currentForeground, currentAlpha, currentSymbol) + --Пишем что-то в консоли + console("Кисть: клик на точку "..e[3].."x"..e[4]..", координаты в изображении: "..x.."x"..y..", индекс массива изображения: "..iterator) + buffer.draw() + end + --Ластик + elseif instruments[currentInstrument] == "E" then + brush(x, y, currentBackground, currentForeground, 1, currentSymbol) + console("Ластик: клик на точку "..e[3].."x"..e[4]..", координаты в изображении: "..x.."x"..y..", индекс массива изображения: "..iterator) + buffer.draw() + --Текст + elseif instruments[currentInstrument] == "T" then + local limit = image.getWidth(masterPixels) - x + 1 + local text = inputText(e[3], e[4], limit) + saveTextToPixels(x, y, text) + drawImage() + buffer.draw() + + --Заливка + elseif instruments[currentInstrument] == "F" then + + fill(x, y, masterPixels[iterator], currentBackground) + drawImage() + buffer.draw() + + end + + iterator, x, y = nil, nil, nil + + end + + --Цвета + for key in pairs(obj["Colors"]) do + if ecs.clickedAtArea(e[3], e[4], obj["Colors"][key][1], obj["Colors"][key][2], obj["Colors"][key][3], obj["Colors"][key][4]) then + if key == 1 then + currentBackground = GUI.palette(math.floor(buffer.getWidth() / 2 - 35), math.floor(buffer.getHeight() / 2 - 12), currentBackground):show() or currentBackground + drawAll() + elseif key == 2 or key == 3 then + currentForeground = GUI.palette(math.floor(buffer.getWidth() / 2 - 35), math.floor(buffer.getHeight() / 2 - 12), currentForeground):show() or currentForeground + drawAll() + elseif key == 4 then + buffer.text(obj["Colors"][key][1], obj["Colors"][key][2], 0xFF0000, "←→") + os.sleep(0.2) + swapColors() + buffer.draw() + end + break + end + end + + --Инструменты + for key in pairs(obj["Instruments"]) do + if ecs.clickedAtArea(e[3], e[4], obj["Instruments"][key][1], obj["Instruments"][key][2], obj["Instruments"][key][3], obj["Instruments"][key][4]) then + selection = nil + currentInstrument = key + drawLeftBar(); buffer.draw() + if instruments[currentInstrument] == "S" then + local menu = GUI.contextMenu(obj["Instruments"][key][3] + 1, obj["Instruments"][key][2]) + menu:addItem(localization.line) + menu:addItem(localization.ellipse) + menu:addItem(localization.rectangle) + menu:addItem(localization.polygon) + menu:addItem(localization.border) + + local action = menu:show() + currentShape = action or localization.line + if currentShape == localization.polygon then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x262626, localization.edges}, + {"EmptyLine"}, + {"Selector", 0x262626, 0x880000, "3", "4", "5", "6", "7", "8", "9", "10"}, + {"EmptyLine"}, + {"Button", {0xaaaaaa, 0xffffff, "OK"}} + ) + currentPolygonCountOfEdges = tonumber(data[1]) + end + drawAll() + end + break + end + end + + --Верхний меню-бар + local object + for i = 1, #obj.menu.children do + if obj.menu.children[i]:isClicked(e[3], e[4]) then + object = obj.menu.children[i] + break + end + end + if object then + object:press({draw = function() end}, object, {}) + buffer.draw() + local action + if object.text == localization.file then + local menu = GUI.contextMenu(object.x, object.y + 1) + + menu:addItem(localization.new, false, "^N") + menu:addItem(localization.open, false, "^O") + menu:addItem(localization.createFromString) + menu:addSeparator() + menu:addItem(localization.save, savePath == nil, "^S") + menu:addItem(localization.saveAs) + menu:addSeparator() + menu:addItem(localization.exit) + + action = menu:show() + elseif object.text == localization.image then + local menu = GUI.contextMenu(object.x, object.y + 1) + + menu:addItem(localization.expand) + menu:addSeparator() + menu:addItem(localization.flipHorizontal) + menu:addItem(localization.flipVertical) + + action = menu:show() + elseif object.text == localization.view then + local menu = GUI.contextMenu(object.x, object.y + 1) + + menu:addItem(localization.transparencyPad) + + action = menu:show() + elseif object.text == localization.about then + ecs.universalWindow("auto", "auto", 36, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x880000, photoshopVersion}, {"EmptyLine"}, {"CenterText", 0x262626, localization.developers}, {"CenterText", 0x555555, "Тимофеев Игорь"}, {"CenterText", 0x656565, "vk.com/id7799889"}, {"CenterText", 0x656565, "Трифонов Глеб"}, {"CenterText", 0x656565, "vk.com/id88323331"}, {"EmptyLine"}, {"CenterText", 0x262626, localization.testers}, {"CenterText", 0x656565, "Шестаков Тимофей"}, {"CenterText", 0x656565, "vk.com/id113499693"}, {"CenterText", 0x656565, "Вечтомов Роман"}, {"CenterText", 0x656565, "vk.com/id83715030"}, {"CenterText", 0x656565, "Омелаенко Максим"}, {"CenterText", 0x656565, "vk.com/paladincvm"}, {"EmptyLine"},{"Button", {0xbbbbbb, 0xffffff, "OK"}}) + elseif object.text == localization.hotkeys then + ecs.universalWindow( "auto", "auto", 42, 0xeeeeee, true, + table.unpack(localization.hotkeysLines) + ) + end + + if action == localization.exit then + ecs.prepareToExit() + return + elseif action == localization.hueSaturation then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x262626, localization.hueSaturation}, + {"EmptyLine"}, + {"Slider", 0x262626, 0x880000, 0, 100, 50, localization.hue .. ": ", ""}, + {"Slider", 0x262626, ecs.colors.red, 0, 100, 50, localization.saturation .. ": ", ""}, + {"Slider", 0x262626, 0x000000, 0, 100, 50, localization.brightness .. ": ", ""}, + {"EmptyLine"}, + {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} + ) + if data[4] == "OK" then + masterPixels = image.hueSaturationBrightness(masterPixels, data[1] - 50, data[2] - 50, data[3] - 50) + drawAll() + end + elseif action == localization.gaussianBlur then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x262626, localization.gaussianBlur}, + {"EmptyLine"}, + {"Slider", 0x262626, 0x880000, 1, 5, 2, localization.radius .. ": ", ""}, + {"Slider", 0x262626, 0x880000, 1, 255, 0x88, localization.force .. ": ", ""}, + {"EmptyLine"}, + {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} + ) + if data[3] == "OK" then + masterPixels = image.gaussianBlur(masterPixels, tonumber(data[1]), tonumber(data[2])) + drawAll() + end + elseif action == localization.colorBalance then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x262626, localization.colorBalance}, + {"EmptyLine"}, + {"Slider", 0x262626, 0x880000, 0, 100, 50, "R: ", ""}, + {"Slider", 0x262626, ecs.colors.green, 0, 100, 50, "G: ", ""}, + {"Slider", 0x262626, ecs.colors.blue, 0, 100, 50, "B: ", ""}, + {"EmptyLine"}, + {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} + ) + if data[4] == "OK" then + masterPixels = image.colorBalance(masterPixels, data[1] - 50, data[2] - 50, data[3] - 50) + drawAll() + end + elseif action == localization.photoFilter then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x262626, localization.photoFilter}, + {"EmptyLine"}, + {"Color", localization.filterColor, 0x333333}, + {"Slider", 0x262626, 0x880000, 0, 255, 100, localization.transparency .. ": ", ""}, + {"EmptyLine"}, + {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} + ) + if data[3] == "OK" then + masterPixels = image.photoFilter(masterPixels, data[1], data[2]) + drawAll() + end + elseif action == localization.crop then + crop() + elseif action == localization.expand then + expand() + elseif action == localization.flipVertical then + masterPixels = image.flipVertically(masterPixels) + drawAll() + elseif action == localization.flipHorizontal then + masterPixels = image.flipHorizontally(masterPixels) + drawAll() + elseif action == localization.invertColors then + masterPixels = image.invert(masterPixels) + drawAll() + elseif action == localization.blackWhite then + masterPixels = image.blackAndWhite(masterPixels) + drawAll() + elseif action == localization.rotateBy90 then + masterPixels = image.rotate(masterPixels, 90) + drawAll() + elseif action == localization.rotateBy180 then + masterPixels = image.rotate(masterPixels, 180) + drawAll() + elseif action == localization.new then + new() + drawAll() + elseif action == localization.saveAs then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x262626, localization.saveAs}, + {"EmptyLine"}, + {"Input", 0x262626, 0x880000, localization.path}, + {"Selector", 0x262626, 0x880000, "OCIF6", "OCIF1", "StringImage"}, + {"EmptyLine"}, + {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} + ) + + if data[3] == "OK" then + data[1] = data[1] or "Untitled.pic" + + local path = string.gsub(data[1], "%.pic$", "") .. ".pic" + if data[2] == "StringImage" then + local file = io.open(path, "w") + file:write(image.toString(masterPixels)) + file:close() + else + savePath = path + image.save(path, masterPixels, data[2] == "OCIF6" and 6 or 1) + end + end + elseif action == localization.save then + image.save(savePath, masterPixels) + + elseif action == localization.open then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, {"EmptyLine"}, {"CenterText", 0x262626, localization.open}, {"EmptyLine"}, {"Input", 0x262626, 0x880000, localization.path}, {"EmptyLine"}, {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}}) + if data[2] == "OK" then + local fileFormat = ecs.getFileFormat(data[1]) + + if not data[1] then + ecs.error("Некорректное имя файла!") + elseif not fs.exists(data[1]) then + ecs.error("Файл\""..data[1].."\" не существует!") + elseif fileFormat ~= ".pic" and fileFormat ~= ".rawpic" and fileFormat ~= ".png" then + ecs.error("Формат файла \""..fileFormat.."\" не поддерживается!") + else + loadImageFromFile(data[1]) + drawAll() + end + end + elseif action == localization.createFromString then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x262626, localization.createFromString}, + {"EmptyLine"}, + {"Input", 0x262626, 0x880000, localization.string}, + {"EmptyLine"}, + {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} + ) + if data[2] == "OK" then + local success, picture = pcall(image.fromString, data[1]) + if success then + masterPixels, selection, savePath = picture, nil, nil + tryToFitImageOnCenterOfScreen() + drawAll() + else + error("Failed to create image from string") + end + end + elseif action == localization.transparencyPad then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x262626, localization.transparencyPad}, + {"EmptyLine"}, + {"Color", localization.transparencyColor .. " 1", colors.transparencyWhite}, + {"Color", localization.transparencyColor .. " 2", colors.transparencyGray}, + {"EmptyLine"}, + {"Switch", 0xF2B233, 0xffffff, 0x262626, localization.transparencyGrid, showTransparencyGrid}, + {"EmptyLine"}, + {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} + ) + + if data[4] == "OK" then + colors.transparencyWhite, colors.transparencyGray, showTransparencyGrid = data[1], data[2], data[3] + drawAll() + end + end + + drawTopMenu() + buffer.draw() + end + else + --Если кликнули на рисовабельную зонку + if ecs.clickedAtArea(e[3], e[4], sizes.xStartOfImage, sizes.yStartOfImage, sizes.xEndOfImage, sizes.yEndOfImage) then + + if instruments[currentInstrument] == "M" and selection then + local menu = GUI.contextMenu(e[3], e[4]) + + menu:addItem(localization.deselect) + menu:addItem(localization.crop) + menu:addSeparator() + menu:addItem(localization.fill) + menu:addItem(localization.border) + menu:addSeparator() + menu:addItem(localization.clear) + + action = menu:show() + if action == localization.deselect then + selection = nil + drawAll() + elseif action == localization.crop then + crop() + elseif action == localization.clear then + fillSelection(0x0, 0x0, 1, " ") + elseif action == localization.fill then + fillSelection(currentBackground, 0x0, 0x0, " ") + elseif action == localization.border then + stroke(selection.x, selection.y, selection.width, selection.height, currentBackground, true) + drawAll() + end + else + local x, y, width, height = e[3], e[4], 30, 12 + --А это чтоб за края экрана не лезло + if y + height >= buffer.getHeight() then y = buffer.getHeight() - height end + if x + width + 1 >= buffer.getWidth() then x = buffer.getWidth() - width - 1 end + + currentBrushSize, currentAlpha = table.unpack(ecs.universalWindow(x, y, width, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x880000, localization.brushParameters}, {"Slider", 0x262626, 0x880000, 1, 10, currentBrushSize, localization.size .. ": ", " px"}, {"Slider", 0x262626, 0x880000, 0, 255, currentAlpha, localization.transparency .. ": ", ""}, {"EmptyLine"}, {"Button", {0xbbbbbb, 0xffffff, "OK"}})) + buffer.draw() + end + end + end + + elseif e[1] == "key_down" then + --Стрелки + if e[4] == 200 then + move("up") + elseif e[4] == 208 then + move("down") + elseif e[4] == 203 then + move("left") + elseif e[4] == 205 then + move("right") + -- --Пробел + -- elseif e[4] == 57 then + -- drawAll() + --ENTER + elseif e[4] == 28 then + if instruments[currentInstrument] == "S" and selection and selection.finished then + applyShapeToMasterPixels() + end + --BACKSPACE + elseif e[4] == 14 then + if selection and selection.finished then + fillSelection(0x000000, 0x000000, 0x00, " ") + drawAll() + end + --X + elseif e[4] == 45 then + swapColors() + buffer.draw() + --B + elseif e[4] == 48 then + changeInstrumentTo(2) + --E + elseif e[4] == 18 then + changeInstrumentTo(3) + --G + elseif e[4] == 34 then + changeInstrumentTo(4) + --T + elseif e[4] == 20 then + changeInstrumentTo(5) + --M + elseif e[4] == 50 then + changeInstrumentTo(1) + --D + elseif e[4] == 32 then + if keyboard.isControlDown() then + selection = nil + drawAll() + else + currentBackground = 0x000000 + currentForeground = 0xFFFFFF + currentAlpha = 0x00 + drawColors() + buffer.draw() + end + end + elseif e[1] == "scroll" then + if e[5] == 1 then + move("up") + else + move("down") + end + end +end + +------------------------------------------------ Выход из программы -------------------------------------------------------------- diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Photoshop.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Photoshop.app/Resources/About/Russian.txt new file mode 100755 index 00000000..a4aa238f --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Photoshop.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Photoshop - это мощный графический редактор, написанный специально для работы с нашей ОС. Он поддерживает работу с кистями, прозрачностью, имеет функции заливки, выбора цвета из красочной палитры, позволяет создавать настоящие мини-шедевры прямо на вашем ПК. Вся графика в нашей ОС нарисована именно в этой программе. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Photoshop.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Photoshop.app/Resources/Icon.pic new file mode 100755 index 00000000..e7d2f0be Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Photoshop.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Photoshop.app/Resources/Localization/English.lang b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Photoshop.app/Resources/Localization/English.lang new file mode 100755 index 00000000..c576084a --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Photoshop.app/Resources/Localization/English.lang @@ -0,0 +1,92 @@ +{ + newDocument = "New document", + width = "Width", + height = "Height", + cancel = "Cancel", + w = "W", + h = "H", + + view = "View", + transparencyPad = "Transparency pad", + transparencyColor = "Transparency color", + transparencyGrid = "Transparency grid", + + path = "Path", + string = "String", + file = "File", + image = "Image", + edit = "Edit", + hotkeys = "Hot keys", + about = "About", + brushSize = "Brush size", + transparency = "Transparency", + brushParameters = "Brush parameters", + size = "Size", + + new = "New", + open = "Open", + createFromString = "Create from StringImage", + save = "Save", + saveAs = "Save as", + exit = "Exit", + + crop = "Crop", + expand = "Expand", + rotateBy90 = "Rotate by 90 degrees", + rotateBy180 = "Rotate by 180 degrees", + flipVertical = "Flip vertical", + flipHorizontal = "Flip horizontal", + + hueSaturation = "Hue/Saturation", + colorBalance = "Color balance", + photoFilter = "Photo filter", + invertColors = "Invert colors", + blackWhite = "Black and white", + gaussianBlur = "Gaussian blur", + + countOfPixels = "Count of pixels", + fromBottom = "From bottom", + fromTop = "From top", + fromLeft = "From left", + fromRight = "From right", + hue = "Hue", + saturation = "Saturation", + brightness = "Brightness", + filterColor = "Filter color", + radius = "Radius", + force = "Force", + edges = "Edges", + accept = "Enter - accept", + + line = "Line", + ellipse = "Ellipse", + rectangle = "Rectangle", + polygon = "Polygon", + border = "Border", + + fill = "Fill", + clear = "Clear", + deselect = "Deselect", + + hotkeysLines = { + {"EmptyLine"}, + {"CenterText", 0x880000, "Hotkeys"}, + {"EmptyLine"}, + {"CenterText", 0x000000, "B - Brush"}, + {"CenterText", 0x000000, "E - Eraser"}, + {"CenterText", 0x000000, "T - Text"}, + {"CenterText", 0x000000, "G - Fill"}, + {"CenterText", 0x000000, "M - Selection"}, + {"CenterText", 0x000000, " "}, + {"CenterText", 0x000000, "Arrows - move image"}, + {"CenterText", 0x000000, "X - swap colors"}, + {"CenterText", 0x000000, "D - make colors black&white"}, + {"CenterText", 0x000000, "Ctrl+D - deselect"}, + {"CenterText", 0x000000, "Alt+Click - pick color (brush only)"}, + {"EmptyLine"}, + {"Button", {0xbbbbbb, 0xffffff, "OK"}}, + }, + + developers = "Developers:", + testers = "Testers:", +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Photoshop.app/Resources/Localization/Russian.lang b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Photoshop.app/Resources/Localization/Russian.lang new file mode 100755 index 00000000..a811b943 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Photoshop.app/Resources/Localization/Russian.lang @@ -0,0 +1,92 @@ +{ + newDocument = "Новый документ", + width = "Ширина", + height = "Высота", + cancel = "Отмена", + w = "Ш", + h = "В", + + view = "Вид", + transparencyPad = "Подложка прозрачности", + transparencyColor = "Цвет прозрачности", + transparencyGrid = "Сетка прозрачности", + + path = "Путь", + string = "Строка", + file = "Файл", + image = "Изображение", + edit = "Редактировать", + hotkeys = "Горячие клавиши", + about = "О программе", + brushSize = "Размер кисти", + transparency = "Прозрачность", + brushParameters = "Параметры кисти", + size = "Размер", + + new = "Новый", + open = "Открыть", + createFromString = "Создать из StringImage", + save = "Сохранить", + saveAs = "Сохранить как", + exit = "Выход", + + crop = "Обрезать", + expand = "Расширить", + rotateBy90 = "Повернуть на 90 градусов", + rotateBy180 = "Повернуть на 180 градусов", + flipVertical = "Отразить по вертикали", + flipHorizontal = "Отразить по горизонтали", + + hueSaturation = "Тон/Насыщенность", + colorBalance = "Цветовой баланс", + photoFilter = "Фотофильтр", + invertColors = "Инвертировать цвета", + blackWhite = "Черно-белый фильтр", + gaussianBlur = "Размытие по Гауссу", + + countOfPixels = "Количество пикселей", + fromBottom = "Снизу", + fromTop = "Сверху", + fromLeft = "Слева", + fromRight = "Справа", + hue = "Тон", + saturation = "Насыщенность", + brightness = "Яркость", + filterColor = "Цвет фильтра", + radius = "Радиус", + force = "Сила", + edges = "Грани", + accept = "Enter - применить", + + line = "Линия", + ellipse = "Эллипс", + rectangle = "Прямоугольник", + polygon = "Многоугольник", + border = "Рамка", + + fill = "Заливка", + clear = "Очистить", + deselect = "Убрать выделение", + + hotkeysLines = { + {"EmptyLine"}, + {"CenterText", 0x880000, "Горячие клавиши"}, + {"EmptyLine"}, + {"CenterText", 0x000000, "B - кисть"}, + {"CenterText", 0x000000, "E - ластик"}, + {"CenterText", 0x000000, "T - текст"}, + {"CenterText", 0x000000, "G - заливка"}, + {"CenterText", 0x000000, "M - выделение"}, + {"CenterText", 0x000000, " "}, + {"CenterText", 0x000000, "Arrows - перемещение"}, + {"CenterText", 0x000000, "X - поменять цвета местами"}, + {"CenterText", 0x000000, "D - сменить цвета на черный и белый"}, + {"CenterText", 0x000000, "Ctrl+D - убрать выделение"}, + {"CenterText", 0x000000, "Alt+Click - выбрать цвет (только для кисти)"}, + {"EmptyLine"}, + {"Button", {0xbbbbbb, 0xffffff, "OK"}}, + }, + + developers = "Разработчики:", + testers = "Тестеры:", +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/PrintImage.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/PrintImage.app/Main.lua new file mode 100755 index 00000000..e43ac59d --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/PrintImage.app/Main.lua @@ -0,0 +1,330 @@ + +----------------------------------------- Libraries ----------------------------------------- + +local component = require("component") +local computer = require("computer") +local unicode = require("unicode") +local fs = require("filesystem") +local advancedLua = require("advancedLua") +local color = require("color") +local image = require("image") +local buffer = require("doubleBuffering") +local GUI = require("GUI") +local MineOSPaths = require("MineOSPaths") +local MineOSCore = require("MineOSCore") + +----------------------------------------- cyka ----------------------------------------- + +if not component.isAvailable("printer3d") then GUI.error("This program requires at least one 3D-printer"); return end +local args, options = require("shell").parse(...) +local startImagePath = args[1] == "open" and args[2] or "/MineOS/System/Icons/Steve.pic" +local configPath = MineOSPaths.applicationData .. "PrintImage/Config.cfg" +local panelWidth = 34 +local mainContainer +local mainImage +local printers +local currentPrinter = 1 +local shapeResolutionLimit = 4 +local timeDelay = 0.05 + +----------------------------------------- Config ----------------------------------------- + +local function save() + table.toFile(configPath, config) +end + +local function load() + if fs.exists(configPath) then + config = table.fromFile(configPath) + else + config = { + mainMaterial = "quartz_block_side", + printName = "My picture", + showGrid = true, + floorMode = false, + frame = {enabled = true, width = 3, material = "planks_spruce"}, + lightEmission = {enabled = false, level = 8} + } + save() + end +end + +----------------------------------------- Printer-related cyka ----------------------------------------- + +local function getPrinters() + printers = {} + for address in pairs(component.list("printer3d")) do table.insert(printers, component.proxy(address)) end +end + +local function addShapePixel(x, y, color, xPrinterPixel, yPrinterPixel) + local pixelSize = math.floor(16 / shapeResolutionLimit) + local xPrinter = x * pixelSize - pixelSize + local yPrinter = y * pixelSize - pixelSize + + if config.floorMode then + printers[currentPrinter].addShape(xPrinter, 0, yPrinter, xPrinter + pixelSize, 16, yPrinter + pixelSize, config.mainMaterial, false, color) + else + if config.frame.enabled then + local xModifyer1, xModifyer2, yModifyer1, yModifyer2 = 0, 0, 0, 0 + if xPrinterPixel == 1 then xModifyer1 = config.frame.width end + if xPrinterPixel == image.getWidth(mainImage) then xModifyer2 = -config.frame.width end + if yPrinterPixel == 1 then yModifyer2 = -config.frame.width end + if yPrinterPixel == image.getHeight(mainImage) * 2 then yModifyer1 = config.frame.width end + printers[currentPrinter].addShape(xPrinter + xModifyer1, yPrinter + yModifyer1, 15, xPrinter + pixelSize + xModifyer2, yPrinter + pixelSize + yModifyer2, 16, config.mainMaterial, false, color) + else + printers[currentPrinter].addShape(xPrinter, 15, yPrinter, xPrinter + pixelSize, 16, yPrinter + pixelSize, config.mainMaterial, false, color) + end + end +end + +local function beginPrint() + buffer.clear(0x0000000, 50) + + local xShape, yShape = 1, 1 + local xShapeCount, yShapeCount = math.ceil(image.getWidth(mainImage) / shapeResolutionLimit), math.ceil(image.getHeight(mainImage) * 2 / shapeResolutionLimit) + local counter = 0 + while true do + if printers[currentPrinter].status() == "idle" then + printers[currentPrinter].reset() + printers[currentPrinter].setLabel(config.printName) + printers[currentPrinter].setTooltip("Part " .. xShape .. "x" .. yShape .. " of " .. xShapeCount .. "x" .. yShapeCount) + if config.lightEmission.enabled then printers[currentPrinter].setLightLevel(config.lightEmission.level) end + + local jReplacer = shapeResolutionLimit + for j = 1, shapeResolutionLimit / 2 do + for i = 1, shapeResolutionLimit do + local xImage = xShape * shapeResolutionLimit - shapeResolutionLimit + i + local yImage = yShape * (shapeResolutionLimit / 2) - (shapeResolutionLimit / 2) + j + + if xImage <= image.getWidth(mainImage) and yImage <= image.getHeight(mainImage) then + local background, foreground, alpha, symbol = image.get(mainImage, xImage, yImage) + if alpha < 0xFF then + if symbol == " " then foreground = background end + addShapePixel(i, jReplacer, background, xImage, yImage * 2 - 1) + addShapePixel(i, jReplacer - 1, foreground, xImage, yImage * 2) + end + + GUI.progressBar(math.floor(buffer.getWidth() / 2 - 25), math.floor(buffer.getHeight() / 2), 50, 0x3366CC, 0xFFFFFF, 0xFFFFFF, math.ceil(counter * 100 / (xShapeCount * yShapeCount)), true, true, "Progress: ", "%"):draw() + buffer.draw() + -- else + -- error("Printing out of mainImage range") + end + end + + jReplacer = jReplacer - 2 + end + + if config.frame.enabled and not config.floorMode then + local xFrame, yFrame = shapeResolutionLimit * (image.getWidth(mainImage) % shapeResolutionLimit), shapeResolutionLimit * ((image.getHeight(mainImage) * 2) % shapeResolutionLimit) + xFrame = xShape == xShapeCount and (xFrame == 0 and 16 or xFrame) or 16 + yFrame = yShape == yShapeCount and (yFrame == 0 and 0 or yFrame) or 0 + + if xShape == 1 then printers[currentPrinter].addShape(0, yFrame, 14, config.frame.width, 16, 16, config.frame.material) end + if xShape == xShapeCount then printers[currentPrinter].addShape(xFrame - config.frame.width, yFrame, 14, xFrame, 16, 16, config.frame.material) end + + if yShape == 1 then printers[currentPrinter].addShape(0, 16 - config.frame.width, 14, xFrame, 16, 16, config.frame.material) end + if yShape == yShapeCount then printers[currentPrinter].addShape(0, yFrame, 14, xFrame, yFrame + config.frame.width, 16, config.frame.material) end + end + + printers[currentPrinter].commit() + + counter = counter + 1 + xShape = xShape + 1 + if xShape > xShapeCount then xShape = 1; yShape = yShape + 1 end + if yShape > yShapeCount then break end + end + + currentPrinter = currentPrinter + 1 + if currentPrinter > #printers then currentPrinter = 1 end + os.sleep(timeDelay) + end + + buffer.clear() + mainContainer:draw() + buffer.draw(true) +end + +----------------------------------------- Window-zaluped parasha ----------------------------------------- + +local function getStatus() + local xBlocks, yBlocks = math.ceil(image.getWidth(mainImage) / shapeResolutionLimit), math.ceil(image.getHeight(mainImage) * 2 / shapeResolutionLimit) + mainContainer.shadeContainer.statusTextBox.lines = { + "Image size: " .. image.getWidth(mainImage) .. "x" .. image.getHeight(mainImage) .. " px", + "Count of printers: " .. #printers, + "Print result: " .. xBlocks .. "x" .. yBlocks .. " blocks", + "Total count: " .. xBlocks * yBlocks .. " blocks" + } +end + +local function verticalLine(x, y, height, transparency) + for i = y, y + height - 1 do + local background = buffer.get(x, i) + buffer.set(x, i, background, color.blend(background, 0xFFFFFF, transparency), "│") + end +end + +local function horizontalLine(x, y, width, transparency) + for i = x, x + width - 1 do + local background, foreground, symbol = buffer.get(i, y) + buffer.set(i, y, background, color.blend(background, 0xFFFFFF, transparency), symbol == "│" and "┼" or "─") + end +end + +local function drawMainImageObject(object) + if mainImage then + local xImage = image.getWidth(mainImage) < buffer.getWidth() and math.floor(buffer.getWidth() / 2 - image.getWidth(mainImage) / 2) or 1 + local yImage = image.getHeight(mainImage) < buffer.getHeight() and math.floor(buffer.getHeight() / 2 - image.getHeight(mainImage) / 2) or 1 + buffer.image(xImage, yImage, mainImage) + GUI.windowShadow(xImage, yImage, image.getWidth(mainImage), image.getHeight(mainImage), 50, true) + if config.showGrid then + for x = xImage, xImage + image.getWidth(mainImage) - 1, shapeResolutionLimit do verticalLine(x, yImage, image.getHeight(mainImage), 0.627) end + for y = yImage, yImage + image.getHeight(mainImage) - 1, shapeResolutionLimit / 2 do horizontalLine(xImage, y, image.getWidth(mainImage), 0.627) end + buffer.text(1, 1, 0xBBBBBB, "хуй") + end + end +end + +local function createWindow() + mainContainer = GUI.fullScreenContainer() + mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0xEEEEEE)) + mainContainer:addChild(GUI.object(1, 1, mainContainer.width, mainContainer.height)).draw = drawMainImageObject + local textBoxesWidth = math.floor(panelWidth * 0.55) + + mainContainer.shadeContainer = mainContainer:addChild(GUI.container(mainContainer.width - panelWidth + 1, 1, panelWidth, mainContainer.height)) + mainContainer.shadeContainer:addChild(GUI.panel(1, 1, mainContainer.shadeContainer.width, mainContainer.shadeContainer.height, 0x0000000, 0.4)) + + local y = 2 + mainContainer.shadeContainer:addChild(GUI.label(1, y, mainContainer.shadeContainer.width, 1, 0xFFFFFF, "Main properties")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + + y = y + 2 + mainContainer.shadeContainer:addChild(GUI.label(3, y, mainContainer.shadeContainer.width, 1, 0xCCCCCC, "Image path:")) + local filesystemChooser = mainContainer.shadeContainer:addChild(GUI.filesystemChooser(mainContainer.shadeContainer.width - textBoxesWidth - 1, y, textBoxesWidth, 1, 0xEEEEEE, 0x262626, 0x444444, 0x999999, startImagePath, MineOSCore.localization.open, MineOSCore.localization.cancel, "Image path", "/")) + filesystemChooser:addExtensionFilter(".pic") + filesystemChooser.onSubmit = function(path) + mainImage = image.load(path) + getStatus() + mainContainer:draw() + buffer.draw() + end + + y = y + 2 + mainContainer.shadeContainer:addChild(GUI.label(3, y, mainContainer.shadeContainer.width, 1, 0xCCCCCC, "Material:")) + local mainMaterialTextBox = mainContainer.shadeContainer:addChild(GUI.input(mainContainer.shadeContainer.width - textBoxesWidth - 1, y, textBoxesWidth, 1, 0xEEEEEE, 0x555555, 0x555555, 0xEEEEEE, 0x262626, config.mainMaterial, nil, false)) + mainMaterialTextBox.onInputFinished = function() + config.mainMaterial = mainMaterialTextBox.text + save() + end + + y = y + 2 + mainContainer.shadeContainer:addChild(GUI.label(3, y, mainContainer.shadeContainer.width, 1, 0xCCCCCC, "Print name:")) + local printNameTextBox = mainContainer.shadeContainer:addChild(GUI.input(mainContainer.shadeContainer.width - textBoxesWidth - 1, y, textBoxesWidth, 1, 0xEEEEEE, 0x555555, 0x555555, 0xEEEEEE, 0x262626, config.printName, nil, false)) + printNameTextBox.onInputFinished = function() + config.printName = printNameTextBox.text + save() + end + + y = y + 2 + mainContainer.shadeContainer:addChild(GUI.label(3, y, mainContainer.shadeContainer.width, 1, 0xCCCCCC, "Floor mode:")) + local floorSwitch = mainContainer.shadeContainer:addChild(GUI.switch(mainContainer.shadeContainer.width - 9, y, 8, 0xFFDB40, 0xAAAAAA, 0xFFFFFF, config.floorMode)) + floorSwitch.onStateChanged = function() + config.floorMode = floorSwitch.state + save() + end + + y = y + 2 + mainContainer.shadeContainer:addChild(GUI.label(3, y, mainContainer.shadeContainer.width, 1, 0xCCCCCC, "Show grid:")) + local gridSwitch = mainContainer.shadeContainer:addChild(GUI.switch(mainContainer.shadeContainer.width - 9, y, 8, 0xFFDB40, 0xAAAAAA, 0xFFFFFF, config.showGrid)) + gridSwitch.onStateChanged = function() + config.showGrid = gridSwitch.state + save() + mainContainer:draw() + end + + y = y + 4 + mainContainer.shadeContainer:addChild(GUI.label(1, y, mainContainer.shadeContainer.width, 1, 0xFFFFFF, "Frame properties")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + y = y + 2 + mainContainer.shadeContainer:addChild(GUI.label(3, y, mainContainer.shadeContainer.width, 1, 0xCCCCCC, "Enabled:")) + local frameSwitch = mainContainer.shadeContainer:addChild(GUI.switch(mainContainer.shadeContainer.width - 9, y, 8, 0xFFDB40, 0xAAAAAA, 0xFFFFFF, config.frame.enabled)) + frameSwitch.onStateChanged = function() + config.frame.enabled = frameSwitch.state + save() + end + y = y + 2 + mainContainer.shadeContainer:addChild(GUI.label(3, y, mainContainer.shadeContainer.width, 1, 0xCCCCCC, "Material:")) + local frameMaterialTextBox = mainContainer.shadeContainer:addChild(GUI.input(mainContainer.shadeContainer.width - textBoxesWidth - 1, y, textBoxesWidth, 1, 0xEEEEEE, 0x555555, 0x555555, 0xEEEEEE, 0x262626, config.frame.material, nil, false)) + frameMaterialTextBox.onInputFinished = function() + config.frame.material = frameMaterialTextBox.text + save() + end + + y = y + 2 + local frameWidthSlider = mainContainer.shadeContainer:addChild(GUI.slider(3, y, mainContainer.shadeContainer.width - 4, 0xFFDB80, 0x000000, 0xFFDB40, 0xCCCCCC, 1, shapeResolutionLimit - 1, config.frame.width, false, "Width: " , " voxel(s)")) + frameWidthSlider.onValueChanged = function() + config.frame.width = frameWidthSlider.value + save() + end + frameWidthSlider.roundValues = true + + y = y + 5 + mainContainer.shadeContainer:addChild(GUI.label(1, y, mainContainer.shadeContainer.width, 1, 0xFFFFFF, "Light emission")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + y = y + 2 + mainContainer.shadeContainer:addChild(GUI.label(3, y, mainContainer.shadeContainer.width, 1, 0xCCCCCC, "Enabled:")) + local lightSwitch = mainContainer.shadeContainer:addChild(GUI.switch(mainContainer.shadeContainer.width - 9, y, 8, 0xFFDB40, 0xAAAAAA, 0xFFFFFF, config.lightEmission.enabled)) + lightSwitch.onStateChanged = function() + config.lightEmission.enabled = true + save() + end + + y = y + 2 + local lightSlider = mainContainer.shadeContainer:addChild(GUI.slider(3, y, mainContainer.shadeContainer.width - 4, 0xFFDB80, 0x000000, 0xFFDB40, 0xCCCCCC, 1, 8, 8, false, "Radius: " , " block(s)")) + lightSlider.roundValues = true + lightSlider.onValueChanged = function() + config.lightEmission.value = lightSlider.value + save() + end + + y = y + 5 + mainContainer.shadeContainer:addChild(GUI.label(1, y, mainContainer.shadeContainer.width, 1, 0xFFFFFF, "Summary information:")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + y = y + 2 + mainContainer.shadeContainer.statusTextBox = mainContainer.shadeContainer:addChild(GUI.textBox(3, y, mainContainer.shadeContainer.width - 4, 5, nil, 0xCCCCCC, {}, 1)):setAlignment(GUI.alignment.horizontal.left, GUI.alignment.vertical.top) + + mainContainer.shadeContainer:addChild(GUI.button(1, mainContainer.shadeContainer.height - 5, mainContainer.shadeContainer.width, 3, 0x363636, 0xFFFFFF, 0xFFFFFF, 0x262626, "Exit")).onTouch = function() + mainContainer:stopEventHandling() + end + + mainContainer.shadeContainer:addChild(GUI.button(1, mainContainer.shadeContainer.height - 2, mainContainer.shadeContainer.width, 3, 0x262626, 0xFFFFFF, 0xFFFFFF, 0x262626, "Start print")).onTouch = function() + beginPrint() + end + + mainContainer.eventHandler = function(mainContainer, object, eventData) + if (eventData[1] == "component_added" or eventData[1] == "component_removed") and eventData[3] == "printer3d" then + getPrinters() + getStatus() + mainContainer:draw() + buffer.draw() + end + end +end + +----------------------------------------- Shitty meatball rolls ----------------------------------------- + +buffer.flush() +load() +getPrinters() +createWindow() +mainImage = image.load(startImagePath) +getStatus() +mainContainer:draw() +buffer.draw() + +mainContainer:startEventHandling() + + + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/PrintImage.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/PrintImage.app/Resources/Icon.pic new file mode 100755 index 00000000..f28c8154 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/PrintImage.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/QuantumCube.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/QuantumCube.app/Main.lua new file mode 100755 index 00000000..726b160e --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/QuantumCube.app/Main.lua @@ -0,0 +1,442 @@ +local os = require("os") +local term = require("term") +local event = require("event") +local component = require("component") +local gpu = component.gpu +math.randomseed(os.time()) +local version = "Cube v1.0" +local level = {} +local doors = {} +local indicator={} +local nick_player +local markColor = {0xff0000, 0xffff00, 0x00ff00, 0x00ffff, 0x0000ff, 0xff00ff, 0xffffff} +local playerColor = 3 +local sx,sy = gpu.getResolution() +sx, sy = math.modf(sx/4), math.modf(sy/2) -- точка отступа/координата игрока на экране (статичные)/центр событий +local px,py = 3,3 -- относительные координаты игрока в комнате +local min_map, max_map = 1, 1000 -- ограничители номеров комнат, чтобы сильно не запутаться при прохождении +level[1] = {number=1, color = 0xffffff, mark=false} -- цель игры - попасть в эту комнату +------------------------------------------------------------------------------------- +----------------------- Генерация случайных формул для дверей ----------------------- +local rand_1, rand_2 ,rand_3, rand_4 +while true do + rand_1, rand_2 ,rand_3, rand_4 = math.random(1,2), math.random(10,30), math.random(1,2), math.random(10,30) + if rand_1~=rand_3 and rand_2~=rand_4 then break end +end +formula={} +formula[1]=function(n) return n*rand_1 + rand_2 end +formula[2]=function(n) return n*rand_3 + rand_4 end +formula[-1]=function(n) return (n - rand_2)/rand_1 end +formula[-2]=function(n) return (n - rand_4)/rand_3 end +------------------------------------------------------------------------------------- +---------------------- Возвращает или генерирует новую комнату ---------------------- +function gen_level(i) + i = tonumber(i) + if not level[i] then + level[i]={number=i, color = math.random(0x000000, 0xffffff), mark=false} + end + return level[i] +end +------------------------------------------------------------------------------------- +-------------------------- Проверка, существует ли комната -------------------------- +function proverka(x,y) -- где x номер формулы, y номер текущей комнаты + local number = formula[x](y) + return number >= min_map and number <= max_map and number == math.modf(number) +end +------------------------------------------------------------------------------------- +---------------------------- Генерация статистики комнат ---------------------------- +function sorting(sorting_table, not_sorting_table) + local trash_table={} + while true do + if #not_sorting_table==0 then + break + else + local new_level = not_sorting_table[1] + local power = true + for i=1, #sorting_table do + if sorting_table[i][1]== new_level[1] then + power = false + if new_level[2] < sorting_table[i][2] then + sorting_table[i][2]=new_level[2] + if proverka(1,new_level[1]) then + trash_table[#trash_table+1] = {formula[1](new_level[1]), new_level[2]+1} + end + if proverka(2,new_level[1]) then + trash_table[#trash_table+1] = {formula[2](new_level[1]), new_level[2]+1} + end + if proverka(-1,new_level[1]) then + trash_table[#trash_table+1] = {formula[-1](new_level[1]), new_level[2]+1} + end + if proverka(-2,new_level[1]) then + trash_table[#trash_table+1] = {formula[-2](new_level[1]), new_level[2]+1} + end + end + table.remove(not_sorting_table,1) + end + end + if power then + sorting_table[#sorting_table+1] = new_level + table.remove(not_sorting_table,1) + if proverka(1,new_level[1]) then + not_sorting_table[#not_sorting_table+1] = {formula[1](new_level[1]), new_level[2]+1} + end + if proverka(2,new_level[1]) then + not_sorting_table[#not_sorting_table+1] = {formula[2](new_level[1]), new_level[2]+1} + end + if proverka(-1,new_level[1]) then + not_sorting_table[#not_sorting_table+1] = {formula[-1](new_level[1]), new_level[2]+1} + end + if proverka(-2,new_level[1]) then + not_sorting_table[#not_sorting_table+1] = {formula[-2](new_level[1]), new_level[2]+1} + end + end + end + end + return sorting_table, trash_table +end + +-- первая сортировка +local not_sorting_tb, trash_tb={} +not_sorting_tb[1]={1,0} +local sorting_tb, trash_tb = sorting({}, not_sorting_tb) + +-- последующие сортировки +while true do + not_sorting_tb = trash_tb + sorting_tb, trash_tb = sorting(sorting_tb, not_sorting_tb) + if #trash_tb == 0 then break end +end + +-- очищаем память +not_sorting_tb, trash_tb = nil, nil + +-- перестраиваем таблицу +local stat_table={} +for i=1, #sorting_tb do + stat_table[sorting_tb[i][1]]=sorting_tb[i][2] +end +------------------------------------------------------------------------------------- +------------------ Находим номер самой удалённой комнаты от выхода ------------------ +local j=1 +for i=1, #sorting_tb do + if sorting_tb[i][2]>sorting_tb[j][2] then + j=i + end +end +------------------------------------------------------------------------------------- +----------------------- Устанавливаем номер стартовой комнаты ----------------------- +local chamber = gen_level(sorting_tb[j][1]) + +-- запишем количество комнат в игре +local max_table, max_level = #sorting_tb, sorting_tb[j][2] + +-- удалим из памяти ненужную таблицу +sorting_tb = nil +------------------------------------------------------------------------------------- +--------------------------- Переставляет двери в комнате ---------------------------- +function reload_doors() + local rezerv={} + for i=1,4 do -- занесём двери в базу данных, чтобы знать использованные формулы + if doors[i] then + rezerv[#rezerv+1]=doors[i] + end + end + for i=1,4 do -- перебираем все 4 двери + if not doors[i] then + while true do + local rand = math.random(-2,2) + local rezerv_2 = 0 + if rand ~= 0 then + if #rezerv > 0 then -- проверка, есть ли комната с такой же формулой + for j=1, #rezerv do + if rezerv[j] == rand then break else rezerv_2 = rezerv_2 + 1 end + end + end + if rezerv_2 == #rezerv then -- если нет повторяющихся формул, то присваивается данная формула + doors[i] = rand + rezerv[#rezerv+1]=rand + break + end + end + end + end + end +end +-- //данная функция достаточно сложна чтобы запутаться +------------------------------------------------------------------------------------- +---------------------------------- Рисования меток ---------------------------------- +function mark_print(nx, ny, number) + if level[number].mark then + for i=1, #level[number].mark do + gpu.setBackground(level[number].mark[i][3]) + gpu.set((level[number].mark[i][1]+nx)*2, level[number].mark[i][2]+ny, " ") + end + end +end +------------------------------------------------------------------------------------- +------------------------- Рисования комнаты по координатам -------------------------- +function level_print(nx, ny, color, number) + number = tostring(number) + gpu.setBackground(color) + gpu.set(nx*2, ny, " ") + gpu.set((nx+4)*2, ny, " ") + gpu.set(nx*2, ny+6, " ") + gpu.set((nx+4)*2, ny+6, " ") + + gpu.set(nx*2, ny+1, " ") + gpu.set(nx*2, ny+2, " ") + gpu.set(nx*2, ny+4, " ") + gpu.set(nx*2, ny+5, " ") + gpu.set((nx+6)*2, ny+1, " ") + gpu.set((nx+6)*2, ny+2, " ") + gpu.set((nx+6)*2, ny+4, " ") + gpu.set((nx+6)*2, ny+5, " ") + + gpu.setBackground(0x000000) + gpu.set(nx*2+6-math.modf((string.len(number)-1)/2), ny+3, number) +end +------------------------------------------------------------------------------------- +----------------------------- Переходы между комнатами ------------------------------ +pxx, pyy = {}, {} +pxx[-1]=function(nx) + local rezerv_3 = doors[1] + if proverka(rezerv_3, chamber.number) then + doors={} + doors[2] = -rezerv_3 + reload_doors() + chamber = gen_level(formula[rezerv_3](chamber.number)) + ppx = 6 + else + ppx = px + end +end +pxx[7]=function(nx) + local rezerv_3 = doors[2] + if proverka(rezerv_3, chamber.number) then + doors={} + doors[1] = -rezerv_3 + reload_doors() + chamber = gen_level(formula[rezerv_3](chamber.number)) + ppx = 0 + else + ppx = px + end +end +pyy[-1]=function(ny) + local rezerv_3 = doors[3] + if proverka(rezerv_3, chamber.number) then + doors={} + doors[4] = -rezerv_3 + reload_doors() + chamber = gen_level(formula[rezerv_3](chamber.number)) + ppy = 6 + else + ppy = py + end +end +pyy[7]=function(ny) + local rezerv_3 = doors[4] + if proverka(rezerv_3, chamber.number) then + doors={} + doors[3] = -rezerv_3 + reload_doors() + chamber = gen_level(formula[rezerv_3](chamber.number)) + ppy = 0 + else + ppy = py + end +end +-- //работает как надо, но лучше подредактировать +------------------------------------------------------------------------------------- +-------------------------------- Передвижение игрока -------------------------------- +function player_update(nx,ny) + ppx, ppy = px+nx, py+ny + if not ((ppx==0 or ppy==0 or ppx==6 or ppy==6) and ppx~=3 and ppy~=3) then + if pxx[ppx] then pxx[ppx](ppx) + elseif pyy[ppy] then pyy[ppy](ppy) + end + px,py = ppx,ppy + end +end +-- //работает как надо, но лучше подредактировать +------------------------------------------------------------------------------------- +--------------------------------- Блок отображения ---------------------------------- +function update(nick) + nick_player = nick + term.clear() + + -- текущая комната + gen_level(chamber.number) + mark_print(sx-px,sy-py, chamber.number) + level_print(sx-px,sy-py,chamber.color, chamber.number) + + -- комната слева + if proverka(doors[1], chamber.number) and px==0 then + local number = formula[doors[1]](chamber.number) + gen_level(number) + mark_print(sx-7-px,sy-py, number) + level_print(sx-7-px,sy-py,gen_level(formula[doors[1]](chamber.number)).color, gen_level(formula[doors[1]](chamber.number)).number) + end + + -- комната справа + if proverka(doors[2], chamber.number) and px==6 then + local number = formula[doors[2]](chamber.number) + gen_level(number) + mark_print(sx+7-px,sy-py, number) + level_print(sx+7-px,sy-py,gen_level(formula[doors[2]](chamber.number)).color, gen_level(formula[doors[2]](chamber.number)).number) + end + + -- комната сверху + if proverka(doors[3], chamber.number) and py==0 then + local number = formula[doors[3]](chamber.number) + gen_level(number) + mark_print(sx-px,sy-7-py, number) + level_print(sx-px,sy-7-py,gen_level(formula[doors[3]](chamber.number)).color, gen_level(formula[doors[3]](chamber.number)).number) + end + + -- комната снизу + if proverka(doors[4], chamber.number) and py==6 then + local number = formula[doors[4]](chamber.number) + gen_level(number) + mark_print(sx-px,sy+7-py, number) + level_print(sx-px,sy+7-py,gen_level(formula[doors[4]](chamber.number)).color, number) + end + + -- отображение игрока + gpu.setBackground(0xff0000) + gpu.set(sx*2, sy, " ") + + -- текстовые индикаторы + for i=1, #indicator do + indicator[i]() + end + + -- индикатор выбранного цвета + gpu.setBackground(markColor[playerColor]) + gpu.set(2, sy*2, " ") +end +------------------------------------------------------------------------------------- +---------------------------------- Блок управления ---------------------------------- +local command={} +command[200]=function() player_update(0,-1) end -- вверх +command[208]=function() player_update(0,1) end -- вниз +command[203]=function() player_update(-1,0) end -- влево +command[205]=function() player_update(1,0) end -- вправо +command[17]=function() -- ставить метку + if not level[chamber.number].mark then level[chamber.number].mark={} end + level[chamber.number].mark[#level[chamber.number].mark+1]={px,py,markColor[playerColor]} + end +command[30]=function() if playerColor-1<1 then playerColor=#markColor else playerColor=playerColor-1 end end -- цвет слева +command[32]=function() if playerColor+1>#markColor then playerColor=1 else playerColor=playerColor+1 end end -- цвет справа +command[31]=function() -- удалить метку + if level[chamber.number].mark then + for i=#level[chamber.number].mark, 1, -1 do + if px==level[chamber.number].mark[i][1] and py==level[chamber.number].mark[i][2] then + table.remove(level[chamber.number].mark,i) + end + end + end + end +command[23]=function() -- включает режим разработчика + if #indicator==0 then + indicator[1]=function() + gpu.setBackground(0x000000) + gpu.setForeground(0xffff00) + gpu.set(2, 2, "max level: "..max_level) + gpu.set(2, 3, "all levels: "..max_table) + gpu.set(2, 4, "this level: "..stat_table[chamber.number]) + gpu.setForeground(0xff0000) + gpu.set(2, 5, "formula 1: ".."n".."*"..rand_1.." + "..rand_2) + gpu.set(2, 6, "formula 2: ".."n".."*"..rand_3.." + "..rand_4) + gpu.set(2, 7, "formula -1: ".."(n - "..rand_2..")/"..rand_1) + gpu.set(2, 8, "formula -2: ".."(n - "..rand_4..")/"..rand_3) + gpu.setForeground(0xff00ff) + gpu.set(2, 9, "progress: " .. math.modf(100-stat_table[chamber.number]*100/max_level).."%") + gpu.setForeground(0xff00ff) + gpu.set(2, 10, "color: "..playerColor) + gpu.setForeground(0xffffff) + end + else + table.remove(indicator,1) + end +end +command[35]=function() -- отобразить управление + term.clear() + gpu.setForeground(0xff0000) + print(version) + print("") + gpu.setForeground(0x00ff00) + print("Target: searching chamber 1") + print("Game 100% passable") + gpu.setForeground(0xffff00) + print("Control:") + print("Q - exit game") + print("H - help") + print("I - info") + print("W - set mark") + print("S - remove mark") + print("A - back color mark") + print("D - next color mark") + print("") + gpu.setForeground(0xffffff) + print("press enter to continue...") + while true do + _,_,_, key = event.pull("key_down") + if key == 28 then + break + end + end +end +------------------------------------------------------------------------------------- +---------------------- Показываем управление до начала игры ------------------------- +command[35]() +------------------------------------------------------------------------------------- +------------------------- Отображение комнат до начала игры ------------------------- +reload_doors() +update(nick) +gpu.setBackground(0x000000) +------------------------------------------------------------------------------------- +------------------------------------- Тело игры ------------------------------------- +while true do + _,_,_, key, nick = event.pull("key_down") + if key==16 then + term.clear() + gpu.setForeground(0xff0000) + print("Exit to game?") + gpu.setForeground(0xffffff) + print("") + print("y/n") + while true do + _,_,_, key = event.pull("key_down") + if key == 21 then + term.clear() + return + elseif key == 49 then + break + end + end + elseif command[key] then + command[key]() + end + update(nick) + gpu.setBackground(0x000000) + if chamber.number == 1 then break end -- цель игры, комната с этим номером + os.sleep(1/15) -- задержка, для более удобного управления +end +------------------------------------------------------------------------------------- +------------------------------------- Прощание ------------------------------------- +term.clear() +gpu.setForeground(0x00ff00) +print("Congratulations "..nick_player.."!") +print("You win!") +print("") +gpu.setForeground(0xffffff) +print("press enter to exit...") +while true do + _,_,_, key = event.pull("key_down") + if key == 28 then + break + end +end +term.clear() +------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/QuantumCube.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/QuantumCube.app/Resources/About/Russian.txt new file mode 100755 index 00000000..5afb8118 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/QuantumCube.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Это мини-игра, разработанная товарищем qwertyMan с форума ComputerCraft.ru. А я ее нагло спиздил. Цель игры: вы должны понять, как устроен "квантовый куб", решить задачу (найти цепочку выходов) к комнате номер 1 и выбраться из квантового лабиринта. А на деле рандомно бегать в поисках комнаты номер 1, не понимать как устроена система нумераций, ловить баттхёрты и проклинать всех, кого только можно. Потому что если даже соседняя комната и окажется под номером 1, то вы можете запросто пробежать и даже не заглянуть в неё. Так как мы видим лишь те комнаты, на границе с которыми стоим. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/QuantumCube.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/QuantumCube.app/Resources/Icon.pic new file mode 100755 index 00000000..a6643e54 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/QuantumCube.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Radio.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Radio.app/Main.lua new file mode 100755 index 00000000..bae826e0 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Radio.app/Main.lua @@ -0,0 +1,314 @@ + +-- package.loaded.bigLetters = nil +local event = require("event") +local buffer = require("doubleBuffering") +local bigLetters = require("bigLetters") +local unicode = require("unicode") +local component = require("component") +local fs = require("filesystem") +local context = require("context") +local serialization = require("serialization") +local ecs = require("ECSAPI") +local radio + +if not component.isAvailable("openfm_radio") then + ecs.error("Этой программе требуется радио из мода OpenFM. Причем не на всех версиях еще работает, автор мода - пидор! Проверял на ноябрьской, полет нормальный.") + return +else + radio = component.openfm_radio +end + +local pathToSaveStations = "MineOS/System/Radio/Stations.cfg" +local stationNameLimit = 8 +local spaceBetweenStations = 8 +local countOfStationsLimit = 9 +local lineHeight + +local config = { + colors = { + background = 0x1b1b1b, + line = 0xFFFFFF, + lineShadow = 0x000000, + activeStation = 0xFFA800, + otherStation = 0xBBBBBB, + bottomToolBarDefaultColor = 0xaaaaaa, + bottomToolBarCurrentColor = 0xFFA800, + }, +} + +local radioStations = { + currentStation = 3, + { + name = "Galnet Soft", + url = "http://galnet.ru:8000/soft" + }, + { + name = "Европа Плюс", + url = "http://ep256.streamr.ru" + }, + { + name = "L-Radio", + url = "http://server2.lradio.ru:8000/lradio64.aac.m3u" + }, + { + name = "Radio Record", + url = "http://online.radiorecord.ru:8101/rr_128.m3u" + }, + { + name = "Moscow FM", + url = "http://livestream.rfn.ru:8080/moscowfmen128.m3u" + }, +} + +--Объекты для тача +local obj = {} + +local function drawStation(x, y, name, color) + bigLetters.drawText(x, y, color, name) +end + +local function drawLine() + local x = math.floor(buffer.getWidth() / 2) + for i = 1, lineHeight do + buffer.text(x + 1, i, config.colors.lineShadow, "▎") + buffer.text(x, i, config.colors.line, "▍") + end +end + +local function drawLeftArrow(x, y, color) + local bg, fg = config.colors.background, color + local arrow = { + { {bg, fg, " "}, {bg, fg, " "}, {bg, fg, "*"} }, + { {bg, fg, " "}, {bg, fg, "*"}, {bg, fg, " "} }, + { {bg, fg, "*"}, {bg, fg, " "}, {bg, fg, " "} }, + { {bg, fg, " "}, {bg, fg, "*"}, {bg, fg, " "} }, + { {bg, fg, " "}, {bg, fg, " "}, {bg, fg, "*"} }, + } + buffer.customImage(x, y, arrow) +end + +local function drawRightArrow(x, y, color) + local bg, fg = config.colors.background, color + local arrow = { + { {bg, fg, "*"}, {bg, fg, " "}, {bg, fg, " "} }, + { {bg, fg, " "}, {bg, fg, "*"}, {bg, fg, " "} }, + { {bg, fg, " "}, {bg, fg, " "}, {bg, fg, "*"} }, + { {bg, fg, " "}, {bg, fg, "*"}, {bg, fg, " "} }, + { {bg, fg, "*"}, {bg, fg, " "}, {bg, fg, " "} }, + } + buffer.customImage(x, y, arrow) +end + +local function drawMenu() + local width = 36 + (3 * 2 + 2) * #radioStations + local x, y = math.floor(buffer.getWidth() / 2 - width / 2), lineHeight + math.floor((buffer.getHeight() - lineHeight) / 2 - 1) + + obj.gromkostPlus = {x, y, x + 4, y + 3} + x = bigLetters.drawText(x, y, config.colors.bottomToolBarDefaultColor, "+", "*") + 1 + x = x + 1 + + obj.strelkaVlevo = {x, y, x + 4, y + 3} + drawLeftArrow(x, y, config.colors.bottomToolBarDefaultColor); x = x + 5 + x = x + 3 + + local color + for i = 1, #radioStations do + if i == radioStations.currentStation then color = config.colors.bottomToolBarCurrentColor else color = config.colors.bottomToolBarDefaultColor end + x = bigLetters.drawText(x, y, color, tostring(i), "*") + 1 + end + + x = x + 2 + obj.strelkaVpravo = {x, y, x + 4, y + 3} + drawRightArrow(x, y, config.colors.bottomToolBarDefaultColor) + + x = x + 8 + obj.gromkostMinus = {x, y, x + 4, y + 3} + x = bigLetters.drawText(x, y, config.colors.bottomToolBarDefaultColor, "-", "*") + 1 +end + +local function drawStations() + local prevWidth, currentWidth, nextWidth, name + + -- Текущая станция + name = ecs.stringLimit("end", unicode.lower(radioStations[radioStations.currentStation].name), stationNameLimit, true) + currentWidth = bigLetters.getTextSize(name) + local x, y = math.floor(buffer.getWidth() / 2 - currentWidth / 2), math.floor(buffer.getHeight() / 2 - 3) + drawStation(x, y, name, config.colors.activeStation) + + -- Предедущая + if radioStations[radioStations.currentStation - 1] then + name = ecs.stringLimit("start", unicode.lower(radioStations[radioStations.currentStation - 1].name), stationNameLimit) + prevWidth = bigLetters.getTextSize(name) + drawStation(x - prevWidth - spaceBetweenStations, y, name, config.colors.otherStation) + end + + -- Следующая + if radioStations[radioStations.currentStation + 1] then + name = ecs.stringLimit("end", unicode.lower(radioStations[radioStations.currentStation + 1].name), stationNameLimit) + nextWidth = bigLetters.getTextSize(name) + drawStation(x + currentWidth + spaceBetweenStations + 1, y, name, config.colors.otherStation) + end + -- ecs.error(x, x - prevWidth - spaceBetweenStations, prevWidth, currentWidth, nextWidth) +end + +local function drawAll() + -- Коррекция от кривых ручонок юзверей + if radioStations.currentStation < 1 then + radioStations.currentStation = 1 + elseif radioStations.currentStation > #radioStations then + radioStations.currentStation = #radioStations + end + + buffer.square(1, 1, buffer.getWidth(), buffer.getHeight(), config.colors.background, 0xFFFFFF, " ") + + drawStations() + drawLine() + drawMenu() + + buffer.draw() +end + +local function saveStations() + fs.makeDirectory(fs.path(pathToSaveStations)) + local file = io.open(pathToSaveStations, "w") + file:write(serialization.serialize(radioStations)) + file:close() +end + +local function loadStations() + if fs.exists(pathToSaveStations) then + local file = io.open(pathToSaveStations, "r") + radioStations = serialization.unserialize(file:read("*a")) + file:close() + else + saveStations() + end +end + +local function switchStation(i) + if i == 1 then + if radioStations.currentStation < #radioStations then + radioStations.currentStation = radioStations.currentStation + 1 + saveStations() + radio.stop() + radio.setURL(radioStations[radioStations.currentStation].url) + radio.start() + end + else + if radioStations.currentStation > 1 then + radioStations.currentStation = radioStations.currentStation - 1 + saveStations() + radio.stop() + radio.setURL(radioStations[radioStations.currentStation].url) + radio.start() + end + end +end + +local function volume(i) + if i == 1 then + radio.volUp() + else + radio.volDown() + end +end + + +buffer.flush() +lineHeight = math.floor(buffer.getHeight() * 0.7) +loadStations() +radio.stop() +radio.setURL(radioStations[radioStations.currentStation].url) +radio.start() +drawAll() + +while true do + local e = {event.pull()} + if e[1] == "touch" then + if e[5] == 0 then + if ecs.clickedAtArea(e[3], e[4], obj.strelkaVlevo[1], obj.strelkaVlevo[2], obj.strelkaVlevo[3], obj.strelkaVlevo[4]) then + drawLeftArrow(obj.strelkaVlevo[1], obj.strelkaVlevo[2], config.colors.bottomToolBarCurrentColor) + buffer.draw() + os.sleep(0.2) + switchStation(-1) + drawAll() + elseif ecs.clickedAtArea(e[3], e[4], obj.strelkaVpravo[1], obj.strelkaVpravo[2], obj.strelkaVpravo[3], obj.strelkaVpravo[4]) then + drawRightArrow(obj.strelkaVpravo[1], obj.strelkaVpravo[2], config.colors.bottomToolBarCurrentColor) + buffer.draw() + os.sleep(0.2) + switchStation(1) + drawAll() + elseif ecs.clickedAtArea(e[3], e[4], obj.gromkostPlus[1], obj.gromkostPlus[2], obj.gromkostPlus[3], obj.gromkostPlus[4]) then + bigLetters.drawText(obj.gromkostPlus[1], obj.gromkostPlus[2], config.colors.bottomToolBarCurrentColor, "+", "*" ) + buffer.draw() + volume(1) + os.sleep(0.2) + drawAll() + elseif ecs.clickedAtArea(e[3], e[4], obj.gromkostMinus[1], obj.gromkostMinus[2], obj.gromkostMinus[3], obj.gromkostMinus[4]) then + bigLetters.drawText(obj.gromkostMinus[1], obj.gromkostMinus[2], config.colors.bottomToolBarCurrentColor, "-", "*" ) + buffer.draw() + volume(-1) + os.sleep(0.2) + drawAll() + end + else + local action = context.menu(e[3], e[4], {"Добавить станцию", #radioStations >= countOfStationsLimit}, {"Удалить станцию", #radioStations < 2}, "-", {"О программе"}, "-", {"Выход"}) + if action == "Добавить станцию" then + local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "Добавить станцию"}, + {"EmptyLine"}, + {"Input", 0xFFFFFF, ecs.colors.orange, "Название станции"}, + {"Input", 0xFFFFFF, ecs.colors.orange, "URL-ссылка на стрим"}, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0x262626, "OK"}, {0x999999, 0xffffff, "Отмена"}} + ) + if data[3] == "OK" then + table.insert(radioStations, {name = data[1], url = data[2]}) + saveStations() + drawAll() + end + elseif action == "Удалить станцию" then + table.remove(radioStations, radioStations.currentStation) + saveStations() + drawAll() + + elseif action == "О программе" then + ecs.universalWindow("auto", "auto", 36, 0x262626, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "Radio v1.0"}, + {"EmptyLine"}, + {"CenterText", 0xFFFFFF, "Автор:"}, + {"CenterText", 0xBBBBBB, "Тимофеев Игорь"}, + {"CenterText", 0xBBBBBB, "vk.com/id7799889"}, + {"EmptyLine"}, + {"CenterText", 0xFFFFFF, "Тестер:"}, + {"CenterText", 0xBBBBBB, "Олег Гречкин"}, + {"CenterText", 0xBBBBBB, "http://vk.com/id250552893"}, + {"EmptyLine"}, + {"CenterText", 0xFFFFFF, "Автор идеи:"}, + {"CenterText", 0xBBBBBB, "MrHerobrine с Dreamfinity"}, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0xffffff, "OK"}} + ) + elseif action == "Выход" then + buffer.square(1, 1, buffer.getWidth(), buffer.getHeight(), config.colors.background, 0xFFFFFF, " ") + buffer.draw() + ecs.prepareToExit() + radio.stop() + return + end + end + + elseif e[1] == "scroll" then + switchStation(e[5]) + drawAll() + end +end + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Radio.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Radio.app/Resources/About/Russian.txt new file mode 100755 index 00000000..e96c4609 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Radio.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Программа для управления радио из мода OpenFM, стилизованная под известный плеер iRiver SPINN. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Radio.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Radio.app/Resources/Icon.pic new file mode 100755 index 00000000..c5f17e38 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Radio.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Main.lua new file mode 100755 index 00000000..691c621a --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Main.lua @@ -0,0 +1,200 @@ + +package.loaded.rayEngine = nil + +local fs = require("filesystem") +local component = require("component") +local buffer = require("doubleBuffering") +local GUI = require("GUI") +local rayEngine = require("rayEngine") +local MineOSCore = require("MineOSCore") +local unicode = require("unicode") +local event = require("event") + +---------------------------------------------------------------------------------------------------------------------------------- + +local applicationResourcesDirectory = MineOSCore.getCurrentApplicationResourcesDirectory() +local localization = MineOSCore.getLocalization(applicationResourcesDirectory .. "Localization/") +local worldsPath = applicationResourcesDirectory .. "Worlds/" +local rayWalkVersion = "RayWalk Tech Demo v3.5" + +---------------------------------------------------------------------------------------------------------------------------------- + +local function menuBackground() + rayEngine.drawWorld() + buffer.clear(0x000000, 0.5) +end + +local function settings() + local window = GUI.fullScreenContainer() + local oldDraw = window.draw + window.draw = function() + menuBackground() + oldDraw(window) + end + + local sliderWidth, textBoxWidth = 43, 19 + local x, y = math.floor(window.width / 2 - sliderWidth / 2), math.floor(window.height / 2 - 19) + + window:addChild(GUI.label(1, y, window.width, 1, 0xFFFFFF, localization.rayEngineProperties)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 3 + + local resolutionTextBoxWidth = window:addChild(GUI.input(x, y, textBoxWidth, 3, 0x262626, 0xBBBBBB, 0xBBBBBB, 0x262626, 0xFFFFFF, tostring(buffer.getWidth()), nil, true)) + window:addChild(GUI.label(x + textBoxWidth + 2, y + 1, 1, 1, 0xFFFFFF, "X")) + local resolutionTextBoxHeight = window:addChild(GUI.input(x + textBoxWidth + 5, y, textBoxWidth, 3, 0x262626, 0xBBBBBB, 0xBBBBBB, 0x262626, 0xFFFFFF, tostring(buffer.getHeight()), nil, true)); y = y + 4 + window:addChild(GUI.label(1, y, window.width, 1, 0xDDDDDD, localization.screenResolution)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 3 + resolutionTextBoxWidth.validator = function(text) local num = tonumber(text); if num and num >= 40 and num <= 160 then return true end end + resolutionTextBoxHeight.validator = function(text) local num = tonumber(text); if num and num >= 12 and num <= 50 then return true end end + local function onAnyResolutionTextBoxInputFinished() + window:stopEventHandling() + rayEngine.changeResolution(tonumber(resolutionTextBoxWidth.text), tonumber(resolutionTextBoxHeight.text)) + settings() + end + resolutionTextBoxWidth.onInputFinished = onAnyResolutionTextBoxInputFinished + resolutionTextBoxHeight.onInputFinished = onAnyResolutionTextBoxInputFinished + + local drawDistanceSlider = window:addChild(GUI.slider(x, y, sliderWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xDDDDDD, 100, 5000, rayEngine.properties.drawDistance, true, localization.drawDistance)) + drawDistanceSlider.onValueChanged = function() + rayEngine.properties.drawDistance = drawDistanceSlider.value + window:draw() + buffer.draw() + end; y = y + 4 + + local shadingDistanceSlider = window:addChild(GUI.slider(x, y, sliderWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xDDDDDD, 100, 3000, rayEngine.properties.shadingDistance, true, localization.shadingDistance)) + shadingDistanceSlider.onValueChanged = function() + rayEngine.properties.shadingDistance = shadingDistanceSlider.value + window:draw() + buffer.draw() + end; y = y + 4 + + local shadingCascadesSlider = window:addChild(GUI.slider(x, y, sliderWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xDDDDDD, 2, 48, rayEngine.properties.shadingCascades, true, localization.shadingCascades)) + shadingCascadesSlider.onValueChanged = function() + rayEngine.properties.shadingCascades = shadingCascadesSlider.value + window:draw() + buffer.draw() + end; y = y + 4 + + local raycastQualitySlider = window:addChild(GUI.slider(x, y, sliderWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xDDDDDD, 0.5, 32, rayEngine.properties.raycastQuality, true, localization.raycastQuality)) + raycastQualitySlider.onValueChanged = function() + rayEngine.properties.raycastQuality = raycastQualitySlider.value + window:draw() + buffer.draw() + end; y = y + 4 + + local currentTimeSlider = window:addChild(GUI.slider(x, y, sliderWidth, rayEngine.world.colors.sky.current, 0x000000, rayEngine.world.colors.sky.current, 0xDDDDDD, 0, rayEngine.world.dayNightCycle.length, rayEngine.world.dayNightCycle.currentTime, true, localization.dayNightCycle, localization.seconds)) + currentTimeSlider.onValueChanged = function() + rayEngine.world.dayNightCycle.currentTime = currentTimeSlider.value + rayEngine.refreshTimeDependentColors() + currentTimeSlider.colors.active = rayEngine.world.colors.sky.current + currentTimeSlider.colors.pipe = rayEngine.world.colors.sky.current + window:draw() + buffer.draw() + end; y = y + 4 + + window:addChild(GUI.label(x, y, sliderWidth, 1, 0xDDDDDD, localization.enableSemipixelRenderer)) + + local graphonSwitch = window:addChild(GUI.switch(x + sliderWidth - 8, y, 8, 0xFFDB40, 0xAAAAAA, 0xFFFFFF, not rayEngine.properties.useSimpleRenderer)) + graphonSwitch.onStateChanged = function() + rayEngine.properties.useSimpleRenderer = not graphonSwitch.state + window:draw() + buffer.draw() + end; y = y + 3 + + window:addChild(GUI.label(x, y, sliderWidth, 1, 0xDDDDDD, localization.enableDayNightCycle)) + + local lockTimeSwitch = window:addChild(GUI.switch(x + sliderWidth - 8, y, 8, 0xFFDB40, 0xAAAAAA, 0xFFFFFF, rayEngine.world.dayNightCycle.enabled)) + lockTimeSwitch.onStateChanged = function() + rayEngine.world.dayNightCycle.enabled = lockTimeSwitch.state + window:draw() + buffer.draw() + end; y = y + 3 + + window:addChild(GUI.button(x, y, sliderWidth, 3, 0xEEEEEE, 0x262626, 0xBBBBBB, 0x262626, localization.continue)).onTouch = function() window:stopEventHandling(); table.toFile(applicationResourcesDirectory .. "RayEngine.cfg", rayEngine.properties, true) end + + window:draw(); buffer.draw(); window:startEventHandling() +end + +local function menu() + local window = GUI.fullScreenContainer() + local oldDraw = window.draw + window.draw = function() + menuBackground() + oldDraw(window) + end + + local buttonWidth, buttonHeight = 50, 3 + local worlds = {} + for file in fs.list(worldsPath) do table.insert(worlds, unicode.sub(file, 1, -2)) end + local x, y = math.floor(window.width / 2 - buttonWidth / 2), math.floor(window.height / 2 - #worlds * (buttonHeight + 1) / 2 - 11) + + window:addChild(GUI.label(1, y, window.width, 1, 0xFFFFFF, rayWalkVersion)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 3 + window:addChild(GUI.button(x, y, buttonWidth, buttonHeight, 0xEEEEEE, 0x262626, 0xBBBBBB, 0x262626, localization.continue)).onTouch = function() window:stopEventHandling() end; y = y + buttonHeight + 1 + window:addChild(GUI.button(x, y, buttonWidth, buttonHeight, 0xEEEEEE, 0x262626, 0xBBBBBB, 0x262626, localization.settings)).onTouch = function() window:stopEventHandling(); settings() end; y = y + buttonHeight + 1 + window:addChild(GUI.button(x, y, buttonWidth, buttonHeight, 0xEEEEEE, 0x262626, 0x999999, 0x262626, localization.exit)).onTouch = function() buffer.clear(0x000000); buffer.draw(); os.exit() end; y = y + buttonHeight + 1 + window:addChild(GUI.label(1, y, window.width, 1, 0xFFFFFF, localization.loadWorld)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 2 + + for i = 1, #worlds do + window:addChild(GUI.button(x, y, buttonWidth, buttonHeight, 0xEEEEEE, 0x262626, 0xBBBBBB, 0x262626, worlds[i])).onTouch = function() rayEngine.loadWorld(worldsPath .. worlds[i]); window:stopEventHandling() end + y = y + buttonHeight + 1 + end + + local lines = {}; for i = 1, #localization.controlsHelp do table.insert(lines, localization.controlsHelp[i]) end + table.insert(lines, 1, " ") + table.insert(lines, 1, {text = localization.controls, color = 0xFFFFFF}) + window:addChild(GUI.textBox(1, y, window.width, #lines, nil, 0xCCCCCC, lines, 1):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)); y = y + #lines + 1 + + window:draw(); buffer.draw(); window:startEventHandling() +end + + +---------------------------------------------------------------------------------------------------------------------------------- + +local controls = { + ["key_down"] = { + [16] = rayEngine.turnLeft, --q + [18] = rayEngine.turnRight, --e + [30] = rayEngine.moveLeft, --a + [32] = rayEngine.moveRight, --d + [17] = rayEngine.moveForward, --w + [31] = rayEngine.moveBackward, --s + [50] = rayEngine.toggleMinimap, --m + [37] = rayEngine.toggleCompass, --k + [25] = rayEngine.toggleWatch, --p + [14] = menu, --backspace + [28] = rayEngine.commandLine, --enter + [57] = rayEngine.jump, --space + [29] = rayEngine.crouch, --ctrl + [59] = rayEngine.toggleDebugInformation, -- F1 + }, + ["key_up"] = { + [29] = rayEngine.crouch, --ctrl + }, +} + +-------------------------------------------------------------------------------------------------------------- + +rayEngine.loadEngineProperties(applicationResourcesDirectory .. "RayEngine.cfg") +rayEngine.loadWeapons(applicationResourcesDirectory .. "Weapons/") +rayEngine.loadWorld(worldsPath .. "ExampleWorld") +rayEngine.changeResolution(rayEngine.properties.screenResolution.width, rayEngine.properties.screenResolution.height) +-- rayEngine.intro() +menu() +rayEngine.update() + +while true do + local e = { event.pull(1) } + if e[1] == "touch" then + if e[5] == 1 then + if not rayEngine.currentWeapon then rayEngine.place(3, 0x3) end + else + if rayEngine.currentWeapon then rayEngine.fire() else rayEngine.destroy(3) end + end + elseif e[1] == "key_down" then + if e[4] > 1 and e[4] < 10 then + rayEngine.changeWeapon(e[4] - 2) + else + if controls[e[1]] and controls[e[1]][e[4]] then controls[e[1]][e[4]]() end + end + elseif e[1] == "key_up" then + if controls[e[1]] and controls[e[1]][e[4]] then controls[e[1]][e[4]]() end + end + rayEngine.update() +end \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/About/Russian.txt new file mode 100755 index 00000000..afa9796e --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Это приложение - вершина графических возможностей OpenComputers! Оно демонстрирует всю мощь нашей библиотеки тройной буферизации, игрового движка RayEngine, а также объектно-ориентированной оконной библиотеки windows, которые в совокупности позволяют рендерить графику на уровне Wolfenstein и DOOM. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Icon.pic new file mode 100755 index 00000000..b8e59198 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Localization/English.lang b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Localization/English.lang new file mode 100755 index 00000000..91a3697c --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Localization/English.lang @@ -0,0 +1,26 @@ +{ + continue = "Continue", + settings = "Settings", + exit = "Exit", + loadWorld = "Load world", + controls = "Controls:", + controlsHelp = { + "WASD for movement, QE - rotation", + "Space - jump, Ctrl - crouch", + "K - compass, P - watch, M - map, F1 - debug info", + "12345 - weapon selection, the first one allows to", + "place and destroy blocks", + "Mouse - shooting/world interaction", + "Enter - command line, Backspace - menu", + }, + rayEngineProperties = "RayEngine™ properties", + screenResolution = "Screen resolution", + drawDistance = "Draw distance: ", + shadingDistance = "Shading distance: ", + shadingCascades = "Shading cascades: ", + raycastQuality = "Raycast quality: ", + dayNightCycle = "World time: ", + enableSemipixelRenderer = "Semipixel renderer: ", + enableDayNightCycle = "Day/night cycle: ", + seconds = " sec", +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Localization/Russian.lang b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Localization/Russian.lang new file mode 100755 index 00000000..a4a49179 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Localization/Russian.lang @@ -0,0 +1,25 @@ +{ + continue = "Продолжить", + settings = "Настройки", + exit = "Выход", + loadWorld = "Загрузить мир", + controls = "Управление:", + controlsHelp = { + "WASD для перемещения, QE - поворот", + "Space - прыжок, Ctrl - приседание", + "K - компас, P - часы, M - карта, F1 - дебаг-инфо", + "12345 - выбор оружия, первое позволяет ставить и ломать блоки", + "Мышь - стрельба/взаимодействие с миром", + "Enter - командная строка, Backspace - меню", + }, + rayEngineProperties = "Параметры RayEngine™", + screenResolution = "Разрешение экрана", + drawDistance = "Дистанция прорисовки: ", + shadingDistance = "Дистанция затенения: ", + shadingCascades = "Каскады затенения: ", + raycastQuality = "Допущения рейкастинка: ", + dayNightCycle = "Время суток: ", + enableSemipixelRenderer = "Полу-пиксельный рендерер: ", + enableDayNightCycle = "Цикл смены дня и ночи: ", + seconds = " сек", +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/RayEngine.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/RayEngine.cfg new file mode 100755 index 00000000..37945fab --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/RayEngine.cfg @@ -0,0 +1,28 @@ +{ + shadingDistance = 500, + shadingCascades = 8, + screenResolution = { + height = 50, + width = 160 + }, + useSimpleRenderer = false, + drawDistance = 1000, + shadingTransparencyMap = { + [12] = 0.50196078431373, + [6] = 1, + [13] = 0.4, + [1] = 0.2, + [3] = 0.6, + [7] = 1, + [8] = 0.8, + [4] = 0.8, + [9] = 0.8, + [14] = 0.30196078431373, + [10] = 0.70196078431373, + [5] = 1, + [11] = 0.6, + [2] = 0.4 + }, + tileWidth = 32, + raycastQuality = 6.4 +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/CrosshairTextures/Angled.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/CrosshairTextures/Angled.pic new file mode 100755 index 00000000..b89fb64c Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/CrosshairTextures/Angled.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/CrosshairTextures/Default.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/CrosshairTextures/Default.pic new file mode 100755 index 00000000..19b50b5d Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/CrosshairTextures/Default.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/CrosshairTextures/Dotted.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/CrosshairTextures/Dotted.pic new file mode 100755 index 00000000..5e93a436 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/CrosshairTextures/Dotted.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/CrosshairTextures/Half.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/CrosshairTextures/Half.pic new file mode 100755 index 00000000..209f09ea Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/CrosshairTextures/Half.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/FireTextures/Plasma.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/FireTextures/Plasma.pic new file mode 100755 index 00000000..f97fdb8f Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/FireTextures/Plasma.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/FireTextures/PowderFire.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/FireTextures/PowderFire.pic new file mode 100755 index 00000000..89b283c3 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/FireTextures/PowderFire.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/WeaponTextures/Pistol.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/WeaponTextures/Pistol.pic new file mode 100755 index 00000000..e6ebe7c5 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/WeaponTextures/Pistol.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/WeaponTextures/Plasmer.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/WeaponTextures/Plasmer.pic new file mode 100755 index 00000000..e1994a21 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/WeaponTextures/Plasmer.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/WeaponTextures/Rifle.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/WeaponTextures/Rifle.pic new file mode 100755 index 00000000..fd034377 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/WeaponTextures/Rifle.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/WeaponTextures/Sniper.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/WeaponTextures/Sniper.pic new file mode 100755 index 00000000..53d74425 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/WeaponTextures/Sniper.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/Weapons.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/Weapons.cfg new file mode 100755 index 00000000..f7aa4274 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Weapons/Weapons.cfg @@ -0,0 +1,46 @@ +{ + { + name = "USP-5", + damage = 25, + weaponTexture = "WeaponTextures/Pistol.pic", + fireTexture = "FireTextures/PowderFire.pic", + firePosition = { + x = -1, + y = -4, + }, + crosshairTexture = "CrosshairTextures/Default.pic", + }, + { + name = "MAG20-USP", + damage = 48, + weaponTexture = "WeaponTextures/Rifle.pic", + fireTexture = "FireTextures/PowderFire.pic", + firePosition = { + x = 1, + y = -1, + }, + crosshairTexture = "CrosshairTextures/Half.pic", + }, + { + name = "UberSniper228", + damage = 100, + weaponTexture = "WeaponTextures/Sniper.pic", + fireTexture = "FireTextures/PowderFire.pic", + firePosition = { + x = -5, + y = 1, + }, + crosshairTexture = "CrosshairTextures/Angled.pic", + }, + { + name = "Plasmer", + damage = 80, + weaponTexture = "WeaponTextures/Plasmer.pic", + fireTexture = "FireTextures/Plasma.pic", + firePosition = { + x = 1, + y = -2, + }, + crosshairTexture = "CrosshairTextures/Dotted.pic", + }, +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/ExampleWorld/Blocks.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/ExampleWorld/Blocks.cfg new file mode 100755 index 00000000..edc7dd40 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/ExampleWorld/Blocks.cfg @@ -0,0 +1,26 @@ +{ + { + color = 0xFFFFFF, + canBeDestroyed = false, + }, + { + color = 0xFFFFFF, + canBeDestroyed = true, + }, + { + color = 0xFF8888, + canBeDestroyed = true, + }, + { + color = 0x88FF88, + canBeDestroyed = true, + }, + { + color = 0xFF88FF, + canBeDestroyed = true, + }, + { + color = 0xFFEE60, + canBeDestroyed = true, + }, +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/ExampleWorld/Map.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/ExampleWorld/Map.cfg new file mode 100755 index 00000000..6c03aaea --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/ExampleWorld/Map.cfg @@ -0,0 +1,35 @@ +{ + { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x3, 0x2, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x2, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x2, 0x2, 0x2, 0x2, 0x2, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x5, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x4, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x3, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x2, 0x2, 0x2, 0x2, 0x2, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x2, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x3, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x3, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, 0x2, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x2, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, 0x4, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x2, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, 0x2, 0x4, 0x4, 0x2, nil, 0x2, 0x2, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }, +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/ExampleWorld/Player.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/ExampleWorld/Player.cfg new file mode 100755 index 00000000..777a7e19 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/ExampleWorld/Player.cfg @@ -0,0 +1,17 @@ +{ + position = { + x = 5, + y = 5, + }, + health = { + maximum = 100, + current = 100, + }, + isCrouched = false, + jumpHeight = 10, + moveSpeed = 16, + rotationSpeed = 5, + crouchHeight = 10, + fieldOfView = 60, + rotation = 0, +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/ExampleWorld/World.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/ExampleWorld/World.cfg new file mode 100755 index 00000000..ae6f7c3f --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/ExampleWorld/World.cfg @@ -0,0 +1,28 @@ +{ + dayNightCycle = { + enabled = true, + currentTime = 100, + speed = 1, + length = 300, + }, + colors = { + ground = 0xEEEEEE, + clouds = 0xFFFFFF, + sky = { + 0x002440, + 0x002480, + 0x3349BF, + 0x6692FF, + 0x99DBFF, + 0x99DBFF, + 0x99DBFF, + 0x66B6FF, + 0x66B6FF, + 0xFFDB80, + 0xFFB640, + 0xCCBD00, + 0x000080, + 0x002440, + }, + }, +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/SundownBeams/Blocks.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/SundownBeams/Blocks.cfg new file mode 100755 index 00000000..edc7dd40 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/SundownBeams/Blocks.cfg @@ -0,0 +1,26 @@ +{ + { + color = 0xFFFFFF, + canBeDestroyed = false, + }, + { + color = 0xFFFFFF, + canBeDestroyed = true, + }, + { + color = 0xFF8888, + canBeDestroyed = true, + }, + { + color = 0x88FF88, + canBeDestroyed = true, + }, + { + color = 0xFF88FF, + canBeDestroyed = true, + }, + { + color = 0xFFEE60, + canBeDestroyed = true, + }, +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/SundownBeams/Map.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/SundownBeams/Map.cfg new file mode 100755 index 00000000..c4e7c04c --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/SundownBeams/Map.cfg @@ -0,0 +1,28 @@ +{ + { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x1, 0x1, 0x1, 0x1, 0x1, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1, 0x1, 0x1, 0x1, 0x1, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x1 }, + { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }, +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/SundownBeams/Player.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/SundownBeams/Player.cfg new file mode 100755 index 00000000..777a7e19 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/SundownBeams/Player.cfg @@ -0,0 +1,17 @@ +{ + position = { + x = 5, + y = 5, + }, + health = { + maximum = 100, + current = 100, + }, + isCrouched = false, + jumpHeight = 10, + moveSpeed = 16, + rotationSpeed = 5, + crouchHeight = 10, + fieldOfView = 60, + rotation = 0, +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/SundownBeams/World.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/SundownBeams/World.cfg new file mode 100755 index 00000000..ae6f7c3f --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RayWalk.app/Resources/Worlds/SundownBeams/World.cfg @@ -0,0 +1,28 @@ +{ + dayNightCycle = { + enabled = true, + currentTime = 100, + speed = 1, + length = 300, + }, + colors = { + ground = 0xEEEEEE, + clouds = 0xFFFFFF, + sky = { + 0x002440, + 0x002480, + 0x3349BF, + 0x6692FF, + 0x99DBFF, + 0x99DBFF, + 0x99DBFF, + 0x66B6FF, + 0x66B6FF, + 0xFFDB80, + 0xFFB640, + 0xCCBD00, + 0x000080, + 0x002440, + }, + }, +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RunningString.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RunningString.app/Main.lua new file mode 100755 index 00000000..d2773f52 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RunningString.app/Main.lua @@ -0,0 +1,72 @@ +local ecs = require("ECSAPI") +local event = require("event") +local gpu = require("component").gpu +local unicode = require("unicode") +local keyboard = require("keyboard") + +local str,freq,speed,scale,bg,fg + +-- gpu.setResolution(gpu.maxResolution()) +-- ecs.prepareToExit() + +local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x880000, "Бегущая строка"}, + {"EmptyLine"}, + {"CenterText", 0x000000, "Для выхода из программы"}, + {"CenterText", 0x000000, "удерживайте Enter"}, + {"EmptyLine"}, + {"Input", 0x262626, 0x880000, "Программист за работой, не мешай, сука!"}, + {"Color", "Цвет фона", 0x000000}, + {"Color", "Цвет текста", 0xFFFFFF}, + {"Slider", 0x262626, 0x880000, 1, 100, 1, "Масштаб: ", "%"}, + {"Slider", 0x262626, 0x880000, 1, 100, 40, "Скорость: ", "/100 FPS"}, + {"EmptyLine"}, + {"Button", {0xbbbbbb, 0xffffff, "OK"}, {0x999999, 0xffffff, "Отмена"}} +) + +-- ecs.error(table.unpack(data)) +if data[6] == "OK" then + str = data[1] or "Где текст, сука?" + bg = tonumber(data[2]) or 0x000000 + fg = tonumber(data[3]) or 0xFFFFFF + scale = tonumber(data[4])/100 or 0.1 + speed = tonumber(data[5])/100 or 0.4 + freq = 5 +else + return +end + +local xOld, yOld = gpu.getResolution() +ecs.setScale(scale) +local xSize, ySize = gpu.getResolution() +gpu.setBackground(bg) +gpu.setForeground(fg) +gpu.fill(1, 1, xSize, ySize, " ") + +str = " " .. str .. string.rep(" ", freq) + +while true do + str = unicode.sub(str, 2, -1) .. unicode.sub(str, 1, 1) + gpu.set(math.ceil(xSize / 2 - unicode.len(str) / 2), math.ceil(ySize / 2), str) + + if keyboard.isKeyDown(28) then + gpu.setResolution(xOld, yOld) + ecs.prepareToExit() + return + end + + local e = event.pull(speed) + if e == "key_down" or e == "touch" then return end +end + + + + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RunningString.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RunningString.app/Resources/About/Russian.txt new file mode 100755 index 00000000..96d61478 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RunningString.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Бегущая строка, красиво и наглядно отображающая любое количество информации. Сделана специально по заказу Никиты Ярычева, ссылка на вк: http://vk.com/mcmodder. В общем, если ты читаешь это, то передай ему, что он пидор, ибо мне пришлось добавлять кучу новых фич в библиотеку ecsapi, а это нервы, нервы! \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RunningString.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RunningString.app/Resources/Icon.pic new file mode 100755 index 00000000..6eacebcc Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/RunningString.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Shooting.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Shooting.app/Main.lua new file mode 100755 index 00000000..04d7fe8e --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Shooting.app/Main.lua @@ -0,0 +1,286 @@ +local component = require("component") +local gpu = component.gpu +local event = require("event") +local ecs = require("ECSAPI") +local color = require("color") + +--------------------------- +local xOld, yOld = gpu.getResolution() +local xSize, ySize = 160, 50 +gpu.setResolution(xSize, ySize) + +local players = {} +local xCenter, yCenter = math.floor(xSize/4 - 15), math.floor(ySize/2) + +local xScore, yScore = 106, 5 + +local symbols = { + ["1"] = { + {0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0}, + {0, 1, 1, 0, 0}, + {0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0}, + {0, 1, 1, 1, 0}, + }, + ["2"] = { + {0, 1, 1, 1, 0}, + {1, 0, 0, 0, 1}, + {0, 0, 0, 0, 1}, + {0, 1, 1, 1, 0}, + {1, 0, 0, 0, 0}, + {1, 0, 0, 0, 0}, + {1, 1, 1, 1, 1}, + }, + ["3"] = { + {0, 1, 1, 1, 0}, + {1, 0, 0, 0, 1}, + {0, 0, 0, 0, 1}, + {0, 0, 1, 1, 0}, + {0, 0, 0, 0, 1}, + {1, 0, 0, 0, 1}, + {0, 1, 1, 1, 0}, + }, + ["4"] = { + {1, 0, 0, 0, 1}, + {1, 0, 0, 0, 1}, + {1, 0, 0, 0, 1}, + {1, 1, 1, 1, 1}, + {0, 0, 0, 0, 1}, + {0, 0, 0, 0, 1}, + {0, 0, 0, 0, 1}, + }, + ["5"] = { + {1, 1, 1, 1, 1}, + {1, 0, 0, 0, 0}, + {1, 0, 0, 0, 0}, + {1, 1, 1, 1, 0}, + {0, 0, 0, 0, 1}, + {1, 0, 0, 0, 1}, + {0, 1, 1, 1, 0}, + }, + ["6"] = { + {0, 0, 1, 1, 1}, + {0, 1, 0, 0, 0}, + {1, 0, 0, 0, 0}, + {1, 1, 1, 1, 0}, + {1, 0, 0, 0, 1}, + {1, 0, 0, 0, 1}, + {0, 1, 1, 1, 0}, + }, + ["7"] = { + {1, 1, 1, 1, 1}, + {0, 0, 0, 0, 1}, + {0, 0, 0, 1, 0}, + {0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0}, + }, + ["8"] = { + {0, 1, 1, 1, 0}, + {1, 0, 0, 0, 1}, + {1, 0, 0, 0, 1}, + {0, 1, 1, 1, 0}, + {1, 0, 0, 0, 1}, + {1, 0, 0, 0, 1}, + {0, 1, 1, 1, 0}, + }, + ["9"] = { + {0, 1, 1, 1, 0}, + {1, 0, 0, 0, 1}, + {1, 0, 0, 0, 1}, + {0, 1, 1, 1, 1}, + {0, 0, 0, 0, 1}, + {0, 0, 0, 1, 0}, + {1, 1, 1, 0, 0}, + }, + ["0"] = { + {0, 1, 1, 1, 0}, + {1, 0, 0, 0, 1}, + {1, 0, 0, 0, 1}, + {1, 0, 0, 0, 1}, + {1, 0, 0, 0, 1}, + {1, 0, 0, 0, 1}, + {0, 1, 1, 1, 0}, + } +} + +--OBJECTS, CYKA +local obj = {} +local function newObj(class, name, ...) + obj[class] = obj[class] or {} + obj[class][name] = {...} +end + +local function SetPixel(x, y, color) + ecs.square(x*2, y, 2, 1, color) +end + +local function GetDistance(x1, y1, x2, y2) + local distance + distance = math.sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2)) + return distance +end + +local function drawKrug(x1, y1, r, color) + for x = x1 - r, x1 + r do + for y = y1 - r, y1 + r do + if GetDistance(x1, y1, x, y) <= r then + SetPixel(x, y, color) + end + end + end +end + +local function drawMishen() + for i = 0, 9 do + local color = 0xffffff + if i % 2 == 0 then + color = 0x010101 + end + drawKrug(xCenter, yCenter, 20 - i*2, color) + end + SetPixel(xCenter, yCenter, 0xff0000) +end + +local function AddPlayer(name) + if not players[name] then + players[name] = {0, color.HSBToInteger(math.random(0, 359), 1, math.random(50, 100) / 100)} + end +end + +local function AddScore(name, score) + players[name][1] = players[name][1] + score +end + +local function GetScore(x, y) + local score = 1 + local distance = GetDistance(xCenter, yCenter, x, y) + if distance == 0 then + score = 25 + else + for i = 0, 6 do + if distance <= 20 - i*3 then + score = score + 2 + end + end + end + return score +end + +local function showPlayers(x, y) + local width = 40 + local nicknameLimit = 20 + local mode = false + local counter = 1 + local stro4ka = string.rep(" ", nicknameLimit).."│"..string.rep(" ", width - nicknameLimit) + ecs.colorTextWithBack(x, y, 0xffffff, ecs.colors.blue, stro4ka) + gpu.set(x + 1, y, "Имя игрока") + gpu.set(x + nicknameLimit + 2, y, "Очки") + + for key, val in pairs(players) do + local color = 0xffffff + + if mode then + color = color - 0x222222 + end + + gpu.setForeground(0x262626) + gpu.setBackground(color) + gpu.set(x, y + counter, stro4ka) + gpu.set(x + 3, y + counter, ecs.stringLimit("end", key, nicknameLimit - 4)) + gpu.set(x + nicknameLimit + 2, y + counter, tostring(players[key][1])) + ecs.colorTextWithBack(x + 1, y + counter, players[key][2], color, "●") + + counter = counter + 1 + mode = not mode + end +end + +local function drawSymb(x, y, symb, color) + for i = 1, 7 do + for j = 1, 5 do + if symbols[symb][i][j] == 1 then + SetPixel(x + j - 1, y + i - 1, color) + end + end + end +end + +local function drawText(x, y, text, color) + if text >=10 then + drawSymb(x, y, tostring(math.floor(text/10)), color) + drawSymb(x + 6, y, tostring(math.floor(text%10)), color) + else + drawSymb(x, y, tostring(text), color) + end +end + +local function isIn(x1, y1, x2, y2, xClick, yClick) + if xClick >= x1 and xClick <= x2 and yClick >=y1 and yClick <= y2 then + return true + else + return false + end +end + +local function drawLastScore(x, y, score, color) + ecs.square((x + 6) * 2, y, 35, 7, 0x262626) + drawKrug(x + 3, y + 3, 3, color) + drawText(x + 9, y, score, 0xffffff) + + local yPos = 34 + newObj("Buttons", "Заново", ecs.drawAdaptiveButton(xScore, yPos, 18, 1, "Заново", ecs.colors.blue, 0xffffff)) + yPos = yPos + 4 + newObj("Buttons", "Выйти ", ecs.drawAdaptiveButton(xScore, yPos, 18, 1, "Выйти ", ecs.colors.blue, 0xffffff)) + +end + +local function Tir() + ecs.prepareToExit() + + showPlayers(xScore, yScore) + drawLastScore(xScore / 2, 22, 0, 0xffffff) + + drawMishen() + while true do + local e = {event.pull()} + if e[1] == "touch" then + for key, val in pairs(obj["Buttons"]) do + if ecs.clickedAtArea(e[3], e[4], obj["Buttons"][key][1], obj["Buttons"][key][2], obj["Buttons"][key][3], obj["Buttons"][key][4]) then + ecs.drawAdaptiveButton(obj["Buttons"][key][1], obj["Buttons"][key][2], 18, 1, key, 0xffffff, 0x000000) + os.sleep(0.5) + + if key == "Выйти " then + return "exit" + else + players = {} + return 0 + end + end + end + e[3] = e[3]/2 + AddPlayer(e[6]) + AddScore(e[6], GetScore(e[3], e[4])) + SetPixel(e[3], e[4], players[e[6]][2]) + showPlayers(xScore, yScore) + drawLastScore(xScore / 2, 22, GetScore(e[3], e[4]),players[e[6]][2]) + end + end +end + +-------------------------- + +gpu.setBackground(0x262626) +gpu.fill(1, 1, xSize, ySize, " ") + +while true do + local exit = Tir() + if exit == "exit" then break end +end + +gpu.setResolution(xOld, yOld) +ecs.prepareToExit() + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Shooting.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Shooting.app/Resources/Icon.pic new file mode 100755 index 00000000..7a2f264a Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Shooting.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Main.lua new file mode 100755 index 00000000..7de608d2 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Main.lua @@ -0,0 +1,330 @@ + +local fs = require("filesystem") +local image = require("image") +local buffer = require("doubleBuffering") +local GUI = require("GUI") +local component = require("component") +local unicode = require("unicode") +local MineOSPaths = require("MineOSPaths") +local MineOSCore = require("MineOSCore") +local MineOSInterface = require("MineOSInterface") +if not component.isAvailable("stargate") then + GUI.error("This program requires stargate from mod \"SGCraft\"") + return +end +local stargate = component.stargate + +--------------------------------------------------------------------------------------------- + +local resources = MineOSCore.getCurrentApplicationResourcesDirectory() +local pathToContacts = MineOSPaths.applicationData .. "Stargate/Contacts.cfg" +local contacts = {} +local Ch1Image = image.load(resources .. "Ch1.pic") +local Ch2Image = image.load(resources .. "Ch2.pic") + +local mainContainer = GUI.fullScreenContainer() + +--------------------------------------------------------------------------------------------- + +local function loadContacts() + if fs.exists(pathToContacts) then + contacts = table.fromFile(pathToContacts) + end +end + +local function saveContacts() + table.toFile(pathToContacts, contacts) +end + +local function chevronDraw(object) + local inactiveColor, activeColor, fadeColor = 0x332400, 0xFFDB00, 0xCC6D00 + -- buffer.square(object.x, object.y, object.width, object.height, object.isActivated and fadeColor or inactiveColor) + -- buffer.square(object.x + 1, object.y, 3, object.height, object.isActivated and activeColor or inactiveColor) + -- buffer.text(object.x + 2, object.y + 1, object.isActivated and 0x0 or 0xFFFFFF, object.text) + buffer.image(object.x, object.y, object.isActivated and Ch1Image or Ch2Image) + return object +end + +local function newChevronObject(x, y) + local object = GUI.object(x, y, 5, 3) + + object.draw = chevronDraw + object.isActivated = false + object.text = " " + + return object +end + +local function addChevron(x, y) + table.insert(mainContainer.chevrons, mainContainer.chevronsContainer:addChild(newChevronObject(x, y))) +end + +local function updateChevrons(state) + for i = 1, #mainContainer.chevrons do + mainContainer.chevrons[i].isActivated = state + if not state then mainContainer.chevrons[i].text = " " end + end +end + +local function updateButtons() + mainContainer.removeContactButton.disabled = #contacts == 0 + mainContainer.connectContactButton.disabled = #contacts == 0 +end + +local function update() + local stargateState, irisState, imagePath = stargate.stargateState(), stargate.irisState() + mainContainer.irisButton.text = irisState == "Closed" and "Open Iris" or "Close Iris" + mainContainer.connectionButton.text = stargateState == "Connected" and "Disconnect" or "Connect" + mainContainer.connectedToLabel.text = stargateState == "Connected" and "(Connected to " .. stargate.remoteAddress() .. ")" or "(Not connected)" + + if stargateState == "Connected" then + mainContainer.connectContactButton.disabled = true + mainContainer.messageContactButton.disabled = false + + if irisState == "Closed" then + imagePath = "OnOn.pic" + else + imagePath = "OnOff.pic" + end + else + mainContainer.connectContactButton.disabled = false + mainContainer.messageContactButton.disabled = true + + if irisState == "Closed" then + imagePath = "OffOn.pic" + else + imagePath = "OffOff.pic" + end + end + + updateButtons() + mainContainer.SGImage.image = image.load(resources .. imagePath) +end + +local function updateContacts() + mainContainer.contactsComboBox:clear() + if #contacts == 0 then + mainContainer.contactsComboBox:addItem("No contacts found") + else + for i = 1, #contacts do + mainContainer.contactsComboBox:addItem(contacts[i].name) + end + end +end + +local function newThing(x, y, width, height) + local object = GUI.object(x, y, width, height) + + object.draw = function(object) + local x, y = object.x + object.width - 1, math.floor(object.y + object.height / 2) + for i = object.y, object.y + object.height - 1 do + buffer.text(x, i, 0xEEEEEE, "│") + end + for i = object.x, object.x + width - 1 do + buffer.text(i, y, 0xEEEEEE, "─") + end + buffer.text(x, y, 0xEEEEEE, "┤") + end + + return object +end + +local function dial(address) + local success = stargate.dial(address) + if success then + mainContainer.fuelProgressBar.value = math.ceil(stargate.energyToDial(address) / stargate.energyAvailable() * 100) + mainContainer:draw() + buffer.draw() + end +end + +--------------------------------------------------------------------------------------------- + +local width, height = 32, 37 +local x, y = mainContainer.width - width - 3, math.floor(mainContainer.height / 2 - height / 2) + +mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x1E1E1E)) + +mainContainer.SGImage = mainContainer:addChild(GUI.image(1, 1, image.load(resources .. "OffOff.pic"))) +mainContainer.SGImage.localX, mainContainer.SGImage.localY = math.floor((x - 2) / 2 - image.getWidth(mainContainer.SGImage.image) / 2), mainContainer.height - image.getHeight(mainContainer.SGImage.image) + 1 + +mainContainer.chevronsContainer = mainContainer:addChild(GUI.container(mainContainer.SGImage.localX, mainContainer.SGImage.localY, mainContainer.SGImage.width, mainContainer.SGImage.height)) +mainContainer.chevrons = {} +addChevron(13, 30) +addChevron(8, 17) +addChevron(21, 6) +addChevron(45, 1) +addChevron(72, 6) +addChevron(83, 17) +addChevron(79, 30) + +mainContainer:addChild(newThing(mainContainer.SGImage.localX + mainContainer.SGImage.width, y, mainContainer.width - mainContainer.SGImage.localX - mainContainer.SGImage.width - width - 7, height)) + +mainContainer:addChild(GUI.label(x, y, width, 1, 0xEEEEEE, "Stargate " .. stargate.localAddress())):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 1 +mainContainer.connectedToLabel = mainContainer:addChild(GUI.label(x, y, width, 1, 0x555555, "(Not connected)")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 2 +mainContainer.connectionButton = mainContainer:addChild(GUI.framedButton(x, y, width, 3, 0xEEEEEE, 0xEEEEEE, 0xBBBBBB, 0xBBBBBB, "Connect")); y = y + 3 +-- mainContainer.connectionButton.animated = false +mainContainer.connectionButton.onTouch = function() + if stargate.stargateState() == "Idle" then + local container = MineOSInterface.addUniversalContainer(mainContainer, "Connect") + local input = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x666666, 0xEEEEEE, 0x262626, contacts.last, "Type address here")) + input.onInputFinished = function() + if input.text then + dial(input.text) + contacts.last = input.text + saveContacts() + container:delete() + + mainContainer:draw() + buffer.draw() + end + end + + container.panel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + input.onInputFinished() + end + end + + mainContainer:draw() + buffer.draw() + else + stargate.disconnect() + end +end + +mainContainer.irisButton = mainContainer:addChild(GUI.framedButton(x, y, width, 3, 0xEEEEEE, 0xEEEEEE, 0xBBBBBB, 0xBBBBBB, "Open Iris")); y = y + 3 +mainContainer.irisButton.onTouch = function() + if stargate.irisState() == "Open" then + stargate.closeIris() + else + stargate.openIris() + end +end + +mainContainer.messageContactButton = mainContainer:addChild(GUI.framedButton(x, y, width, 3, 0xEEEEEE, 0xEEEEEE, 0xBBBBBB, 0xBBBBBB, "Message")); y = y + 4 +mainContainer.messageContactButton.onTouch = function() + local container = MineOSInterface.addUniversalContainer(mainContainer, "Message") + local input = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x666666, 0xEEEEEE, 0x262626, nil, "Type message text here")) + input.onInputFinished = function() + if input.text then + container:delete() + stargate.sendMessage(input.text) + + mainContainer:draw() + buffer.draw() + end + end + + container.panel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + input.onInputFinished() + end + end + + mainContainer:draw() + buffer.draw() +end + +mainContainer:addChild(GUI.label(x, y, width, 1, 0xEEEEEE, "Contacts")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 2 +mainContainer.contactsComboBox = mainContainer:addChild(GUI.comboBox(x, y, width, 3, 0x3C3C3C, 0xBBBBBB, 0x555555, 0x888888)); y = y + 4 + +mainContainer.connectContactButton = mainContainer:addChild(GUI.framedButton(x, y, width, 3, 0xEEEEEE, 0xEEEEEE, 0xBBBBBB, 0xBBBBBB, "Connect")); y = y + 3 +mainContainer.connectContactButton.onTouch = function() + dial(contacts[mainContainer.contactsComboBox.selectedItem].address) +end + +mainContainer.addContactButton = mainContainer:addChild(GUI.framedButton(x, y, width, 3, 0xEEEEEE, 0xEEEEEE, 0xBBBBBB, 0xBBBBBB, "Add contact")); y = y + 3 +mainContainer.addContactButton.onTouch = function() + local container = MineOSInterface.addUniversalContainer(mainContainer, "Add contact") + local input1 = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x666666, 0xEEEEEE, 0x262626, nil, "Name")) + local input2 = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x666666, 0xEEEEEE, 0x262626, contacts.last, "Address")) + + container.panel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + if input1.text and input2.text then + local exists = false + for i = 1, #contacts do + if contacts[i].address == input2.text then + exists = true + break + end + end + if not exists then + table.insert(contacts, {name = input1.text, address = input2.text}) + updateContacts() + saveContacts() + updateButtons() + end + + container:delete() + mainContainer:draw() + buffer.draw() + end + end + end + + mainContainer:draw() + buffer.draw() +end + +mainContainer.removeContactButton = mainContainer:addChild(GUI.framedButton(x, y, width, 3, 0xEEEEEE, 0xEEEEEE, 0xBBBBBB, 0xBBBBBB, "Remove contact")); y = y + 4 +mainContainer.removeContactButton.onTouch = function() + if #contacts > 0 then + table.remove(contacts, mainContainer.contactsComboBox.selectedItem) + updateContacts() + saveContacts() + updateButtons() + + mainContainer:draw() + buffer.draw() + end +end + +mainContainer:addChild(GUI.label(x, y, width, 1, 0xEEEEEE, "Energy to dial")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 2 +mainContainer.fuelProgressBar = mainContainer:addChild(GUI.progressBar(x, y, width, 0xBBBBBB, 0x0, 0xEEEEEE, 100, true, true, "", "%")); y = y + 3 +mainContainer.exitButton = mainContainer:addChild(GUI.framedButton(x, y, width, 3, 0xEEEEEE, 0xEEEEEE, 0xBBBBBB, 0xBBBBBB, "Exit")); y = y + 4 +mainContainer.exitButton.onTouch = function() + mainContainer:stopEventHandling() +end + +mainContainer.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "sgIrisStateChange" then + update() + mainContainer:draw() + buffer.draw() + elseif eventData[1] == "sgStargateStateChange" then + if eventData[3] == "Idle" or eventData[3] == "Connected" then + update() + updateChevrons(eventData[3] == "Connected") + mainContainer:draw() + buffer.draw() + end + elseif eventData[1] == "sgChevronEngaged" then + if mainContainer.chevrons[eventData[3]] then + mainContainer.chevrons[eventData[3]].isActivated = true + mainContainer.chevrons[eventData[3]].text = eventData[4] + mainContainer:draw() + buffer.draw() + end + elseif eventData[1] == "sgMessageReceived" then + GUI.error(eventData[3]) + end +end + +loadContacts() +updateContacts() +update() +updateChevrons(stargate.stargateState() == "Connected") + +mainContainer:draw() +buffer.draw(true) +mainContainer:startEventHandling() + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/Ch1.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/Ch1.pic new file mode 100755 index 00000000..8ab765ec Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/Ch1.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/Ch2.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/Ch2.pic new file mode 100755 index 00000000..b5c53a97 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/Ch2.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/Icon.pic new file mode 100755 index 00000000..d99d3812 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/OffOff.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/OffOff.pic new file mode 100755 index 00000000..2e59b39f Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/OffOff.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/OffOn.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/OffOn.pic new file mode 100755 index 00000000..0d28f6f6 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/OffOn.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/OnOff.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/OnOff.pic new file mode 100755 index 00000000..75cde429 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/OnOff.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/OnOn.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/OnOn.pic new file mode 100755 index 00000000..5c9e6fcf Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Stargate.app/Resources/OnOn.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/TurretControl.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/TurretControl.app/Main.lua new file mode 100755 index 00000000..3e74fb08 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/TurretControl.app/Main.lua @@ -0,0 +1,291 @@ + +local component = require("component") +local buffer = require("doubleBuffering") +local image = require("image") +local event = require("event") +local ecs = require("ECSAPI") +local serialization = require("serialization") +local unicode = require("unicode") + +------------------------------------------------------------------------------------------------------------------------------------- + +-- /MineOS/Applications/TurretControl.app/TurretControl.lua + +buffer.flush() +local pathToTurretPicture = "MineOS/Applications/TurretControl.app/Resources/Turret.pic" +local turretImage = image.load(pathToTurretPicture) +local turrets = {} +local proxies = {} + +local turretConfig = { + turretsOn = false, + attacksNeutrals = false, + attacksPlayers = false, + attacksMobs = false, +} + +local yTurrets = 2 +local spaceBetweenTurretsHorizontal = 2 +local spaceBetweenTurretsVertical = 1 +local turretHeight = turretImage[2] + 12 +local turretWidth = turretImage[1] + 8 +local countOfTurretsCanBeShowByWidth = math.floor(buffer.getWidth() / (turretWidth + spaceBetweenTurretsHorizontal)) +local xTurrets = math.floor(buffer.getWidth() / 2 - (countOfTurretsCanBeShowByWidth * (turretWidth + spaceBetweenTurretsHorizontal)) / 2 ) + math.floor(spaceBetweenTurretsHorizontal / 2) + +local yellowColor = 0xFFDB40 + +------------------------------------------------------------------------------------------------------------------------------------- + +--Объекты +local obj = {} +local function newObj(class, name, ...) + obj[class] = obj[class] or {} + obj[class][name] = {...} +end + +local function getProxiesOfAllComponents(name) + for address in component.list(name) do + table.insert(proxies, component.proxy(address)) + end +end + +local function getTurrets() + + turretConfig.turretsOn = false + turretConfig.attacksNeutrals = false + turretConfig.attacksPlayers = false + turretConfig.attacksMobs = false + + getProxiesOfAllComponents("tierOneTurretBase") + getProxiesOfAllComponents("tierTwoTurretBase") + getProxiesOfAllComponents("tierThreeTurretBase") + getProxiesOfAllComponents("tierFourTurretBase") + getProxiesOfAllComponents("tierFiveTurretBase") + + for i = 1, #proxies do + -- print(proxies[i].type) + -- ecs.error(proxies[i].type) + if type(proxies[i].getCurrentEnergyStorage()) ~= "string" then + local turret = {} + turret.type = proxies[i].type + -- turret.isActive = (proxies[i].isAttacksPlayers() and proxies[i].isAttacksMobs()) and true or false + turret.energyPercent = math.ceil(proxies[i].getCurrentEnergyStorage() / proxies[i].getMaxEnergyStorage() * 100) + turret.proxy = proxies[i] + table.insert(turrets, turret) + + turret.isActive = false + turret.proxy.setAttacksNeutrals(false) + turret.proxy.setAttacksPlayers(false) + turret.proxy.setAttacksMobs(false) + end + end +end + +local function progressBar(x, y, width, height, background, foreground, percent) + buffer.square(x, y, width, height, background, 0x0, " ") + buffer.frame(x, y, width, height, foreground) + width = width - 2 + local cykaWidth = math.ceil(width * percent / 100) + buffer.text(x + 1, y + 1, foreground, string.rep("▒", cykaWidth)) +end + +local function drawTurrets(y) + local counter = 0 + local x = xTurrets + + if #turrets <= 0 then + local text = "Подключите турели из мода OpenModularTurrets" + local x = math.floor(buffer.getWidth() / 2 - unicode.len(text) / 2) + buffer.text(x, math.floor(buffer.getHeight() / 2 - 2), yellowColor, text) + return + end + + for turret = 1, #turrets do + local yPos = y + buffer.frame(x, yPos, turretWidth, turretHeight, yellowColor) + yPos = yPos + 1 + buffer.text(x + 2, yPos, yellowColor, ecs.stringLimit("end", "Турель " .. turrets[turret].proxy.address, turretWidth - 4)) + yPos = yPos + 2 + buffer.image(x + 4, yPos, turretImage) + yPos = yPos + turretImage[2] + 1 + buffer.text(x + 2, yPos, yellowColor, "Энергия:") + yPos = yPos + 1 + progressBar(x + 1, yPos, turretWidth - 2, 3, 0x000000, yellowColor, turrets[turret].energyPercent) + yPos = yPos + 4 + local widthOfButton = 13 + -- local isActive = turrets[turret].getActive() + local isActive = turrets[turret].isActive + newObj("TurretOn", turret, buffer.button(x + 2, yPos, widthOfButton, 1, isActive and yellowColor or 0x000000, isActive and 0x000000 or yellowColor, "ВКЛ")) + obj.TurretOn[turret].proxy = turrets[turret].proxy + newObj("TurretOff", turret, buffer.button(x + 2 + widthOfButton + 2, yPos, widthOfButton, 1, not isActive and yellowColor or 0x000000, not isActive and 0x000000 or yellowColor, "ВЫКЛ")) + yPos = yPos + 1 + + x = x + turretWidth + spaceBetweenTurretsHorizontal + counter = counter + 1 + if counter % countOfTurretsCanBeShowByWidth == 0 then + x = xTurrets + y = y + turretHeight + spaceBetweenTurretsVertical + end + end +end + +local function drawSeparator(y) + buffer.text(1, y, yellowColor, string.rep("─", buffer.getWidth())) +end + +local function drawButtonWithState(x, y, width, height, text, state) + if state then + buffer.button(x, y, width, height, yellowColor, 0x000000, text) + else + buffer.framedButton(x, y, width, height, 0x000000, yellowColor, text) + end + + return (x + width + 1) +end + +local function drawBottomBar() + local height = 6 + local y = buffer.getHeight() - height + 1 + buffer.square(1, y, buffer.getWidth(), height, 0x000000, yellowColor, " ") + drawSeparator(y) + local text = " ECS® Security Systems™ " + local x = math.floor(buffer.getWidth() / 2 - unicode.len(text) / 2) + buffer.text(x, y, yellowColor, text) + + y = y + 2 + + local widthOfButton = 19 + local totalWidth = (widthOfButton + 2) * 6 + local x = math.floor(buffer.getWidth() / 2 - totalWidth / 2) + 1 + + newObj("BottomButtons", "On", x, y, x + widthOfButton - 1, y + 2) + x = drawButtonWithState(x, y, widthOfButton, 3, turretConfig.turretsOn and "Турели ВКЛ" or "Турели ВЫКЛ", turretConfig.turretsOn) + newObj("BottomButtons", "AddPlayer", x, y, x + widthOfButton - 1, y + 2) + x = drawButtonWithState(x, y, widthOfButton, 3, "Добавить игрока", false) + newObj("BottomButtons", "AttacksMobs", x, y, x + widthOfButton - 1, y + 2) + x = drawButtonWithState(x, y, widthOfButton, 3, "Атака мобов", turretConfig.attacksMobs) + newObj("BottomButtons", "AttacksNeutrals", x, y, x + widthOfButton - 1, y + 2) + x = drawButtonWithState(x, y, widthOfButton, 3, "Атака нейтралов", turretConfig.attacksNeutrals) + newObj("BottomButtons", "AttacksPlayers", x, y, x + widthOfButton - 1, y + 2) + x = drawButtonWithState(x, y, widthOfButton, 3, "Атака игроков", turretConfig.attacksPlayers) + newObj("BottomButtons", "Exit", x, y, x + widthOfButton - 1, y + 2) + x = drawButtonWithState(x, y, widthOfButton, 3, "Выход", false) +end + +local function drawAll() + buffer.clear(0x000000) + drawTurrets(yTurrets) + drawBottomBar() + buffer.draw() +end + +local function refresh() + turrets = {} + proxies = {} + getTurrets() + drawAll() +end + +local function changeTurretState(i, state) + turrets[i].isActive = state + turrets[i].energyPercent = math.ceil(turrets[i].proxy.getCurrentEnergyStorage() / turrets[i].proxy.getMaxEnergyStorage() * 100) + if state == true then + turrets[i].proxy.setAttacksNeutrals(turretConfig.attacksNeutrals) + turrets[i].proxy.setAttacksPlayers(turretConfig.attacksPlayers) + turrets[i].proxy.setAttacksMobs(turretConfig.attacksMobs) + else + turrets[i].proxy.setAttacksNeutrals(false) + turrets[i].proxy.setAttacksPlayers(false) + turrets[i].proxy.setAttacksMobs(false) + end +end + +------------------------------------------------------------------------------------------------------------------------------------- + +refresh() + +while true do + local e = {event.pull()} + if e[1] == "touch" then + if obj.TurretOn then + for key in pairs(obj.TurretOn) do + if ecs.clickedAtArea(e[3], e[4], obj.TurretOn[key][1], obj.TurretOn[key][2], obj.TurretOn[key][3], obj.TurretOn[key][4]) then + changeTurretState(key, true) + drawAll() + break + end + end + end + + if obj.TurretOff then + for key in pairs(obj.TurretOff) do + if ecs.clickedAtArea(e[3], e[4], obj.TurretOff[key][1], obj.TurretOff[key][2], obj.TurretOff[key][3], obj.TurretOff[key][4]) then + changeTurretState(key, false) + drawAll() + break + end + end + end + + for key in pairs(obj.BottomButtons) do + if ecs.clickedAtArea(e[3], e[4], obj.BottomButtons[key][1], obj.BottomButtons[key][2], obj.BottomButtons[key][3], obj.BottomButtons[key][4]) then + if key == "On" then + turretConfig.turretsOn = not turretConfig.turretsOn + for i = 1, #turrets do changeTurretState(i, turretConfig.turretsOn) end + drawAll() + elseif key == "AttacksNeutrals" then + turretConfig.attacksNeutrals = not turretConfig.attacksNeutrals + for i = 1, #turrets do changeTurretState(i, turrets[i].isActive) end + drawAll() + elseif key == "AttacksMobs" then + turretConfig.attacksMobs = not turretConfig.attacksMobs + for i = 1, #turrets do changeTurretState(i, turrets[i].isActive) end + drawAll() + elseif key == "AttacksPlayers" then + turretConfig.attacksPlayers = not turretConfig.attacksPlayers + for i = 1, #turrets do changeTurretState(i, turrets[i].isActive) end + drawAll() + elseif key == "AddPlayer" then + buffer.button(obj.BottomButtons[key][1], obj.BottomButtons[key][2], 19, 3, yellowColor, 0x000000, "Добавить игрока") + buffer.draw() + os.sleep(0.2) + drawAll() + local data = ecs.universalWindow("auto", "auto", 30, 0x1e1e1e, true, {"EmptyLine"}, {"CenterText", ecs.colors.orange, "Добавить игрока"}, {"EmptyLine"}, {"Input", 0xFFFFFF, ecs.colors.orange, "Никнейм"}, {"EmptyLine"}, {"Button", {ecs.colors.orange, 0xffffff, "OK"}, {0x999999, 0xffffff, "Отмена"}} ) + if data[2] == "OK" then for i = 1, #turrets do turrets[i].proxy.addTrustedPlayer(data[1]) end end + elseif key == "Exit" then + buffer.button(obj.BottomButtons[key][1], obj.BottomButtons[key][2], 19, 3, yellowColor, 0x000000, "Выход") + buffer.draw() + os.sleep(0.2) + buffer.clear(0x262626) + ecs.prepareToExit() + return + end + + break + end + end + + elseif e[1] == "scroll" then + if e[5] == 1 then + yTurrets = yTurrets + 2 + else + yTurrets = yTurrets - 2 + end + drawAll() + elseif e[1] == "component_added" or e[1] == "component_removed" then + if e[3] == "tierOneTurretBase" or e[3] == "tierTwoTurretBase" or e[3] == "tierThreeTurretBase" or e[3] == "tierFourTurretBase" or e[3] == "tierFiveTurretBase" then + refresh() + end + end +end + + + + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/TurretControl.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/TurretControl.app/Resources/About/Russian.txt new file mode 100755 index 00000000..9afc9140 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/TurretControl.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Приложение, предназначенное для управления турелями из мода OpenModularTurrets. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/TurretControl.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/TurretControl.app/Resources/Icon.pic new file mode 100755 index 00000000..9effbea4 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/TurretControl.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/TurretControl.app/Resources/Turret.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/TurretControl.app/Resources/Turret.pic new file mode 100755 index 00000000..46b99f7f Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/TurretControl.app/Resources/Turret.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/VK.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/VK.app/Main.lua new file mode 100755 index 00000000..5d147e58 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/VK.app/Main.lua @@ -0,0 +1,1367 @@ + +---------------------------------------------------- Библиотеки ---------------------------------------------------------------- + +local advancedLua = require("advancedLua") +local json = require("json") +local serialization = require("serialization") +local event = require("event") +local ecs = require("ECSAPI") +local fs = require("filesystem") +local buffer = require("doubleBuffering") +local context = require("context") +local image = require("image") +local unicode = require("unicode") +local component = require("component") +local computer = require("computer") +local GUI = require("GUI") +local MineOSCore = require("MineOSCore") +local MineOSPaths = require("MineOSPaths") + +---------------------------------------------------- Константы ---------------------------------------------------------------- + +local VKAPIVersion = "5.52" + +local colors = { + leftBar = 0x262626, + leftBarAlternative = 0x383838, + leftBarText = 0xFFFFFF, + leftBarSelection = 0x00A8FF, + leftBarSelectionText = 0xFFFFFF, + + scrollBar = 0xCCCCCC, + scrollBarPipe = 0x666666, + + mainZone = 0xFFFFFF, + senderCloudColor = 0x3392FF, + senderCloudTextColor = 0xFFFFFF, + yourCloudColor = 0x55BBFF, + yourCloudTextColor = 0xFFFFFF, + systemMessageColor = 0x555555, + dateTime = 0x777777, + + loginGUIBackground = 0x002440, + + topBar = 0x002440, + topBarText = 0xFFFFFF, + + statusBar = 0x1b1b1b, + statusBarText = 0xAAAAAA, + + audioPlayButton = 0x002440, + audioPlayButtonText = 0xFFFFFF, + + messageInputBarColor = 0xEEEEEE, + messageInputBarTextBackgroundColor = 0xFFFFFF, + messsageInputBarTextColor = 0x262626, +} + +local leftBarHeight = buffer.getHeight() - 9 +local leftBarWidth = math.floor(buffer.getWidth() * 0.20) + +local topBarHeight = 3 + +local mainZoneWidth = buffer.getWidth() - leftBarWidth +local mainZoneHeight = buffer.getHeight() - topBarHeight - 1 +local mainZoneX = leftBarWidth + 1 +local mainZoneY = topBarHeight + 1 + +local cloudWidth = math.floor(mainZoneWidth * 0.7) + +------------------------------------------------------------------------------------------------------------------------------- + +local settingsPath = MineOSPaths.applicationData .. "VK/Settings.cfg" +local VKLogoImagePath = MineOSCore.getCurrentApplicationResourcesDirectory() .. "VKLogo.pic" +-- local leftBarElements = {"Новости", "Друзья", "Сообщения", "Настройки", "Выход"} +local leftBarElements = { "Моя страница", "Друзья", "Сообщения", "Аудиозаписи", "Новости", "Настройки", "Выход" } +local currentLeftBarElement = 3 +local personalInfo +local access_token +local whatIsOnScreen + +local countOfDialogsToLoadFromServer = 10 +local countOfAudioToLoadFromServer = 10 +local countOfMessagesToLoadFromServer = 10 + +local dialogToShowFrom = 1 +local audioToShowFrom = 1 +local messageToShowFrom = 1 + +local dialogScrollSpeed = 5 +local audioScrollSpeed = 5 +local messagesScrollSpeed = 5 +local profileScrollSpeed = 2 +local friendsScrollSpeed = 5 + +local countOfFriendsToGetOnFriendsTab = 12 +local currentFriendsOffset = 0 +local currentFriends = {} + +local countOfFriendsToDisplayInProfile = 16 +local currentProfileY = mainZoneY + 2 + +local currentMessagesPeerID, currentMessagesAvatarText +local dialogPreviewTextLimit = mainZoneWidth - 15 +local currentProfile + +local settings = {saveAuthData = false, addSendingInfo = true} + +local vip = { + [7799889] = {avatarColor = 0x000000, avatarTextColor = 0xCCCCCC, avatarBottomText = "DEV", avatarBottomTextColor = 0x1b1b1b}, + [113499693] = {avatarColor = 0xFF99CC, avatarTextColor = 0x000000, avatarBottomText = "DEV", avatarBottomTextColor = 0xff6dbf}, + [60991376] = {avatarColor = 0xEEEEEE, avatarTextColor = 0x000000, avatarBottomText = "DEV", avatarBottomTextColor = 0x555555}, +} + +local messageEndAdderText = " (отправлено с MineOS VKClient)" + +local news +local currentNews = 1 +local countOfNewsToShow = 10 +local countOfNewsToGet = 20 + +---------------------------------------------------- Веб-часть ---------------------------------------------------------------- + +local function loadSettings() + if fs.exists(settingsPath) then settings = table.fromFile(settingsPath) end +end + +local function saveSettings() + table.toFile(settingsPath, settings) +end + +--Объекты +local obj = {} +local function newObj(class, name, ...) + obj[class] = obj[class] or {} + obj[class][name] = {...} +end + +--Дебаг-функция на сохранение говна в файл, МАЛО ЛИ ЧО +local function saveToFile(filename, stro4ka) + local file = io.open(filename, "w") + file:write(stro4ka) + file:close() +end + +--Банальный URL-запрос, декодирующийся через ЖУСОН в случае успеха, епты +local function request(url) + local success, response = ecs.internetRequest(url) + if success then + response = json:decode(response) + end + return success, response +end + +--Отправляем запрос на авторизацию по логину и паролю +local function getLoginDataRequest(username, password) + local url = "https://oauth.vk.com/token?grant_type=password&client_id=3697615&client_secret=AlVXZFMUqyrnABp8ncuU&username=" .. username .. "&password=" .. password .. "&v=" .. VKAPIVersion + return request(url) +end + +--Запрос к методам VK API +local function VKAPIRequest(method, ... ) + local arguments = { ... } + local stringArguments = "" + + local url = "https://api.vk.com/method/" .. method .. "?" .. table.concat(arguments, "&") .. "&access_token=" .. access_token .. "&v=" .. VKAPIVersion + + return request(url) +end + +--Запрос на получение списка диалогов +local function getDialogsRequest(fromDialog, count) + return VKAPIRequest("messages.getDialogs", "offset=" .. fromDialog, "count=" .. count, "preview_length=" .. dialogPreviewTextLimit) +end + +--Запрос на получение списка диалогов +local function getMessagesRequest(peerID, fromMessage, count) + return VKAPIRequest("messages.getHistory", "offset=" .. fromMessage, "count=" .. count, "peer_id=" .. peerID) +end + +--Запрос на получение списка музычки +local function getAudioRequest(id, fromAudio, count) + return VKAPIRequest("audio.get", "offset=" .. fromAudio, "count=" .. count, "owner_id=" .. id, "need_user=1") +end + +--Эта хуйня делает строку охуенной путем замены говна на конфетку +local function optimizeStringForURLSending(code) + if code then + code = string.gsub(code, "([^%w ])", function (c) + return string.format("%%%02X", string.byte(c)) + end) + code = string.gsub(code, " ", "+") + end + return code +end + +local function optimizeStringForWrongSymbols(s) + --Удаляем некорректные символы + s = string.gsub(s, " ", " ") + s = string.gsub(s, "\r\n", "\n") + s = string.gsub(s, "\n", "") + --Заменяем "широкие" двухпиксельные символы на знак вопроса + local massiv = {} + for i = 1, unicode.len(s) do + massiv[i] = unicode.sub(s, i, i) + if unicode.isWide(massiv[i]) then massiv[i] = "?" end + end + --Возвращаем оптимизрованную строку + return table.concat(massiv) +end + +local function convertIDtoPeerID(whatIsThisID, ID) + if whatIsThisID == "user" then + return ID + elseif whatIsThisID == "chat" then + return (2000000000 + ID) + elseif whatIsThisID == "group" then + return -ID + end +end + +local function getPeerIDFromMessageArray(messageArray) + local peerID + --Если это чат + if messageArray.users_count then + peerID = convertIDtoPeerID("chat", messageArray.chat_id) + --Или если это диалог с группой какой-то + elseif messageArray.user_id < 0 then + peerID = convertIDtoPeerID("group", messageArray.user_id) + --Или если просто какой-то сталкер-одиночка + else + peerID = convertIDtoPeerID("user", messageArray.user_id) + end + + return peerID +end + +--Запрос на отправку сообщения указанному пидору +local function sendMessageRequest(peerID, message) + --Делаем строчку не пидорской + message = optimizeStringForURLSending(message) + return VKAPIRequest("messages.send", "peer_id=" .. peerID, "message=" .. message) +end + +local function usersInformationRequest(...) + return VKAPIRequest("users.get", "user_ids=" .. table.concat({...}, ","), "fields=contacts,education,site,city,bdate,online,status,last_seen,quotes,about,games,books,counters,relatives,connections,blacklisted,activities,interests,music,movies,tv") +end + +local function userFriendsRequest(ID, count, offset, order, nameCase) + return VKAPIRequest("friends.get", "user_id=" .. ID, "count=" .. count, "offset=" .. offset, "order=" .. order, "name_case=" .. nameCase, "fields=domain,online,last_seen") +end + +local function userFriendsListsRequest(ID) + return VKAPIRequest("friends.getLists", "user_id=" .. ID, "return_system=1") +end + +local function userWallRequest(ID, count, offset) + return VKAPIRequest("wall.get", "owner_id=" .. ID, "count=" .. count, "offset=" .. offset) +end + +local function setCurrentAudioPlaying(ownerID, audioID) + return VKAPIRequest("audio.setBroadcast", "audio=" .. ownerID .. "_" .. audioID) +end + +local function newsRequest(count) + return VKAPIRequest("newsfeed.get", "filters=post", "return_banned=1", "max_photos=0", "count=" .. count, "fields=name,first_name,last_name") +end + +local function setCrazyTypingRequest(peer_id) + return VKAPIRequest("messages.setActivity", "type=typing", "peer_id=" .. peer_id) +end + + + + + +---------------------------------------------------- GUI-часть ---------------------------------------------------------------- + +local function createAvatarHashColor(hash) + return math.abs(hash % 0xFFFFFF) +end + +local function drawAvatar(x, y, width, height, user_id, text) + local avatarColor = createAvatarHashColor(user_id) + local textColor = avatarColor > 8388607 and 0x000000 or 0xFFFFFF + + --Хочу себе персональную авку, а то че за хуйня? + if vip[user_id] then + avatarColor = vip[user_id].avatarColor + textColor = vip[user_id].avatarTextColor + end + + buffer.square(x, y, width, height, avatarColor, textColor, " ") + buffer.text(x + math.floor(width / 2) - math.floor(unicode.len(text) / 2), y + math.floor(height / 2), textColor, unicode.upper(text)) + + if vip[user_id] and vip[user_id].avatarBottomText then buffer.text(x + math.floor(width / 2) - math.floor(unicode.len(text) / 2), y + height - 1, vip[user_id].avatarBottomTextColor, vip[user_id].avatarBottomText) end +end + +--Проверка клика в определенную область по "объекту". Кому на хуй вссалось ООП? +local function clickedAtZone(x, y, zone) + if x >= zone[1] and y >= zone[2] and x <= zone[3] and y <= zone[4] then + return true + end + return false +end + +--Интерфейс логина в аккаунт ВК, постараюсь сделать пографонистей +--Хотя хах! Кого я обманываю, ага +local function loginGUI(startUsername, startPassword) + local background = 0x002440 + local buttonColor = 0x666DFF + local textColor = 0x262626 + local username, password = startUsername, startPassword + + local textFieldWidth = 50 + local textFieldHeight = 3 + local x, y = math.floor(buffer.getWidth() / 2 - textFieldWidth / 2), math.floor(buffer.getHeight() / 2) + + local obj = {} + obj.username = {x, y, x + textFieldWidth - 1, y + 2}; y = y + textFieldHeight + 1 + obj.password = {x, y, x + textFieldWidth - 1, y + 2}; y = y + textFieldHeight + 1 + obj.button = GUI.button(x, y, textFieldWidth, textFieldHeight, buttonColor, 0xEEEEEE, 0xEEEEEE, buttonColor, "Войти") + + local VKLogoImage = image.load(VKLogoImagePath) + local loginTextBox = GUI.input(x, obj.username[2], textFieldWidth, 3, 0xEEEEEE, 0x777777, 0x777777, 0xEEEEEE, 0x262626, username, "E-Mail", false) + loginTextBox.parent = { draw = function() loginTextBox:draw() end } + loginTextBox.getFirstParent = function() return loginTextBox.parent end + + local passwordTextBox = GUI.input(x, obj.password[2], textFieldWidth, 3, 0xEEEEEE, 0x777777, 0x777777, 0xEEEEEE, 0x262626, password, "Password", false, "*") + passwordTextBox.parent = { draw = function() passwordTextBox:draw() end } + passwordTextBox.getFirstParent = function() return passwordTextBox.parent end + + + local function draw() + buffer.clear(colors.loginGUIBackground) + + buffer.image(x + 5, obj.username[2] - 15, VKLogoImage) + loginTextBox:draw() + passwordTextBox:draw() + obj.button:draw() + + buffer.draw() + end + + while true do + draw() + local e = {event.pull()} + if e[1] == "touch" then + if clickedAtZone(e[3], e[4], obj.username) then + loginTextBox.eventHandler({draw = function() loginTextBox:draw() end}, loginTextBox, {[1] = "touch", [3] = loginTextBox.x, [4] = loginTextBox.y}) + username = loginTextBox.text + + elseif clickedAtZone(e[3], e[4], obj.password) then + passwordTextBox.eventHandler({draw = function() passwordTextBox:draw() end}, passwordTextBox, {[1] = "touch", [3] = passwordTextBox.x, [4] = passwordTextBox.y}) + password = passwordTextBox.text + + elseif obj.button:isClicked(e[3], e[4]) then + obj.button:press(0.2) + draw() + local success, loginData = getLoginDataRequest(username or "", password or "") + if success then + if settings.saveAuthData then settings.username = username; settings.password = password; saveSettings() end + loginData.username = username + loginData.password = password + return loginData + else + GUI.error("Ошибка авторизации: " .. tostring(loginData)) + end + end + end + end +end + +---------------------------------------------------- GUI для взаимодействия с VK API ---------------------------------------------- + +local function drawPersonalAvatar(x, y, width, height) + drawAvatar(x, y, width, height, personalInfo.id, unicode.sub(personalInfo.first_name, 1, 1) .. unicode.sub(personalInfo.last_name, 1, 1)) +end + +local function status(text) + buffer.square(mainZoneX, buffer.getHeight(), mainZoneWidth, 1, colors.statusBar, 0x0, " ") + buffer.text(mainZoneX + 1, buffer.getHeight(), colors.statusBarText, text) + buffer.draw() +end + +local function drawTopBar(text) + buffer.square(mainZoneX, 1, mainZoneWidth, 3, colors.topBar, 0x0, " ") + local x = math.floor(mainZoneX + mainZoneWidth / 2 - unicode.len(text) / 2 - 1) + buffer.text(x, 2, colors.topBarText, text) +end + +--Рисуем главную зону +local function clearGUIZone() + buffer.square(mainZoneX, mainZoneY, mainZoneWidth, mainZoneHeight, colors.mainZone, 0x0, " ") +end + +local function drawEmptyCloud(x, y, cloudWidth, cloudHeight, cloudColor, fromYou) + local upperPixel = "▀" + local lowerPixel = "▄" + + --Рисуем финтифлюшечки + if not fromYou then + buffer.set(x, y - cloudHeight + 2, colors.mainZone, cloudColor, upperPixel) + buffer.set(x + 1, y - cloudHeight + 2, cloudColor, 0xFFFFFF, " ") + x = x + 2 + else + buffer.set(x + cloudWidth + 3, y - cloudHeight + 2, colors.mainZone, cloudColor, upperPixel) + buffer.set(x + cloudWidth + 2, y - cloudHeight + 2, cloudColor, 0xFFFFFF, " ") + end + + --Заполняшечки + buffer.square(x + 1, y - cloudHeight + 1, cloudWidth, cloudHeight, cloudColor, 0xFFFFFF, " ") + buffer.square(x, y - cloudHeight + 2, cloudWidth + 2, cloudHeight - 2, cloudColor, 0xFFFFFF, " ") + + --Сгругленные краешки + buffer.set(x, y - cloudHeight + 1, colors.mainZone, cloudColor, lowerPixel) + buffer.set(x + cloudWidth + 1, y - cloudHeight + 1, colors.mainZone, cloudColor, lowerPixel) + buffer.set(x, y, colors.mainZone, cloudColor, upperPixel) + buffer.set(x + cloudWidth + 1, y, colors.mainZone, cloudColor, upperPixel) + + return y - cloudHeight + 1 +end + +local function drawTextCloud(x, y, cloudColor, textColor, fromYou, text) + local y = drawEmptyCloud(x, y, cloudWidth, #text + 2, cloudColor, fromYou) + x = fromYou and x + 2 or x + 4 + + for i = 1, #text do + buffer.text(x, y + i, textColor, text[i]) + end + + return y +end + +local function getAttachments(messageArray) + local text = "Вложения: " + for j = 1, #messageArray.attachments do + if messageArray.attachments[j].type == "sticker" then + text = text .. "стикер, " + elseif messageArray.attachments[j].type == "photo" then + text = text .. "фото, " + elseif messageArray.attachments[j].type == "video" then + text = text .. "видео, " + elseif messageArray.attachments[j].type == "audio" then + text = text .. "аудио, " + elseif messageArray.attachments[j].type == "wall" then + text = text .. "запись на стене, " + end + end + text = unicode.sub(text, 1, -3) + + return text +end + +local function drawMessageInputBar(currentText) + local x, y = mainZoneX, buffer.getHeight() - 5 + buffer.square(x, y, mainZoneWidth, 5, colors.messageInputBarColor, 0x0, " ") + obj.messageInputBar = GUI.input(x + 2, y + 1, mainZoneWidth - 4, 3, 0xFFFFFF, 0x444444, 0x444444, 0xFFFFFF, 0x262626, nil, "Введите сообщение", true) + obj.messageInputBar.parent = { draw = function() obj.messageInputBar:draw() end } + obj.messageInputBar.getFirstParent = function() return obj.messageInputBar.parent end + obj.messageInputBar:draw() +end + +local function getUserNamesFromTheirIDs(IDsArray) + local success, usersData = usersInformationRequest(table.unpack(IDsArray)) + local userNames = {} + if success and usersData.response then + for i = 1, #usersData.response do + userNames[usersData.response[i].id] = { + first_name = usersData.response[i].first_name, + last_name = usersData.response[i].last_name, + } + end + end + return success, userNames +end + +local function messagesGUI() + + status("Загружаю историю переписки") + local success, messages = getMessagesRequest(currentMessagesPeerID, messageToShowFrom - 1, countOfMessagesToLoadFromServer) + if success and messages.response then + + whatIsOnScreen = "messages" + + if currentMessagesPeerID > 2000000000 then + status("Загружаю имена пользователей из переписки (актуально для конференций)") + + local IDsArray = {}; + for i = 1, #messages.response.items do table.insert(IDsArray, messages.response.items[i].user_id) end + local userNamesSuccess, userNames = getUserNamesFromTheirIDs(IDsArray) + for i = 1, #messages.response.items do + messages.response.items[i].first_name = userNames[messages.response.items[i].user_id].first_name or "N/A" + messages.response.items[i].last_name = userNames[messages.response.items[i].user_id].last_name or "N/A" + end + IDsArray = nil + end + + clearGUIZone() + drawTopBar("Сообщения") + + -- saveToFile("lastMessagesRequest.json", serialization.serialize(messages)) + + buffer.setDrawLimit(mainZoneX, mainZoneY, mainZoneX + mainZoneWidth - 1, mainZoneY + mainZoneHeight - 1) + + local y = buffer.getHeight() - 7 + local xSender = mainZoneX + 2 + local xYou = buffer.getWidth() - 7 + + for i = 1, #messages.response.items do + + local messageTextArray = {} + + --Если строка пиздатая + if messages.response.items[i].body ~= "" then table.insert(messageTextArray, optimizeStringForWrongSymbols(messages.response.items[i].body)) end + if messages.response.items[i].fwd_messages then table.insert(messageTextArray, "Пересланные сообщения") end + if messages.response.items[i].attachments then table.insert(messageTextArray, getAttachments(messages.response.items[i])) end + if messages.response.items[i].action == "chat_invite_user" then table.insert(messageTextArray, "Пользователь под ID " .. messages.response.items[i].from_id .. " пригласил в беседу пользователя под ID " .. messages.response.items[i].action_mid) end + + messageTextArray = string.wrap(messageTextArray, cloudWidth - 4) + local peerID = getPeerIDFromMessageArray(messages.response.items[i]) + + --Делаем дату пиздатой + -- messages.response.items[i].date = os.date("%d.%m.%y в %X", messages.response.items[i].date) + messages.response.items[i].date = os.date("%H:%M", messages.response.items[i].date) + + if messages.response.items[i].out == 1 then + y = drawTextCloud(xYou - cloudWidth - 6, y, colors.yourCloudColor, colors.yourCloudTextColor, true, messageTextArray) + drawPersonalAvatar(xYou, y, 6, 3) + buffer.text(xYou - cloudWidth - unicode.len(messages.response.items[i].date) - 8, y + 1, colors.dateTime, messages.response.items[i].date) + else + y = drawTextCloud(xSender + 8, y, colors.senderCloudColor, colors.senderCloudTextColor, false, messageTextArray) + drawAvatar(xSender, y, 6, 3, peerID, messages.response.items[i].first_name and (unicode.sub(messages.response.items[i].first_name, 1, 1) .. unicode.sub(messages.response.items[i].last_name, 1, 1)) or currentMessagesAvatarText) + buffer.text(xSender + cloudWidth + 14, y + 1, colors.dateTime, messages.response.items[i].date) + end + + y = y - 2 + end + + local currentText + + -- Создаем объект тырканья + drawMessageInputBar() + status("История переписки загружена, ожидаю ввода сообщения") + buffer.resetDrawLimit() + end +end + +local function drawDialog(y, dialogBackground, avatarID, avatarText, text1, text2, text3) + --Рисуем подложку под диалог нужного цвета + buffer.square(mainZoneX, y, mainZoneWidth, 5, dialogBackground, 0x0, " ") + --Рисуем аватарку, чо уж + drawAvatar(mainZoneX + 2, y + 1, 6, 3, avatarID, avatarText) + --Пишем все, что нужно + y = y + 1 + if text1 then buffer.text(mainZoneX + 10, y, 0x000000, text1); y = y + 1 end + if text2 then buffer.text(mainZoneX + 10, y, 0x555555, text2); y = y + 1 end + if text3 then buffer.text(mainZoneX + 10, y, 0x666666, text3); y = y + 1 end +end + +local function dialogsGUI() + + local success, dialogs = getDialogsRequest(dialogToShowFrom - 1, countOfDialogsToLoadFromServer) + if success and dialogs.response then + + whatIsOnScreen = "dialogs" + + obj.dialogList = {} + + clearGUIZone() + drawTopBar("Сообщения") + + --Ебашим КНОПАЧКИ спама + obj.crazyTypingButton = GUI.adaptiveButton(mainZoneX + 2, 2, 1, 0, 0xFFFFFF, colors.topBar, 0xAAAAAA, 0x000000, "CrazyTyping") + -- obj.spamButton = {buffer.adaptiveButton(obj.crazyTypingButton[3] + 2, 2, 1, 0, 0xFFFFFF, colors.topBar, "Спам")} + + --НУ ТЫ ПОНЯЛ, АГА + status("Получаю имена пользователей по ID") + local IDsArray = {} + for i = 1, #dialogs.response.items do + if not dialogs.response.items[i].message.chat_id and dialogs.response.items[i].message.user_id and dialogs.response.items[i].message.user_id > 0 then + table.insert(IDsArray, dialogs.response.items[i].message.user_id) + end + end + local userNamesSuccess, userNames = getUserNamesFromTheirIDs(IDsArray) + for i = 1, #dialogs.response.items do + if not dialogs.response.items[i].message.chat_id and dialogs.response.items[i].message.user_id and dialogs.response.items[i].message.user_id > 0 then + dialogs.response.items[i].message.title = userNames[dialogs.response.items[i].message.user_id].first_name or "N/A" .. " " .. userNames[dialogs.response.items[i].message.user_id].last_name or "" + end + end + + local y = mainZoneY + local avatarText = "" + local peerID + local color + + for i = 1, #dialogs.response.items do + --Ебемся с цветами + if dialogs.response.items[i].unread then + if i % 2 == 0 then + color = 0xCCDBFF + else + color = 0xCCDBFF + end + else + if i % 2 == 0 then + color = 0xEEEEEE + else + color = 0xFFFFFF + end + end + + avatarText = unicode.sub(dialogs.response.items[i].message.title, 1, 2) + peerID = getPeerIDFromMessageArray(dialogs.response.items[i].message) + + --Ебля с текстом диалога + local text1 = dialogs.response.items[i].message.title + local text2 + local text3 + + --Если это банальное сообщение + if dialogs.response.items[i].message.body and dialogs.response.items[i].message.body ~= "" then + text2 = optimizeStringForWrongSymbols(dialogs.response.items[i].message.body) + end + + --Если есть какие-либо пересланные сообщения, то + if dialogs.response.items[i].message.fwd_messages then + text3 = "Пересланные сообщения" + --Если есть какие-либо вложения, то + elseif dialogs.response.items[i].message.attachments then + text3 = getAttachments(dialogs.response.items[i].message) + end + + --Рисуем диалог + drawDialog(y, color, peerID, avatarText, text1, text2, text3) + + --Рисуем пиздюлинку, показывающую кол-во непрочитанных сообщений + if dialogs.response.items[i].unread and dialogs.response.items[i].unread ~= 0 then + local cyka = tostring(dialogs.response.items[i].unread) + local cykaWidth = unicode.len(cyka) + 2 + local cykaX = buffer.getWidth() - cykaWidth - 2 + buffer.square(cykaX, y + 2, cykaWidth, 1, ecs.colors.blue, 0x0, " ") + buffer.text(cykaX + 1, y + 2, 0xFFFFFF, cyka) + end + + obj.dialogList[i] = GUI.object(mainZoneX, y, mainZoneWidth, 5) + obj.dialogList[i][5], obj.dialogList[i][6], obj.dialogList[i][7], obj.dialogList[i][8], obj.dialogList[i][9] = peerID, avatarText, text1, text2, text3 + + y = y + 5 + end + end + + status("Список диалогов получен") +end + +--Гуишка аудиозаписей +--А-А-А-А!!!!! МОЙ КРАСИВЫЙ ТРЕУГОЛЬНИЧЕК PLAY, БЛЯДЬ!!!! ШТО ТЫ ДЕЛАЕШЬ, SANGAR, ПРЕКРАТИ!!!! +local function audioGUI(ID) + status("Загружаю список аудиозаписей") + local success, audios = getAudioRequest(ID, audioToShowFrom - 1, countOfAudioToLoadFromServer) + if success and audios.response then + whatIsOnScreen = "audio" + obj.audio = {} + clearGUIZone() + drawTopBar("Аудиозаписи " .. audios.response.items[1].name_gen) + + local y = mainZoneY + local color + for i = 2, #audios.response.items do + color = 0xFFFFFF + if i % 2 == 0 then color = 0xEEEEEE end + + buffer.square(mainZoneX, y, mainZoneWidth, 5, color, 0x0, " ") + obj.audio[i] = GUI.button(mainZoneX + 2, y + 1, 5, 3, colors.audioPlayButton, colors.audioPlayButtonText, 0x66FF80, colors.audioPlayButton, ">") + obj.audio[i][5] = audios.response.items[i] + + local x = mainZoneX + 9 + buffer.text(x, y + 1, colors.audioPlayButton, audios.response.items[i].artist) + x = x + unicode.len(audios.response.items[i].artist) + buffer.text(x, y + 1, 0x000000, " - " .. audios.response.items[i].title) + + x = mainZoneX + 9 + local hours = string.format("%02.f", math.floor(audios.response.items[i].duration / 3600)) + local minutes = string.format("%02.f", math.floor(audios.response.items[i].duration / 60 - (hours * 60))) + local seconds = string.format("%02.f", math.floor(audios.response.items[i].duration - hours * 3600 - minutes * 60)) + buffer.text(x, y + 2, 0x888888, "Длительность: " .. hours .. ":" .. minutes .. ":" .. seconds) + + y = y + 5 + end + else + GUI.error("Ошибка при получении списка аудиозаписей") + end +end + +local function checkField(field) + if field and field ~= "" and field ~= " " then return true end + return false +end + +local function userProfileRequest() + --Ебашим основную инфу + status("Загружаю информацию о пользователе под ID " .. currentProfile.ID) + local profileSuccess, userProfile = usersInformationRequest(currentProfile.ID) + + --Ебашим стену + status("Загружаю содержимое стены пользователя " .. currentProfile.ID) + local wallSuccess, wall = userWallRequest(currentProfile.ID, 20, currentProfile.wallOffset) + --Получаем инфу о юзверях со стены + local userNamesSuccess, userNames + if wallSuccess and wall.response then + local IDsArray = {} + for i = 1, #wall.response.items do table.insert(IDsArray, wall.response.items[i].from_id) end + status("Загружаю имена людей, оставивших сообщения на стене пользователя " .. currentProfile.ID) + userNamesSuccess, userNames = getUserNamesFromTheirIDs(IDsArray) + IDsArray = nil + end + + --Ебашим френдсов + status("Загружаю информацию о друзьях пользователя под ID " .. currentProfile.ID) + local friendsSuccess, friends = userFriendsRequest(currentProfile.ID, countOfFriendsToDisplayInProfile, 0, "random", "nom") + + --Анализируем на пиздатость + if (profileSuccess and userProfile.response) and (wallSuccess and wall.response) and (userNamesSuccess) and (friendsSuccess and friends.response) then + -- saveToFile("lastUserProfileRequest.json", serialization.serialize(userProfile)) + currentProfile.userProfile = userProfile + currentProfile.wall = wall + currentProfile.userNames = userNames + currentProfile.friends = friends + return true + else + GUI.error("Ошибка при загрузке информации о профиле") + return false + end +end + +local function userProfileGUI() + clearGUIZone() + whatIsOnScreen = "userProfile" + drawTopBar("Страница пользователя " .. currentProfile.ID) + + buffer.setDrawLimit(mainZoneX, mainZoneY, mainZoneX + mainZoneWidth - 1, mainZoneY + mainZoneHeight - 1) + + local xAvatar, yAvatar = mainZoneX + 4, currentProfileY + local x, y = xAvatar, yAvatar + local avatarWidth = 18 + local avatarHeight = math.floor(avatarWidth / 2) + + --Рисуем авку + currentProfile.avatarText = unicode.sub(currentProfile.userProfile.response[1].first_name, 1, 1) .. unicode.sub(currentProfile.userProfile.response[1].last_name, 1, 1) + drawAvatar(x, y, avatarWidth, avatarHeight, currentProfile.ID, currentProfile.avatarText) + --Рисуем имячко и статус + x = x + avatarWidth + 4 + buffer.text(x, y, 0x000000, currentProfile.userProfile.response[1].first_name .. " " .. currentProfile.userProfile.response[1].last_name); y = y + 1 + buffer.text(x, y, 0xAAAAAA, currentProfile.userProfile.response[1].status); y = y + 2 + + --Инфааааа + local informationOffset = 20 + local informationKeyColor = 0x888888 + local informationTitleColor = 0x000000 + local informationValueColor = 0x002440 + local informationSeparatorColor = 0xCCCCCC + + local function drawInfo(x, y2, key, value) + if checkField(value) then + value = {value} + value = string.wrap(value, buffer.getWidth() - x - 4 - informationOffset) + buffer.text(x, y2, informationKeyColor, key) + for i = 1, #value do + buffer.text(x + informationOffset, y2, informationValueColor, value[i]) + y2 = y2 + 1 + end + y = y2 + end + end + + local function drawSeparator(x, y2, text) + buffer.text(x, y2, informationTitleColor, text) + buffer.text(x + unicode.len(text) + 1, y2, informationSeparatorColor, string.rep("─", buffer.getWidth() - x - unicode.len(text))) + y = y + 1 + end + + drawSeparator(x, y, "Основная информация"); y = y + 1 + + drawInfo(x, y, "Дата рождения:", currentProfile.userProfile.response[1].bdate) + if currentProfile.userProfile.response[1].city then drawInfo(x, y, "Город:", currentProfile.userProfile.response[1].city.title) end + drawInfo(x, y, "Образование:", currentProfile.userProfile.response[1].university_name) + drawInfo(x, y, "Веб-сайт", currentProfile.userProfile.response[1].site); y = y + 1 + + drawSeparator(x, y, "Контактная информация"); y = y + 1 + + drawInfo(x, y, "Мобильный телефон:", currentProfile.userProfile.response[1].mobile_phone) + drawInfo(x, y, "Домашний телефон:", currentProfile.userProfile.response[1].home_phone) + drawInfo(x, y, "Skype:", currentProfile.userProfile.response[1].skype); y = y + 1 + + drawSeparator(x, y, "Личная информация"); y = y + 1 + + drawInfo(x, y, "Интересы:", currentProfile.userProfile.response[1].interests) + drawInfo(x, y, "Деятельность:", currentProfile.userProfile.response[1].activities) + drawInfo(x, y, "Любимая музыка:", currentProfile.userProfile.response[1].music) + drawInfo(x, y, "Любимая фильмы:", currentProfile.userProfile.response[1].movies) + drawInfo(x, y, "Любимая телешоу:", currentProfile.userProfile.response[1].tv) + drawInfo(x, y, "Любимая книги:", currentProfile.userProfile.response[1].books) + drawInfo(x, y, "Любимая игры:", currentProfile.userProfile.response[1].games) + drawInfo(x, y, "О себе:", currentProfile.userProfile.response[1].about) + + -- А ВОТ И СТЕНОЧКА ПОДЪЕХАЛА НА ПРАЗДНИК ДУШИ + y = y + 1 + buffer.square(x, y, buffer.getWidth() - x - 2, 1, 0xCCCCCC, 0x0, " "); buffer.text(x + 1, y, 0x262626, "Стена"); y = y + 2 + --Перебираем всю стенку + for i = 1, #currentProfile.wall.response.items do + --Если это не репост или еще не хуйня какая-то + if currentProfile.wall.response.items[i].text ~= "" then + -- GUI.error(userNames) + drawAvatar(x, y, 6, 3, currentProfile.wall.response.items[i].from_id, unicode.sub(currentProfile.userNames[currentProfile.wall.response.items[i].from_id].first_name, 1, 1) .. unicode.sub(currentProfile.userNames[currentProfile.wall.response.items[i].from_id].last_name, 1, 1)) + buffer.text(x + 8, y, informationValueColor, currentProfile.userNames[currentProfile.wall.response.items[i].from_id].first_name .. " " .. currentProfile.userNames[currentProfile.wall.response.items[i].from_id].last_name) + local date = os.date("%d.%m.%y в %H:%M", currentProfile.wall.response.items[i].date) + buffer.text(buffer.getWidth() - unicode.len(date) - 2, y, 0xCCCCCC, date) + y = y + 1 + local text = {currentProfile.wall.response.items[i].text} + text = string.wrap(text, buffer.getWidth() - x - 10) + for i = 1, #text do + buffer.text(x + 8, y, 0x000000, text[i]) + y = y + 1 + end + y = y + 1 + if #text == 1 then y = y + 1 end + end + end + + --ПодАвочная параша + informationOffset = 13 + x, y = xAvatar, yAvatar + y = y + avatarHeight + 1 + + currentProfile.avatarWidth = avatarWidth + currentProfile.sendMessageButton = GUI.button(x, y, avatarWidth, 1, 0xCCCCCC, 0x000000, 0x888888, 0x000000,"Сообщение") + y = y + 2 + currentProfile.audiosButton = GUI.button(x, y, avatarWidth, 1, 0xCCCCCC, 0x000000, 0x888888, 0x000000, "Аудиозаписи") + y = y + 2 + + drawInfo(x, y, "Подписчики: ", tostring(currentProfile.userProfile.response[1].counters.followers)) + drawInfo(x, y, "Фотографии: ", currentProfile.userProfile.response[1].counters.photos) + drawInfo(x, y, "Видеозаписи: ", currentProfile.userProfile.response[1].counters.videos) + drawInfo(x, y, "Аудиозаписи: ", currentProfile.userProfile.response[1].counters.audios) + + --Друзяшки, ЕПТАААААА, АХАХАХАХАХАХАХАХАХА + y = y + 1 + buffer.square(x, y, avatarWidth, 1, 0xCCCCCC, 0x0, " "); buffer.text(x + 1, y, 0x262626, "Друзья (" .. currentProfile.userProfile.response[1].counters.friends .. ")"); y = y + 2 + local xPos, yPos = x + 1, y + local count = 1 + for i = 1, #currentProfile.friends.response.items do + drawAvatar(xPos, yPos, 6, 3, currentProfile.friends.response.items[i].id, unicode.sub(currentProfile.friends.response.items[i].first_name, 1, 1) .. unicode.sub(currentProfile.friends.response.items[i].last_name, 1, 1)) + buffer.text(xPos - 1, yPos + 3, 0x000000, ecs.stringLimit("end", currentProfile.friends.response.items[i].first_name .. " " .. currentProfile.friends.response.items[i].last_name, 8)) + xPos = xPos + 10 + if i % 2 == 0 then xPos = x + 1; yPos = yPos + 5 end + count = count + 1 + if count > countOfFriendsToDisplayInProfile then break end + end + + buffer.resetDrawLimit() +end + +local function loadAndShowProfile(ID) + currentProfileY = mainZoneY + 2 + currentProfile = {ID = ID, wallOffset = 0} + if userProfileRequest() then userProfileGUI(currentProfile.ID) end +end + +local function friendsGUI() + status("Загружаю список друзей") + local success, friends = userFriendsRequest(personalInfo.id, countOfFriendsToGetOnFriendsTab, currentFriendsOffset, "hints", "nom") + status("Загружаю список категорий друзей") + local successLists, friendsLists = userFriendsListsRequest(personalInfo.id) + if (success and friends.response) and (successLists and friendsLists.response) then + -- saveToFile("lastFriendsResponse.json", serialization.serialize(friends)) + clearGUIZone() + currentFriends = {sendMessageButtons = {}, openProfileButtons = {}} + whatIsOnScreen = "friends" + drawTopBar("Друзья") + buffer.setDrawLimit(mainZoneX, mainZoneY, mainZoneX + mainZoneWidth - 1, mainZoneY + mainZoneHeight - 1) + + local function getListName(listID) + local name = "N/A" + for i = 1, #friendsLists.response.items do + if friendsLists.response.items[i].id == listID then + name = friendsLists.response.items[i].name + break + end + end + return name + end + + local x, y = mainZoneX + 2, mainZoneY + for i = 1, #friends.response.items do + --Падложка + if i % 2 == 0 then buffer.square(mainZoneX, y, mainZoneWidth, 5 + (friends.response.items[i].lists and 1 or 0), 0xEEEEEE, 0x0, " ") end + --Юзер + y = y + 1 + local subbedName = unicode.sub(friends.response.items[i].first_name, 1, 1) .. unicode.sub(friends.response.items[i].last_name, 1, 1) + drawAvatar(x, y, 6, 3, friends.response.items[i].id, subbedName) + local text = friends.response.items[i].first_name .. " " .. friends.response.items[i].last_name + buffer.text(x + 8, y, colors.topBar, text) + local text2 = friends.response.items[i].last_seen and (", " .. (friends.response.items[i].online == 1 and "онлайн" or "был(а) в сети " .. os.date("%d.%m.%y в %H:%M", friends.response.items[i].last_seen.time))) or " " + buffer.text(x + 8 + unicode.len(text), y, 0xAAAAAA, text2) + + if friends.response.items[i].lists then + y = y + 1 + local cykaX = x + 8 + for listID = 1, #friends.response.items[i].lists do + local listName = getListName(friends.response.items[i].lists[listID]) + local listWidth = unicode.len(listName) + 2 + local listBackColor = math.floor(0xFFFFFF / friends.response.items[i].lists[listID]) + local listTextColor = (listBackColor > 0x7FFFFF and 0x000000 or 0xFFFFFF) + buffer.square(cykaX, y, listWidth, 1, listBackColor, listTextColor, " ") + buffer.text(cykaX + 1, y, listTextColor, listName) + cykaX = cykaX + listWidth + 2 + end + end + + y = y + 1 + buffer.text(x + 8, y, 0x999999, "Написать сообщение") + currentFriends.sendMessageButtons[friends.response.items[i].id] = {x + 8, y, x + 18, y, subbedName} + y = y + 1 + buffer.text(x + 8, y, 0x999999, "Открыть профиль") + currentFriends.openProfileButtons[friends.response.items[i].id] = {x + 8, y, x + 18, y, subbedName} + + y = y + 2 + end + + buffer.resetDrawLimit() + else + GUI.error("Ошибка при получении списка друзей пользователя") + end +end + +local function newsGUI() + clearGUIZone() + drawTopBar("Новости") + whatIsOnScreen = "news" + buffer.setDrawLimit(mainZoneX, mainZoneY, mainZoneX + mainZoneWidth - 1, mainZoneY + mainZoneHeight - 1) + + local function getAvatarTextAndNameForNews(source_id) + local avatarText, name = "N/A", "N/A" + if source_id < 0 then + for i = 1, #news.response.groups do + if news.response.groups[i].id == math.abs(source_id) then + avatarText = unicode.sub(news.response.groups[i].name, 1, 2) + name = news.response.groups[i].name + break + end + end + else + for i = 1, #news.response.profiles do + if news.response.profiles[i].id == source_id then + avatarText = unicode.sub(news.response.profiles[i].first_name, 1, 1) .. unicode.sub(news.response.profiles[i].last_name, 1, 1) + name = news.response.profiles[i].first_name .. " " .. news.response.profiles[i].last_name + break + end + end + end + return avatarText, name + end + + local x, y = mainZoneX + 2, mainZoneY + for item = currentNews, currentNews + countOfNewsToShow do + if news.response.items[item] then + --Делаем текст пиздатым + news.response.items[item].text = optimizeStringForWrongSymbols(news.response.items[item].text) + --Убираем говно из новостей + if news.response.items[item].text == "" then + if news.response.items[item].copy_history then + news.response.items[item].text = "Репост" + elseif news.response.items[item].attachments then + news.response.items[item].text = getAttachments(news.response.items[item]) + end + end + --Делаем его еще пизже + local text = {news.response.items[item].text}; text = string.wrap(text, buffer.getWidth() - x - 10) + --Получаем инфу нужную + local avatarText, name = getAvatarTextAndNameForNews(news.response.items[item].source_id) + --Сместиться потом на стока вот + local yShift = 5 + if #text > 2 then yShift = yShift + #text - 2 end + + --Рисуем авку и название хуйни + if item % 2 == 0 then buffer.square(mainZoneX, y, mainZoneWidth, yShift, 0xEEEEEE, 0x0, " ") end + drawAvatar(x, y + 1, 6, 3, math.abs(news.response.items[item].source_id), avatarText) + buffer.text(x + 7, y + 1, colors.topBar, name) + --Рисуем текст + for line = 1, #text do + buffer.text(x + 7, y + line + 1, 0x000000, text[line]) + end + + y = y + yShift + end + end + + buffer.resetDrawLimit() +end + +local function getAndShowNews() + status("Загружаю список новостей") + local success, news1 = newsRequest(countOfNewsToGet) + if success and news1.response then + news = news1 + currentNews = 1 + newsGUI() + else + GUI.error("Ошибка при получении списка новостей") + end +end + +local function drawLeftBar() + --Подложка под элементы + buffer.square(1, 1, leftBarWidth, buffer.getHeight(), colors.leftBar, 0xFFFFFF, " ") + + if personalInfo then + drawPersonalAvatar(3, 2, 6, 3) + buffer.text(11, 3, 0xFFFFFF, ecs.stringLimit("end", personalInfo.first_name .. " " .. personalInfo.last_name, leftBarWidth - 11)) + end + + --Элементы + obj.leftBar = {} + local y, color = 6 + for i = 1, #leftBarElements do + color = colors.leftBarAlternative + if i % 2 == 0 then color = colors.leftBar end + if i == currentLeftBarElement then color = colors.leftBarSelection end + + newObj("leftBar", i, 1, y, leftBarWidth, y + 2) + + buffer.square(1, y, leftBarWidth, 3, color, 0xFFFFFF, " ") + y = y + 1 + buffer.text(3, y, colors.leftBarText, ecs.stringLimit("end", leftBarElements[i], leftBarWidth - 4)) + y = y + 2 + end +end + +--Главное ГУИ с левтбаром и прочим +local function mainGUI() + drawLeftBar() + --Отображаем гую нужную выбранную + if leftBarElements[currentLeftBarElement] == "Сообщения" then + status("Получаю список диалогов") + messageToShowFrom = 1 + dialogToShowFrom = 1 + dialogsGUI() + elseif leftBarElements[currentLeftBarElement] == "Аудиозаписи" then + status("Получаю список аудозаписей") + audioToShowFrom = 1 + audioGUI(personalInfo.id) + elseif leftBarElements[currentLeftBarElement] == "Моя страница" then + loadAndShowProfile(personalInfo.id) + -- loadAndShowProfile(186860159) + elseif leftBarElements[currentLeftBarElement] == "Друзья" then + friendsGUI() + elseif leftBarElements[currentLeftBarElement] == "Новости" then + getAndShowNews() + end + + buffer.draw() +end + +local function spam(id) + while true do + local randomMessages = { + "Ты мое золотце", + "Ты никогда не сделаешь сайт", + "Ты ничтожество", + "Твоя жизнь ничего не значит", + "Ты ничего не добьешься", + "Ты завалишь экзамены", + "Ты никому не нужна", + "Ты не напишешь курсовую", + "Твое животное помрет завтра", + "Не добавляй в ЧС!", + "Передаем привет от Яши и Меня (а кто я?)", + "Хуй!", + "Пизда!", + "Залупа!", + "Пенис!", + "Хер!", + "Давалка!" + } + local text = randomMessages[math.random(1, #randomMessages)] .. " (с любовью, отправлено с OpenComputers)" + sendMessageRequest(tostring(id), text) + print("Отправляю сообщение: " .. text) + os.sleep(2) + end +end + + +---------------------------------------------------- Старт скрипта ---------------------------------------------------------------- + +--Инициализируем библиотеку двойного буффера +--Эх, что бы я делал, если б не накодил ее? 0.2 фпс на GPU мертвеца! +buffer.flush() +--Хуярим настррррроечки +loadSettings() +--Активируем форму логина +local loginData = loginGUI(settings.username, settings.password) +access_token = loginData.access_token +--Получаем персональные данные +_, personalInfo = usersInformationRequest(loginData.user_id) +personalInfo = personalInfo.response[1] + +-- --Ебемся в попчанский +-- spam(21321257) + +--Активируем главное GUI +clearGUIZone() +mainGUI() + +while true do + local e = {event.pull()} + if e[1] == "touch" then + + if whatIsOnScreen == "audio" then + for key in pairs(obj.audio) do + if obj.audio[key]:isClicked(e[3], e[4]) then + obj.audio[key]:press(0.2) + + if component.isAvailable("openfm_radio") then + component.openfm_radio.stop() + component.openfm_radio.setURL(obj.audio[key][5].url) + component.openfm_radio.start() + status("Вывожу в статус играемую музыку") + setCurrentAudioPlaying(currentProfile and currentProfile.ID or personalInfo.id, obj.audio[key][5].id) + else + GUI.error("Эта функция доступна только при наличии установленного мода OpenFM, добавляющего полноценное интернет-радио") + end + + break + end + end + end + + if whatIsOnScreen == "dialogs" then + for key in pairs(obj.dialogList) do + if obj.dialogList[key]:isClicked(e[3], e[4]) then + drawDialog(obj.dialogList[key].y, 0xFF8888, obj.dialogList[key][5], obj.dialogList[key][6], obj.dialogList[key][7], obj.dialogList[key][8], obj.dialogList[key][9]) + buffer.draw() + os.sleep(0.2) + status("Загружаю переписку с пользователем " .. obj.dialogList[key][7]) + currentMessagesPeerID = obj.dialogList[key][5] + currentMessagesAvatarText = obj.dialogList[key][6] + messagesGUI() + break + end + end + + if obj.crazyTypingButton:isClicked(e[3], e[4]) then + obj.crazyTypingButton:press(0.2) + local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "CrazyTyping"}, + {"EmptyLine"}, + {"Slider", 0xFFFFFF, ecs.colors.orange, 1, 15, 5, "Количество диалогов: ", ""}, + {"Slider", 0xFFFFFF, ecs.colors.orange, 1, 100, 5, "Количество запросов: ", ""}, + {"Slider", 0xFFFFFF, ecs.colors.orange, 1, 5000, 500, "Задержка между запросами: ", " мс"}, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0xffffff, "OK"}, {0x999999, 0xffffff, "Отмена"}} + ) + if data[4] == "OK" then + for i = 1, data[2] do + local count = 1 + for key in pairs(obj.dialogList) do + -- GUI.error("Ебашу спам диалогу под пиром: " .. obj.dialogList[key][5]) + ecs.info("auto", "auto", "CrazyTyping", "Запрос: " .. i .. " из " .. data[2] .. ", диалог: " .. count .. " из ".. data[1] .. ", peerID: " .. obj.dialogList[key][5]) + setCrazyTypingRequest(obj.dialogList[key][5]) + count = count + 1 + if count > data[1] then break end + os.sleep(data[3] / 1000) + end + end + buffer.draw(true) + end + end + end + + if whatIsOnScreen == "messages" then + if obj.messageInputBar:isClicked(e[3], e[4]) then + obj.messageInputBar.eventHandler({draw = function() obj.messageInputBar:draw() end}, obj.messageInputBar, {[1] = "touch", [3] = obj.messageInputBar.x, [4] = obj.messageInputBar.y}) + local newText = obj.messageInputBar.text + if newText and newText ~= " " and newText ~= "" then + computer.beep(1700) + status("Отправляю сообщение пользователю") + sendMessageRequest(currentMessagesPeerID, newText .. (settings.addSendingInfo and messageEndAdderText or "")) + status("Обновляю историю переписки") + messageToShowFrom = 1 + messagesGUI() + end + drawMessageInputBar() + end + end + + if whatIsOnScreen == "userProfile" then + if currentProfile.audiosButton:isClicked(e[3], e[4]) then + currentProfile.audiosButton:press(0.2) + audioToShowFrom = 1 + audioGUI(currentProfile.ID) + buffer.draw() + elseif currentProfile.sendMessageButton:isClicked(e[3], e[4]) then + currentProfile.sendMessageButton:press(0.2) + currentMessagesPeerID = currentProfile.ID + messageToShowFrom = 1 + currentMessagesAvatarText = currentProfile.avatarText + messagesGUI() + end + end + + if whatIsOnScreen == "friends" then + for ID in pairs(currentFriends.sendMessageButtons) do + if clickedAtZone(e[3], e[4], currentFriends.sendMessageButtons[ID]) then + buffer.text(currentFriends.sendMessageButtons[ID][1], currentFriends.sendMessageButtons[ID][2], 0x000000, "Написать сообщение") + buffer.draw() + currentMessagesPeerID = ID + messageToShowFrom = 1 + currentMessagesAvatarText = currentFriends.sendMessageButtons[ID][5] + messagesGUI() + break + end + end + + for ID in pairs(currentFriends.openProfileButtons) do + if clickedAtZone(e[3], e[4], currentFriends.openProfileButtons[ID]) then + buffer.text(currentFriends.openProfileButtons[ID][1], currentFriends.openProfileButtons[ID][2], 0x000000, "Открыть профиль") + buffer.draw() + loadAndShowProfile(ID) + buffer.draw() + break + end + end + end + + for key in pairs(obj.leftBar) do + if clickedAtZone(e[3], e[4], obj.leftBar[key]) then + -- GUI.error("Кликнули на лефт бар ээлемент") + local oldLeftBarElement = currentLeftBarElement + currentLeftBarElement = key + + drawLeftBar() + buffer.draw() + + if leftBarElements[currentLeftBarElement] == "Выход" then + os.sleep(0.3) + buffer.clear(0x262626) + ecs.prepareToExit() + return + elseif leftBarElements[currentLeftBarElement] == "Аудиозаписи" then + currentProfile = currentProfile or {} + currentProfile.ID = personalInfo.id + elseif leftBarElements[currentLeftBarElement] == "Настройки" then + local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "Настройки"}, + {"EmptyLine"}, + {"Switch", ecs.colors.orange, 0xffffff, 0xFFFFFF, "Сохранять данные авторизации", settings.saveAuthData}, + {"EmptyLine"}, + {"Switch", ecs.colors.orange, 0xffffff, 0xFFFFFF, "Добавлять приписку \"Отправлено с ...\"", settings.addSendingInfo}, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "OpenComputers VK Client v4.0"}, + {"EmptyLine"}, + {"CenterText", ecs.colors.white, "Автор: Игорь Тимофеев, vk.com/id7799889"}, + {"CenterText", ecs.colors.white, "Все права защищены, епта! Попробуй только спиздить!"}, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0xffffff, "OK"}, {0x999999, 0xffffff, "Отмена"}} + ) + if data[3] == "OK" then + settings.saveAuthData = data[1] + settings.addSendingInfo = data[2] + + if settings.saveAuthData then + settings.username = loginData.username + settings.password = loginData.password + else + settings.username = nil + settings.password = nil + end + saveSettings() + + currentLeftBarElement = oldLeftBarElement + end + end + + mainGUI() + break + end + end + elseif e[1] == "scroll" then + if e[5] == 1 then + if whatIsOnScreen == "dialogs" then + dialogToShowFrom = dialogToShowFrom - dialogScrollSpeed + if dialogToShowFrom < 1 then dialogToShowFrom = 1 end + status("Прокручиваю диалоги, отправляю запрос на сервер") + dialogsGUI() + buffer.draw() + elseif whatIsOnScreen == "messages" then + messageToShowFrom = messageToShowFrom + messagesScrollSpeed + status("Прокручиваю сообщения, отправляю запрос на сервер") + messagesGUI() + buffer.draw() + elseif whatIsOnScreen == "audio" then + audioToShowFrom = audioToShowFrom - audioScrollSpeed + if audioToShowFrom < 1 then audioToShowFrom = 1 end + status("Прокручиваю аудозаписи, отправляю запрос на сервер") + audioGUI(currentProfile and currentProfile.ID or personalInfo.id) + buffer.draw() + elseif whatIsOnScreen == "userProfile" then + currentProfileY = currentProfileY + profileScrollSpeed + if currentProfileY > mainZoneY + 2 then currentProfileY = mainZoneY + 2 end + userProfileGUI() + buffer.draw() + elseif whatIsOnScreen == "friends" then + currentFriendsOffset = currentFriendsOffset - friendsScrollSpeed + if currentFriendsOffset < 0 then currentFriendsOffset = 0 end + friendsGUI() + buffer.draw() + elseif whatIsOnScreen == "news" then + currentNews = currentNews - 1 + if currentNews < 1 then currentNews = 1 end + newsGUI() + buffer.draw() + end + else + if whatIsOnScreen == "dialogs" then + dialogToShowFrom = dialogToShowFrom + dialogScrollSpeed + status("Прокручиваю диалоги, отправляю запрос на сервер") + dialogsGUI() + buffer.draw() + elseif whatIsOnScreen == "messages" then + messageToShowFrom = messageToShowFrom - messagesScrollSpeed + if messageToShowFrom < 1 then messageToShowFrom = 1 end + status("Прокручиваю сообщения, отправляю запрос на сервер") + messagesGUI() + buffer.draw() + elseif whatIsOnScreen == "audio" then + audioToShowFrom = audioToShowFrom + audioScrollSpeed + status("Прокручиваю аудозаписи, отправляю запрос на сервер") + audioGUI(currentProfile and currentProfile.ID or personalInfo.id) + buffer.draw() + elseif whatIsOnScreen == "userProfile" then + currentProfileY = currentProfileY - profileScrollSpeed + userProfileGUI() + buffer.draw() + elseif whatIsOnScreen == "friends" then + currentFriendsOffset = currentFriendsOffset + friendsScrollSpeed + friendsGUI() + buffer.draw() + elseif whatIsOnScreen == "news" then + currentNews = currentNews + 1 + newsGUI() + buffer.draw() + end + end + end +end + +-- local success, dialogs = getDialogsRequest(0, 5) +-- saveToFile(serialization.serialize(dialogs)) + + +-- sendMessageRequest(dialogs.response.items[2], "тестовое сообщение, отправлено через OpenComputers VK Client by Игорь, епта") + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/VK.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/VK.app/Resources/About/Russian.txt new file mode 100755 index 00000000..dc55052e --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/VK.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Полноценный клиент для сайта VK.com, позволяющий общаться с вашими друзьями, просматривать основную информацию их профилей, читать новостную ленту, а также прослушивать аудиозаписи. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/VK.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/VK.app/Resources/Icon.pic new file mode 100755 index 00000000..c4363302 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/VK.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/VK.app/Resources/VKLogo.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/VK.app/Resources/VKLogo.pic new file mode 100755 index 00000000..a6a2e932 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/VK.app/Resources/VKLogo.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Main.lua new file mode 100755 index 00000000..3cc39a86 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Main.lua @@ -0,0 +1,156 @@ + +require("advancedLua") +local web = require("web") +local json = require("json") +local fs = require("filesystem") +local bigLetters = require("bigLetters") +local buffer = require("doubleBuffering") +local image = require("image") +local unicode = require("unicode") +local component = require("component") +local GUI = require("GUI") +local MineOSCore = require("MineOSCore") +local MineOSInterface = require("MineOSInterface") +local MineOSPaths = require("MineOSPaths") + +-------------------------------------------------------------------------------------------------------- + +local mainContainer, window = MineOSInterface.addWindow(MineOSInterface.filledWindow(1, 1, 130, 30, 0)) +window.backgroundPanel.colors.transparency = 0.2 + +local weatherContainer = window:addChild(GUI.container(1, 1, 1, 23)) + +local resources = MineOSCore.getCurrentApplicationResourcesDirectory() +local weatherIcons = { + sunny = image.load(resources .. "Sunny.pic"), + sunnyAndCloudy = image.load(resources .. "Icon.pic"), + snowy = image.load(resources .. "Snowy.pic"), + rainy = image.load(resources .. "Rainy.pic"), + cloudy = image.load(resources .. "Cloudy.pic"), + thundery = image.load(resources .. "Stormy.pic"), + foggy = image.load(resources .. "Foggy.pic"), +} + +-------------------------------------------------------------------------------------------------------- + +local function newWeather(x, y, day) + local object = GUI.object(x, y, 14, 11) + + local type + if day.weather[1].id == 800 then + type = "sunny" + elseif day.weather[1].id == 801 then + type = "sunnyAndCloudy" + elseif day.weather[1].id >= 800 then + type = "cloudy" + elseif day.weather[1].id >= 700 then + type = "foggy" + elseif day.weather[1].id >= 600 then + type = "snowy" + elseif day.weather[1].id >= 300 then + type = "rainy" + elseif day.weather[1].id >= 200 then + type = "thundery" + else + type = "sunnyAndCloudy" + end + + local temp = math.round(day.temp.min) .. " / " .. math.round(day.temp.max) .. " °C" + local pressure = math.round(day.pressure / 1.33322387415) .. " mm Hg" + local humidity = math.round(day.humidity) .. "%" + local winds = { + [0] = "N", + [1] = "NE", + [2] = "E", + [3] = "SE", + [4] = "S", + [5] = "SW", + [6] = "W", + [7] = "NW", + [8] = "N", + } + local wind = day.speed .. " m/s, " .. (winds[math.round(day.deg / 45)] or "N/A") + + local function centerText(y, color, text) + buffer.text(math.floor(object.x + object.width / 2 - unicode.len(text) / 2), y, color, text) + end + + object.draw = function() + centerText(object.y, 0xFFFFFF, os.date("%a", day.dt)) + buffer.image(object.x + 3, object.y + 2, weatherIcons[type]) + centerText(object.y + 7, 0xFFFFFF, temp) + centerText(object.y + 8, 0xDDDDDD, wind) + centerText(object.y + 9, 0xBBBBBB, pressure) + centerText(object.y + 10, 0x999999, humidity) + end + + return object +end + +local function updateForecast(city) + local result, reason = web.request("http://api.openweathermap.org/data/2.5/forecast/daily?&appid=98ba4333281c6d0711ca78d2d0481c3d&units=metric&cnt=17&q=" .. web.encode(city)) + if result then + result = json:decode(result) + + if result.list then + weatherContainer:deleteChildren() + + local x, y = 1, 1 + local currentDay = result.list[1] + local object = weatherContainer:addChild(GUI.object(x + 2, y, 40, 8)) + object.draw = function() + bigLetters.drawText(object.x, object.y, 0xFFFFFF, math.round((currentDay.temp.max + currentDay.temp.min) / 2) .. "°") + buffer.text(object.x, object.y + 6, 0xFFFFFF, result.city.name .. ", " .. result.city.country) + buffer.text(object.x, object.y + 7, 0xFFFFFF, "Population: " .. math.shorten(result.city.population, 2)) + end + + y = y + object.height + 1 + + local input = weatherContainer:addChild(GUI.input(x + 2, y, 25, 1, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, "", "Type city name here")) + input.onInputFinished = function() + updateForecast(input.text) + input.text = "" + + mainContainer:draw() + buffer.draw() + end + + y = y + input.height + 2 + + for i = 1, #result.list do + local object = weatherContainer:addChild(newWeather(x, y, result.list[i])) + x = x + object.width + 2 + end + else + GUI.error(result.message) + end + else + GUI.error("Wrong result. Check city name and try again.") + end +end + + +-------------------------------------------------------------------------------------------------------- + +window.onResize = function(width, height) + window.backgroundPanel.width = width + window.backgroundPanel.height = height + weatherContainer.width = width + weatherContainer.localY = height - weatherContainer.height - 1 + weatherContainer.localX = 3 +end + +window:resize(window.width, window.height) + +updateForecast("Санкт-Петербург") + + + + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/About/Russian.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/About/Russian.txt new file mode 100755 index 00000000..31b9dabb --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/About/Russian.txt @@ -0,0 +1 @@ +Просматривайте информацию о погоде прямо из мира Minecraft! Просто введите название города и наслаждайтесь приятным интерфейсом, украшающим любое жилище. \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Cloudy.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Cloudy.pic new file mode 100755 index 00000000..08a860a4 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Cloudy.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Foggy.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Foggy.pic new file mode 100755 index 00000000..85a69089 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Foggy.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Icon.pic new file mode 100644 index 00000000..f1b0f8f1 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Rainy.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Rainy.pic new file mode 100755 index 00000000..d4453d92 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Rainy.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Snowy.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Snowy.pic new file mode 100755 index 00000000..b5d88d23 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Snowy.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Stormy.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Stormy.pic new file mode 100755 index 00000000..c8e4709d Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Stormy.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Sunny.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Sunny.pic new file mode 100644 index 00000000..8ee51d70 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Applications/Weather.app/Resources/Sunny.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/.icons b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/.icons new file mode 100644 index 00000000..e847dad3 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/.icons @@ -0,0 +1 @@ +{["Radio.lnk"]={["y"]=16,["x"]=42},["Palette.lnk"]={["y"]=16,["x"]=3},["CodeDoor.lnk"]={["y"]=9,["x"]=29},["VK.lnk"]={["y"]=16,["x"]=120},["Graph2.app/"]={["y"]=2,["x"]=42},["Camera.app/"]={["y"]=2,["x"]=16},["TurretControl.lnk"]={["y"]=16,["x"]=107},["Battleship.lnk"]={["y"]=2,["x"]=120},["Weather.lnk"]={["y"]=16,["x"]=133},["PS4.app/"]={["y"]=2,["x"]=55},["3DPrint.lnk"]={["y"]=2,["x"]=94},["Calendar.lnk"]={["y"]=2,["x"]=146},["BufferDemo.lnk"]={["y"]=2,["x"]=133},["Braille.app/"]={["y"]=2,["x"]=3},["RunningString.lnk"]={["y"]=16,["x"]=68},["Camera.lnk"]={["y"]=9,["x"]=3},["HoloEdit.lnk"]={["y"]=9,["x"]=133},["ForceAdmin.lnk"]={["y"]=9,["x"]=55},["Spinner.app/"]={["y"]=2,["x"]=68},["QuantumCube.lnk"]={["y"]=16,["x"]=29},["ChristmasTree.lnk"]={["y"]=9,["x"]=16},["Translate.app/"]={["y"]=2,["x"]=81},["FlappyBird.lnk"]={["y"]=9,["x"]=42},["GuessWord.lnk"]={["y"]=9,["x"]=94},["3DTest.lnk"]={["y"]=2,["x"]=107},["RayWalk.lnk"]={["y"]=16,["x"]=55},["HoloClock.lnk"]={["y"]=9,["x"]=120},["PrintImage.lnk"]={["y"]=16,["x"]=16},["EBAMARKET2.app/"]={["y"]=2,["x"]=29},["Shooting.lnk"]={["y"]=16,["x"]=81},["FuckTheRain.lnk"]={["y"]=9,["x"]=68},["GeoScan2.lnk"]={["y"]=9,["x"]=81},["HEX.lnk"]={["y"]=9,["x"]=107},["InfoPanel.lnk"]={["y"]=9,["x"]=146},["Stargate.lnk"]={["y"]=16,["x"]=94}} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/3DPrint.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/3DPrint.lnk new file mode 100644 index 00000000..467eb2d7 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/3DPrint.lnk @@ -0,0 +1 @@ +/MineOS/Applications/3DPrint.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/3DTest.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/3DTest.lnk new file mode 100644 index 00000000..6d1131a8 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/3DTest.lnk @@ -0,0 +1 @@ +/MineOS/Applications/3DTest.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Battleship.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Battleship.lnk new file mode 100644 index 00000000..5caf03f7 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Battleship.lnk @@ -0,0 +1 @@ +/MineOS/Applications/Battleship.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Braille.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Braille.app/Main.lua new file mode 100644 index 00000000..dc4512fa --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Braille.app/Main.lua @@ -0,0 +1,268 @@ + +require("advancedLua") +local fs = require("filesystem") +local buffer = require("doubleBuffering") +local GUI = require("GUI") +local unicode = require("unicode") +local image = require("image") +local keyboard = require("keyboard") +local MineOSInterface = require("MineOSInterface") + +--------------------------------------------------------------------------------------------------------- + +local mainContainer, window = MineOSInterface.addWindow(MineOSInterface.filledWindow(1, 1, 32, 19, 0x2D2D2D)) + +local layout = window:addChild(GUI.layout(1, 2, 1, 1, 1, 1)) +layout:setCellDirection(1, 1, GUI.directions.horizontal) + +local newButton = layout:addChild(GUI.button(1, 1, 3, 1, 0x444444, 0xE1E1E1, 0xE1E1E1, 0x444444, "N")) +local saveButton = layout:addChild(GUI.button(1, 1, 3, 1, 0x444444, 0xE1E1E1, 0xE1E1E1, 0x444444, "S")) +local openButton = layout:addChild(GUI.button(1, 1, 3, 1, 0x444444, 0xE1E1E1, 0xE1E1E1, 0x444444, "O")) +local colorSelector1 = layout:addChild(GUI.colorSelector(1, 1, 3, 1, 0xFF4940, "B")) +local colorSelector2 = layout:addChild(GUI.colorSelector(1, 1, 3, 1, 0x9924FF, "F")) +local keepSwitch = layout:addChild(GUI.switchAndLabel(1, 1, 16, 5, 0x66DB80, 0x1E1E1E, 0xE1E1E1, 0x888888, "Replace: ", true)).switch + +local function newCell(x, y, shaded) + local object = GUI.object(x, y, 4, 4) + object.shaded = shaded + object.pixels = {} + object.background = 0xFF0000 + object.foreground = 0x0000FF + for y = 1, 4 do + object.pixels[y] = {} + end + + object.draw = function(object) + local step = false + for y = 1, 4 do + for x = 1, 2 do + if object.pixels[y][x] then + buffer.square(object.x + x * 2 - 2, object.y + y - 1, 2, 1, object.pixels[y][x] == 1 and object.foreground or object.background, 0x0, " ") + else + buffer.square(object.x + x * 2 - 2, object.y + y - 1, 2, 1, 0xFFFFFF, object.shaded and (step and 0xC3C3C3 or 0xB4B4B4) or (step and 0xE1E1E1 or 0xD2D2D2), "▒") + end + step = not step + end + step = not step + end + end + + object.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" or eventData[1] == "drag" then + local x, y = math.ceil((eventData[3] - object.x + 1) / 2), eventData[4] - object.y + 1 + + if (object.background ~= colorSelector1.color and keepSwitch.state) or object.background == colorSelector1.color then + object.background = colorSelector1.color + end + + if (object.foreground ~= colorSelector2.color and keepSwitch.state) or object.foreground == colorSelector2.color then + object.foreground = colorSelector2.color + end + + -- CTRL or CMD or ALT + if keyboard.isKeyDown(29) or keyboard.isKeyDown(219) or keyboard.isKeyDown(56) then + object.pixels[y][x] = nil + else + object.pixels[y][x] = eventData[5] == 0 and 1 or 0 + end + + mainContainer:draw() + buffer.draw() + end + end + + return object +end + + +local drawingArea = window:addChild(GUI.container(1, 4, 1, 1)) +local overrideDraw = drawingArea.draw +drawingArea.draw = function(...) + GUI.windowShadow(drawingArea.x, drawingArea.y, drawingArea.width, drawingArea.height, GUI.colors.contextMenu.transparency.shadow, true) + overrideDraw(...) +end + +local function getBrailleChar(a, b, c, d, e, f, g, h) + return unicode.char(10240 + 128*h + 64*g + 32*f + 16*d + 8*b + 4*e + 2*c + a) +end + +local function newNoGUI(width, height) + drawingArea.width, drawingArea.height = width * 4, height * 4 + + window.width = math.max(50, drawingArea.width) + window.height = drawingArea.height + 4 + + drawingArea.localX = math.floor(window.width / 2 - drawingArea.width / 2) + + window.backgroundPanel.width = window.width + window.backgroundPanel.height = window.height + + layout.width = window.backgroundPanel.width + + + drawingArea:deleteChildren() + + local x, y, step = 1, 1, false + for j = 1, height do + for i = 1, width do + drawingArea:addChild(newCell(x, y, step)) + x, step = x + 4, not step + end + x, y, step = 1, y + 4, not step + end +end + +local function new() + local container = MineOSInterface.addUniversalContainer(mainContainer, "Create") + + local widthTextBox = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x666666, 0xEEEEEE, 0x262626, "8", "Width", true)) + widthTextBox.validator = function(text) + return tonumber(text) + end + + local heightTextBox = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x666666, 0xEEEEEE, 0x262626, "4", "Height", true)) + heightTextBox.validator = function(text) + return tonumber(text) + end + + container.panel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + container:delete() + + newNoGUI(tonumber(widthTextBox.text), tonumber(heightTextBox.text)) + + mainContainer:draw() + buffer.draw() + end + end + + mainContainer:draw() + buffer.draw() +end + +local function fillBrailleArray(source, inverted) + local brailleArray, transparencyCyka, backgroundCyka, foregroundCyka = {} + + for j = 1, 4 do + for i = 1, 2 do + if not source[j][i] then + transparencyCyka = true + table.insert(brailleArray, 0) + elseif source[j][i] == 1 then + foregroundCyka = true + table.insert(brailleArray, inverted and 0 or 1) + else + backgroundCyka = true + table.insert(brailleArray, inverted and 1 or 0) + end + end + end + + return brailleArray, transparencyCyka, backgroundCyka, foregroundCyka +end + +newButton.onTouch = function() + new() +end + +saveButton.onTouch = function() + local filesystemDialog = GUI.addFilesystemDialogToContainer(mainContainer, 50, math.floor(mainContainer.height * 0.8), true, "OK", "Cancel", "Path", "/") + + filesystemDialog:setMode(GUI.filesystemModes.save, GUI.filesystemModes.file) + filesystemDialog:addExtensionFilter(".pic") + filesystemDialog:addExtensionFilter(".braiile") + + filesystemDialog.onSubmit = function(path) + if fs.extension(path) == ".pic" then + local picture = {drawingArea.width / 4, drawingArea.height / 4} + + local x, y = 1, 1 + for childIndex = 1, #drawingArea.children do + local background, foreground = drawingArea.children[childIndex].background, drawingArea.children[childIndex].foreground + + local brailleArray, transparencyCyka, backgroundCyka, foregroundCyka = fillBrailleArray(drawingArea.children[childIndex].pixels) + if transparencyCyka then + if backgroundCyka and foregroundCyka then + GUI.error("Пиксель " .. x .. "x" .. y .. " имеет два цвета и прозрачность. Убирай любой из цветов и наслаждайся") + return + else + background = 0x0 + if backgroundCyka then + foreground = drawingArea.children[childIndex].background + brailleArray = fillBrailleArray(drawingArea.children[childIndex].pixels, true) + end + end + end + + image.set( + picture, x, y, background, foreground, + transparencyCyka and 1 or 0, + string.brailleChar(table.unpack(brailleArray)) + ) + + x = x + 1 + if x > picture[1] then + x, y = 1, y + 1 + end + end + + image.save(path, picture) + else + local pizda = { + width = drawingArea.width / 4, + height = drawingArea.height / 4, + } + + for i = 1, #drawingArea.children do + table.insert(pizda, { + background = drawingArea.children[i].background, + foreground = drawingArea.children[i].foreground, + pixels = drawingArea.children[i].pixels, + }) + end + + table.toFile(path, pizda, true) + end + end + + filesystemDialog:show() +end + +openButton.onTouch = function() + local filesystemDialog = GUI.addFilesystemDialogToContainer(mainContainer, 50, math.floor(mainContainer.height * 0.8), true, "OK", "Cancel", "Path", "/") + + filesystemDialog:setMode(GUI.filesystemModes.open, GUI.filesystemModes.file) + filesystemDialog:addExtensionFilter(".braiile") + + filesystemDialog.onSubmit = function(path) + local pizda = table.fromFile(path) + drawingArea:deleteChildren() + + newNoGUI(pizda.width, pizda.height) + + for i = 1, #drawingArea.children do + drawingArea.children[i].background = pizda[i].background + drawingArea.children[i].foreground = pizda[i].foreground + drawingArea.children[i].pixels = pizda[i].pixels + end + + mainContainer:draw() + buffer.draw() + end + + filesystemDialog:show() +end + +window.actionButtons.minimize:delete() +window.actionButtons.maximize:delete() + + +--------------------------------------------------------------------------------------------------------- + +newNoGUI(8, 4) + +mainContainer:draw() +buffer.draw(true) + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Braille.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Braille.app/Resources/Icon.pic new file mode 100644 index 00000000..a959182b Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Braille.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/BufferDemo.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/BufferDemo.lnk new file mode 100644 index 00000000..205d95c0 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/BufferDemo.lnk @@ -0,0 +1 @@ +/MineOS/Applications/BufferDemo.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Calendar.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Calendar.lnk new file mode 100644 index 00000000..a5e7cd40 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Calendar.lnk @@ -0,0 +1 @@ +/MineOS/Applications/Calendar.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Camera.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Camera.app/Main.lua new file mode 100644 index 00000000..1418dfad --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Camera.app/Main.lua @@ -0,0 +1,191 @@ + +local computer = require("computer") +local component = require("component") +local GUI = require("GUI") +local MineOSInterface = require("MineOSInterface") +local buffer = require("doubleBuffering") +local image = require("image") +local fs = require("filesystem") + +if not component.isAvailable("camera") then + GUI.error("This program reqiures camera from computronix mod") + return +end + +local cameraProxy = component.camera + +local grayscale = { + 0xF0F0F0, + 0xE1E1E1, + 0xD2D2D2, + 0xC3C3C3, + 0xB4B4B4, + 0xA5A5A5, + 0x969696, + 0x878787, + 0x787878, + 0x696969, + 0x5A5A5A, + 0x4B4B4B, + 0x3C3C3C, + 0x2D2D2D, + 0x1E1E1E, + 0x0F0F0F, +} + +local thermal = { + 0xFF0000, + 0xFF2400, + 0xFF4900, + 0xFF6D00, + 0xFF9200, + 0xFFB600, + 0xFFDB00, + 0xCCFF00, + 0x99FF00, + 0x33DB00, + 0x00B600, + 0x009200, + 0x006D00, + 0x004900, + 0x002400, + 0x0024BF, + 0x0000BF, + 0x002480, + 0x000080, + 0x000040, + 0x000000, +} +local palette = grayscale + +local mainContainer, window = MineOSInterface.addWindow(MineOSInterface.filledWindow(1, 1, 100, 25, 0x2D2D2D)) + +window.backgroundPanel.width = 22 +window.backgroundPanel.height = window.height +window.backgroundPanel.colors.transparency = nil + +local layout = window:addChild(GUI.layout(1, 4, window.backgroundPanel.width, window.backgroundPanel.height - 3, 1, 1)) +layout:setCellFitting(1, 1, true, false, 2, 0) +layout:setCellAlignment(1, 1, GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + +layout:addChild(GUI.label(1, 1, 1, 1, 0xC3C3C3, "Select camera"):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) +local comboBox = layout:addChild(GUI.comboBox(1, 1, 36, 1, 0xF0F0F0, 0x2D2D2D, 0x444444, 0x999999)) +local paletteSwitch = layout:addChild(GUI.switchAndLabel(1, 1, 16, 6, 0x66DB80, 0x0, 0xF0F0F0, 0xC3C3C3, "Thermal:", false)).switch +local semiPixelSwitch = layout:addChild(GUI.switchAndLabel(1, 1, 16, 6, 0x66DB80, 0x0, 0xF0F0F0, 0xC3C3C3, "Semipixels:", true)).switch + +local autoupdateSwitch = layout:addChild(GUI.switchAndLabel(1, 1, 16, 6, 0x66DB80, 0x0, 0xF0F0F0, 0xC3C3C3, "Autoupdate:", false)).switch +local autoupdateSlider = layout:addChild(GUI.slider(1, 1, 12, 0x66DB80, 0x0, 0xFFFFFF, 0x666666, 0, 10000, 1000, false, "Delay: ", " ms")) +autoupdateSlider.hidden = true + +local FOVSlider = layout:addChild(GUI.slider(1, 1, 12, 0x66DB80, 0x0, 0xFFFFFF, 0x666666, 10, 90, 90, false, "FOV: ", "")) +local rangeSlider = layout:addChild(GUI.slider(1, 1, 12, 0x66DB80, 0x0, 0xFFFFFF, 0x666666, 0, 60, 32, false, "Range: ", "")) + +local cameraView = window:addChild(GUI.object(window.backgroundPanel.width + 1, 1, 1, 1)) +cameraView.pixels = {} + +local function takePicture() + cameraView.pixels = {} + + local FOV = FOVSlider.value / FOVSlider.maximumValue + local doubleFOV = FOV * 2 + + local x, y = 1, 1 + for yRotation = FOV, -FOV, -(doubleFOV / (cameraView.height * (semiPixelSwitch.state and 2 or 1))) do + cameraView.pixels[y] = {} + for xRotation = FOV, -FOV, -(doubleFOV / cameraView.width) do + cameraView.pixels[y][x] = cameraProxy.distance(xRotation, yRotation) + + x = x + 1 + end + + x, y = 1, y + 1 + end + + mainContainer:draw() + buffer.draw() +end + +local buttonImage = image.load(fs.path(getCurrentScript()) .. "/Resources/Icon.pic") +local buttonImagePressed = image.blend(buttonImage, 0x0, 0.6) +local shootButton = window:addChild(GUI.object(1, 1, 8, 4)) +shootButton.draw = function() + buffer.image(shootButton.x, shootButton.y, shootButton.pressed and buttonImagePressed or buttonImage) +end + +shootButton.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + shootButton.pressed = true + mainContainer:draw() + buffer.draw() + + takePicture() + + shootButton.pressed = false + mainContainer:draw() + buffer.draw() + end +end + +cameraView.draw = function(cameraView) + local x, y = 0, 0 + for y = 1, #cameraView.pixels do + for x = 1, #cameraView.pixels[y] do + local color = palette[math.ceil(cameraView.pixels[y][x] / rangeSlider.value * #palette)] or 0x0 + if semiPixelSwitch.state then + buffer.semiPixelSet(cameraView.x + x - 1, cameraView.y * 2 + y - 2, color) + else + buffer.set(cameraView.x + x - 1, cameraView.y + y - 2, color, 0x0, " ") + end + end + end +end + +local lastUptime = computer.uptime() +layout.eventHandler = function() + if autoupdateSwitch.state then + local uptime = computer.uptime() + if uptime - lastUptime >= autoupdateSlider.value / 1000 then + takePicture() + lastUptime = uptime + end + end +end + +window.actionButtons:moveToFront() + +semiPixelSwitch.onStateChanged = takePicture +FOVSlider.onValueChanged = takePicture + +paletteSwitch.onStateChanged = function() + palette = paletteSwitch.state and thermal or grayscale + mainContainer:draw() + buffer.draw() +end + +autoupdateSwitch.onStateChanged = function() + autoupdateSlider.hidden = not autoupdateSwitch.state + mainContainer:draw() + buffer.draw() +end + +for address in component.list("camera") do + comboBox:addItem(address).onTouch = function() + cameraProxy = component.proxy(address) + takePicture() + end +end + +window.onResize = function(width, height) + layout.height = window.height + window.backgroundPanel.height = window.height + cameraView.height = window.height + cameraView.width = window.width - window.backgroundPanel.width + + shootButton.localX = math.floor(1 + window.backgroundPanel.width / 2 - shootButton.width / 2) + shootButton.localY = window.height - shootButton.height + + takePicture() +end + +window:resize(window.width, window.height) +takePicture() diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Camera.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Camera.app/Resources/Icon.pic new file mode 100644 index 00000000..77b04374 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Camera.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Camera.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Camera.lnk new file mode 100644 index 00000000..32f58662 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Camera.lnk @@ -0,0 +1 @@ +/MineOS/Applications/Camera.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/ChristmasTree.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/ChristmasTree.lnk new file mode 100644 index 00000000..265aa24f --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/ChristmasTree.lnk @@ -0,0 +1 @@ +/MineOS/Applications/ChristmasTree.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/CodeDoor.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/CodeDoor.lnk new file mode 100644 index 00000000..2c72c72d --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/CodeDoor.lnk @@ -0,0 +1 @@ +/MineOS/Applications/CodeDoor.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/EBAMARKET2.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/EBAMARKET2.app/Main.lua new file mode 100644 index 00000000..692cb0d5 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/EBAMARKET2.app/Main.lua @@ -0,0 +1,1270 @@ + +require("advancedLua") +local component = require("component") +local computer = require("computer") +local web = require("web") +local GUI = require("GUI") +local buffer = require("doubleBuffering") +local MineOSCore = require("MineOSCore") +local MineOSPaths = require("MineOSPaths") +local MineOSInterface = require("MineOSInterface") +local image = require("image") +local fs = require("filesystem") +local color = require("color") +local unicode = require("unicode") + +-------------------------------------------------------------------------------- + +local host = "http://buttex.ru/mineos/appmarket/" +local luaIcon = image.load(MineOSPaths.icons .. "Lua.pic") +local scriptIcon = image.load(MineOSPaths.icons .. "Script.pic") +local appMarketPath = MineOSPaths.applicationData .. "AppMarket/" +local configPath = appMarketPath .. "Config.cfg" +local iconCachePath = appMarketPath .. "Cache/" + +local config = { + descriptionLanguage = "en", + orderBy = 1, + orderDirection = 1, + user = {} +} + +local categories = { + "Приложения", + "Библиотеки", + "Скрипты", +} + +local orderDirections = { + "desc", + "asc", +} + +local downloadPaths = { + "/MineOS/Applications/", + "/lib/", + "/bin/", +} + +local licenses = { + "MIT", + "GNU GPLv3", + "GNU AGPLv3", + "GNU LGPLv3", + "Apache Licence 2.0", + "Mozilla Public License 2.0", + "The Unlicense", +} + +local orderBys = { + "average_rating", + "file_id", + "publication_name", +} + +local search = "" +local appWidth, appHeight, appHSpacing, appVSpacing, currentPage, appsPerPage, appsPerWidth, appsPerHeight = 34, 6, 2, 1 + +local updateFileList, editPublication + +-------------------------------------------------------------------------------- + +local function saveConfig() + table.toFile(configPath, config) +end + +local function loadConfig() + if fs.exists(configPath) then + config = table.fromFile(configPath) + else + saveConfig() + end +end + +-------------------------------------------------------------------------------- + +local function RawAPIRequest(script, postData, notUnserialize) + local url = host .. script .. ".php?" .. web.serialize(postData) + -- table.toFile("/test.txt", {url}) + local requestResult, requestReason = web.request(url) + if requestResult then + if not notUnserialize then + local unserializeResult, unserializeReason = table.fromString(requestResult) + if unserializeResult then + if unserializeResult.success then + return unserializeResult + else + return false, "API request not succeded: " .. tostring(unserializeResult.reason) + end + else + return false, "Failed to unserialize response data: " .. tostring(unserializeReason) .. ", the data was: " .. tostring(requestResult) + end + else + return result + end + else + return false, "Web request failed: " .. tostring(requestReason) + end +end + +local function fieldAPIRequest(fieldToReturn, ...) + local success, reason = RawAPIRequest(...) + if success then + if success[fieldToReturn] then + return success[fieldToReturn] + else + return false, "Request was successful, but field " .. tostring(fieldToReturn) .. " doesn't exists" + end + else + return false, reason + end +end + +local function checkImage(url) + local handle = component.internet.request(url) + if handle then + local _, _, responseData + repeat + _, _, responseData = handle:response() + until responseData + + local contentLength = tonumber(responseData["Content-Length"][1]) + if contentLength <= 10240 then + local data, chunk, reason = "" + while true do + chunk, reason = handle.read(math.huge) + if chunk then + data = data .. chunk + if #data > 8 then + if data:sub(1, 4) == "OCIF" then + if string.byte(data:sub(6, 6)) > 8 or string.byte(data:sub(7, 7)) > 4 then + handle:close() + return false, "Image size is larger than 8x4" + end + else + handle:close() + return false, "Wrong image file signature" + end + end + else + handle:close() + if reason then + return false, reason + else + return data + end + end + end + else + handle:close() + return false, "Specified image size is too big" + end + else + return false, "Invalid URL" + end +end + +-------------------------------------------------------------------------------- + +local mainContainer, window = MineOSInterface.addWindow(MineOSInterface.tabbedWindow(1, 1, 110, 30)) +local overrideWindowDraw = window.draw +window.draw = function(...) + overrideWindowDraw(...) + buffer.text(window.x, window.y + window.height, 0xFF0000, "Free RAM: " .. math.floor(computer.freeMemory() / 1024)) +end + +local contentContainer = window:addChild(GUI.container(1, 4, 1, 1)) +local statusWidget = window:addChild(GUI.object(1, 1, 1, 1)) +statusWidget.draw = function() + buffer.square(statusWidget.x, statusWidget.y, statusWidget.width, 1, 0x2D2D2D, 0xF0F0F0, " ") + buffer.text(statusWidget.x + 1, statusWidget.y, 0xF0F0F0, statusWidget.text) +end + +-------------------------------------------------------------------------------- + +local function status(text) + statusWidget.text = text + MineOSInterface.OSDraw() +end + +local function getAllDependencies(application) + if application.dependencies then + local allDependencies = {} + + local function getAllDependenciesRecursively(file_ids) + local list, reason = fieldAPIRequest("list", "list", { + file_ids = file_ids, + fields = { + "dependencies", + "publication_name", + "path", + "source_url", + "category_id", + } + }) + + if list then + local newDependenciesList = {} + + for i = 1, #list do + if not allDependencies[list[i].file_id] and list[i].file_id ~= application.file_id then + allDependencies[list[i].file_id] = list[i] + end + + if list[i].dependencies then + for j = 1, #list[i].dependencies do + if not allDependencies[list[i].dependencies[j]] and list[i].dependencies[j] ~= application.file_id then + table.insert(newDependenciesList, list[i].dependencies[j]) + end + end + end + end + + if #newDependenciesList > 0 then + getAllDependenciesRecursively(newDependenciesList) + end + else + GUI.error(reason) + end + end + + getAllDependenciesRecursively(application.dependencies) + + application.expandedDependencies = {} + for key, value in pairs(allDependencies) do + table.insert(application.expandedDependencies, value) + allDependencies[key] = nil + end + + if #application.expandedDependencies == 0 then + application.expandedDependencies = nil + end + end +end + +local function ratingWidgetDraw(object) + local x = 0 + for i = 1, 5 do + buffer.text(object.x + x, object.y, math.round(object.rating) >= i and object.colors.first or object.colors.second, "*") + x = x + object.spacing + end + + return object +end + +local function newRatingWidget(x, y, rating, firstColor, secondColor) + local object = GUI.object(x, y, 9, 1) + + object.colors = { + first = firstColor or 0xFFB600, + second = secondColor or 0xC3C3C3 + } + object.spacing = 2 + object.draw = ratingWidgetDraw + object.rating = rating + + return object +end + +-------------------------------------------------------------------------------- + +local function getApplicationIcon(category_id, dependencies) + if dependencies then + for i = 1, #dependencies do + if dependencies[i].path == "Resources/Icon.pic" then + local path = iconCachePath .. dependencies[i].file_id .. ".pic" + + if fs.exists(path) then + return image.load(path) + else + local data, reason = checkImage(dependencies[i].source_url) + if data then + local file = io.open(path, "w") + file:write(data) + file:close() + + return image.load(path) + else + GUI.error("Failed to download publication icon: " .. reason) + break + end + end + end + end + end + + if category_id == 2 then + return luaIcon + else + return scriptIcon + end +end + +local function addPanel(container, color) + container.panel = container:addChild(GUI.panel(1, 1, container.width, container.height, color or 0xFFFFFF)) +end + +local function addApplicationInfo(container, application) + addPanel(container) + container.image = container:addChild(GUI.image(3, 2, getApplicationIcon(application.category_id, application.expandedDependencies))) + container.nameLabel = container:addChild(GUI.text(13, 2, 0x0, application.publication_name)) + container.versionLabel = container:addChild(GUI.text(13, 3, 0x888888, "©" .. application.user_name)) + container.rating = container:addChild(newRatingWidget(13, 4, application.average_rating or 0)) + container.downloadButton = container:addChild(GUI.adaptiveRoundedButton(13, 5, 1, 0, 0xBBBBBB, 0xFFFFFF, 0x888888, 0xFFFFFF, "Загрузить")) + container.downloadButton.onTouch = function() + local filesystemDialog = GUI.addFilesystemDialogToContainer(MineOSInterface.mainContainer, 50, math.floor(MineOSInterface.mainContainer.height * 0.8), true, "Загрузить", "Отмена", "Имя приложения", "/") + + filesystemDialog.input.text = application.category_id == 1 and application.publication_name or fs.hideExtension(application.path) + filesystemDialog:addExtensionFilter(application.category_id == 1 and ".app" or ".lua") + + filesystemDialog.filesystemTree.selectedItem = downloadPaths[application.category_id] + filesystemDialog:expandPath(filesystemDialog.filesystemTree.selectedItem) + + filesystemDialog.onSubmit = function(downloadPath) + local container = MineOSInterface.addUniversalContainer(MineOSInterface.mainContainer, "") + container.layout:setCellFitting(2, 1, false, false) + + local progressBar = container.layout:addChild(GUI.progressBar(1, 1, 36, 0x66DB80, 0x0, 0xEEEEEE, 0, true, true, "", "%")) + + local function updateLabel(pizda) + container.label.text = "Загрузка " .. (pizda.publication_name or fs.name(pizda.path)) + end + updateLabel(application) + + MineOSInterface.OSDraw() + + -- SAVED + getAllDependencies(application) + local whatToDownload = {application} + if application.expandedDependencies then + for i = 1, #application.expandedDependencies do + table.insert(whatToDownload, application.expandedDependencies[i]) + end + end + + for i = 1, #whatToDownload do + progressBar.value = math.round(i / #whatToDownload * 100) + updateLabel(whatToDownload[i]) + + -- Если это публикация + local finalPath + if whatToDownload[i].category_id then + finalPath = downloadPaths[whatToDownload[i].category_id] + + if whatToDownload[i].category_id == 1 then + if i == 1 then + finalPath = downloadPath .. "/Main.lua" + else + finalPath = finalPath .. whatToDownload[i].publication_name .. ".app/Main.lua" + end + else + finalPath = finalPath .. whatToDownload[i].path + end + -- Если это ресурс + else + finalPath = downloadPath .. "/" .. whatToDownload[i].path + end + + -- GUI.error(whatToDownload[i].source_url, finalPath) + -- local success, reason = web.download(whatToDownload[i].source_url, finalPath) + -- if not success then + -- GUI.error(reason) + -- end + + MineOSInterface.OSDraw() + end + + container:delete() + MineOSInterface.OSDraw() + end + + filesystemDialog:setMode(GUI.filesystemModes.save, GUI.filesystemModes.file) + filesystemDialog:show() + end +end + +local function keyValueWidgetUpdate(object) + object.width = unicode.len(object.key .. object.value) +end + +local function keyValueWidgetDraw(object) + keyValueWidgetUpdate(object) + buffer.text(object.x, object.y, object.colors.key, object.key) + buffer.text(object.x + unicode.len(object.key), object.y, object.colors.value, object.value) +end + +local function newKeyValueWidget(x, y, keyColor, valueColor, key, value) + local object = GUI.object(x, y, 1, 1) + + object.colors = { + key = keyColor, + value = valueColor + } + object.key = key + object.value = value + + object.draw = keyValueWidgetDraw + keyValueWidgetUpdate(object) + + return object +end + +local function containerScrollEventHandler(mainContainer, object, eventData) + if eventData[1] == "scroll" then + local first, last = object.children[1], object.children[#object.children] + + if eventData[5] == 1 then + if first.localY < 2 then + for i = 1, #object.children do + object.children[i].localY = object.children[i].localY + 1 + end + MineOSInterface.OSDraw() + end + else + if last.localY + last.height - 1 >= object.height then + for i = 1, #object.children do + object.children[i].localY = object.children[i].localY - 1 + end + MineOSInterface.OSDraw() + end + end + end +end + +local function newApplicationInfo(file_id) + status("Получение информации о приложении...") + + local info, reason = fieldAPIRequest("list", "list", { + file_ids = {file_id}, + fields = { + "publication_id", + "publication_name", + "average_rating", + "version", + "reviews", + "description", + "category_id", + "dependencies", + "user_name", + "license", + "timestamp", + "path", + }, + description_language = config.descriptionLanguage, + }) + + if info then + local application = info[1] + + status("Построение древа зависимостей...") + getAllDependencies(application) + + contentContainer:deleteChildren() + + local infoContainer = contentContainer:addChild(GUI.container(1, 1, contentContainer.width, contentContainer.height)) + infoContainer.eventHandler = containerScrollEventHandler + + -- Жирный йоба-лейаут для отображения ВАЩЕ всего - и инфы, и отзыввов + local layout = infoContainer:addChild(GUI.layout(3, 2, infoContainer.width - 4, infoContainer.height, 1, 1)) + layout:setCellAlignment(1, 1, GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + + -- А вот эт уже контейнер чисто инфы крч + local detailsContainer = layout:addChild(GUI.container(3, 2, layout.width, 6)) + + -- Тут будут находиться ваще пизда подробности о публикации + local ratingsContainer = detailsContainer:addChild(GUI.container(1, 1, 26, 6)) + ratingsContainer.localX = detailsContainer.width - ratingsContainer.width + 1 + addPanel(ratingsContainer, 0xE1E1E1) + + -- Всякая текстовая пизда + local y = 2 + ratingsContainer:addChild(newKeyValueWidget(2, y, 0x2D2D2D, 0x888888, "Разработчик", ": " .. application.user_name)); y = y + 1 + ratingsContainer:addChild(newKeyValueWidget(2, y, 0x2D2D2D, 0x888888, "Лицензия", ": " .. application.license)); y = y + 1 + ratingsContainer:addChild(newKeyValueWidget(2, y, 0x2D2D2D, 0x888888, "Категория", ": " .. categories[application.category_id])); y = y + 1 + ratingsContainer:addChild(newKeyValueWidget(2, y, 0x2D2D2D, 0x888888, "Версия", ": " .. string.format("%.2f", application.version))); y = y + 1 + ratingsContainer:addChild(newKeyValueWidget(2, y, 0x2D2D2D, 0x888888, "Обновлено", ": " .. os.date("%d.%m.%Y", application.timestamp))); y = y + 1 + y = y + 1 + + -- Добавляем инфу с общими рейтингами + if application.reviews then + status("Формирование структуры отзывов...") + + local ratings = {0, 0, 0, 0, 0} + for i = 1, #application.reviews do + ratings[application.reviews[i].rating] = ratings[application.reviews[i].rating] + 1 + end + + ratingsContainer:addChild(newKeyValueWidget(2, y, 0x2D2D2D, 0x888888, "Средний рейтинг", ": " .. string.format("%.1f", application.average_rating or 0))); y = y + 1 + + for i = #ratings, 1, -1 do + local text = tostring(ratings[i]) + local textLength = #text + ratingsContainer:addChild(newRatingWidget(2, y, i, nil, 0xC3C3C3)) + ratingsContainer:addChild(GUI.progressBar(12, y, ratingsContainer.width - textLength - 13, 0x2D2D2D, 0xC3C3C3, 0xC3C3C3, ratings[i] / #application.reviews * 100, true)) + ratingsContainer:addChild(GUI.text(ratingsContainer.width - textLength, y, 0x2D2D2D, text)) + y = y + 1 + end + end + + -- Добавляем описание и прочую пизду + local textDetailsContainer = detailsContainer:addChild(GUI.container(1, 1, detailsContainer.width - ratingsContainer.width, detailsContainer.height)) + addApplicationInfo(textDetailsContainer, application) + + local lines = string.wrap(info[1].description, textDetailsContainer.width - 4) + local textBox = textDetailsContainer:addChild(GUI.textBox(3, 7, textDetailsContainer.width - 4, #lines, nil, 0x888888, lines, 1, 0, 0)) + textBox.eventHandler = nil + + if application.expandedDependencies then + local publicationDependencyExists, resourceDependencyExists = false, false + for i = 1, #application.expandedDependencies do + if application.expandedDependencies[i].publication_name then + publicationDependencyExists = true + else + resourceDependencyExists = true + end + end + + local x, y = 3, textBox.localY + textBox.height + 1 + + if resourceDependencyExists then + textDetailsContainer:addChild(GUI.label(1, y, textDetailsContainer.width, 1, 0x666666, "Структура приложения")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + y = y + 2 + + local tree = textDetailsContainer:addChild(GUI.tree(2, y, textDetailsContainer.width - 2, 1, 0xF0F0F0, 0x3C3C3C, 0xAAAAAA, 0xAAAAAA, 0x3C3C3C, 0xE1E1E1, 0xBBBBBB, 0xAAAAAA, 0xC3C3C3, 0x444444)) + + local dependencyTree = {} + for i = 1, #application.expandedDependencies do + if not application.expandedDependencies[i].publication_name then + local idiNahooy = dependencyTree + for blyad in (application.publication_name .. ".app/" .. fs.path(application.expandedDependencies[i].path)):gmatch("[^/]+") do + if not idiNahooy[blyad] then + idiNahooy[blyad] = {} + end + idiNahooy = idiNahooy[blyad] + end + table.insert(idiNahooy, fs.name(application.expandedDependencies[i].path)) + end + end + table.insert(dependencyTree[application.publication_name .. ".app"], "Main.lua") + -- GUI.error(dependencyTree) + + local function pizda(t, offset) + for key, value in pairs(t) do + if type(value) == "table" then + tree:addItem(key, key, offset, true) + tree.expandedItems[key] = true + + pizda(value, offset + 2) + else + tree:addItem(value, value, offset, false) + end + end + end + + pizda(dependencyTree, 1) + + tree.height = #tree.items + tree.eventHandler = nil + y = y + tree.height + 1 + end + + if publicationDependencyExists then + textDetailsContainer:addChild(GUI.label(1, y, textDetailsContainer.width, 1, 0x666666, "Зависимости")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + y = y + 2 + + for i = 1, #application.expandedDependencies do + local text = application.expandedDependencies[i].publication_name or fs.name(application.expandedDependencies[i].path) + if application.expandedDependencies[i].publication_name then + local textLength = unicode.len(text) + if x + textLength + 4 > textDetailsContainer.width - 4 then + x, y = 3, y + 2 + end + local button = textDetailsContainer:addChild(GUI.roundedButton(x, y, textLength + 2, 1, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, text)) + button.onTouch = function() + newApplicationInfo(application.expandedDependencies[i].file_id) + end + x = x + button.width + 2 + end + end + + y = y + 2 + end + end + + textDetailsContainer.height = math.max( + textDetailsContainer.children[#textDetailsContainer.children].localY + textDetailsContainer.children[#textDetailsContainer.children].height, + ratingsContainer.children[#ratingsContainer.children].localY + ratingsContainer.children[#ratingsContainer.children].height + ) + textDetailsContainer.panel.height = textDetailsContainer.height + + ratingsContainer.height = textDetailsContainer.height + ratingsContainer.panel.height = textDetailsContainer.height + + detailsContainer.height = textDetailsContainer.height + + if config.user.token and config.user.name ~= application.user_name then + layout:addChild(GUI.adaptiveRoundedButton(1, 1, 2, 0, 0x666666, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "Написать отзыв")).onTouch = function() + local container = MineOSInterface.addUniversalContainer(window, "Написать отзыв") + container.layout:setCellFitting(2, 1, false, false) + + local input = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "Оставьте свой высер тут")) + + local pizda = container.layout:addChild(GUI.container(1, 1, 1, 1)) + local eblo = pizda:addChild(GUI.text(1, 1, 0xE1E1E1, "Оцените приложение: ")) + pizda.width = eblo.width + 9 + + local cyka = pizda:addChild(newRatingWidget(eblo.width + 1, 1, 4)) + cyka.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + cyka.rating = (eventData[3] - object.x + 1) / object.width * 5 + MineOSInterface.OSDraw() + end + end + + local govno = container.layout:addChild(GUI.adaptiveRoundedButton(1, 1, 1, 0, 0xFFFFFF, 0x2D2D2D, 0x0, 0xFFFFFF, "Отправить высер")) + govno.disabled = true + govno.colors.disabled.background = 0xAAAAAA + govno.colors.disabled.text = 0xC3C3C3 + govno.onTouch = function() + local success, reason = RawAPIRequest("review", { + token = config.user.token, + publication_id = application.publication_id, + rating = cyka.rating, + comment = input.text, + }) + + container:delete() + + if success then + newApplicationInfo(application.file_id) + else + MineOSInterface.OSDraw() + GUI.error(reason) + end + end + + input.onInputFinished = function() + local textLength, from, to = unicode.len(input.text), 2, 1000 + if textLength >= from and textLength <= to then + govno.disabled = false + else + govno.disabled = true + GUI.error("Слишком охуевший высер. Его длина величиной " .. textLength .. " выходит за границы допустимого диапазона [" .. from .. "; " .. to .. "]") + end + + MineOSInterface.OSDraw() + end + + MineOSInterface.OSDraw() + end + end + + if application.reviews then + -- Отображаем все оценки + layout:addChild(GUI.text(1, 1, 0x666666, "Отзывы пользователей")) + + -- Перечисляем все отзывы + local counter, limit = 0, 10 + + for i = 1, #application.reviews do + if application.reviews[i].comment then + local reviewContainer = layout:addChild(GUI.container(1, 1, layout.width, 4)) + addPanel(reviewContainer) + + local y = 2 + local nameLabel = reviewContainer:addChild(GUI.text(3, y, 0x2D2D2D, application.reviews[i].user_name)) + reviewContainer:addChild(GUI.text(nameLabel.localX + nameLabel.width + 1, y, 0xC3C3C3, "(" .. os.date("%d.%m.%Y в %H:%M", application.reviews[i].timestamp) .. ")")) + y = y + 1 + + reviewContainer:addChild(newRatingWidget(3, y, application.reviews[i].rating)) + y = y + 1 + + local lines = string.wrap(application.reviews[i].comment, reviewContainer.width - 4) + local textBox = reviewContainer:addChild(GUI.textBox(3, y, reviewContainer.width - 4, #lines, nil, 0x888888, lines, 1, 0, 0)) + textBox.eventHandler = nil + y = y + #lines + 1 + + if application.reviews[i].votes then + reviewContainer:addChild(GUI.text(3, y, 0xC3C3C3, application.reviews[i].positive_votes .. " из " .. application.reviews[i].votes .. " пользователей считают этот отзыв полезным")) + y = y + 1 + end + + if config.user.token then + local wasHelpText = reviewContainer:addChild(GUI.text(3, y, 0xC3C3C3, "Был ли этот отзыв полезен?")) + local yesButton = reviewContainer:addChild(GUI.adaptiveButton(wasHelpText.localX + wasHelpText.width + 1, y, 0, 0, nil, 0x666666, nil, 0x2D2D2D, "Да")) + local stripLabel = reviewContainer:addChild(GUI.text(yesButton.localX + yesButton.width + 1, y, 0xC3C3C3, "|")) + local noButton = reviewContainer:addChild(GUI.adaptiveButton(stripLabel.localX + stripLabel.width + 1, y, 0, 0, nil, 0x666666, nil, 0x2D2D2D, "Нет")) + + local function go(rating) + RawAPIRequest("review_vote", { + token = config.user.token, + review_id = application.reviews[i].id, + rating = rating + }, true) + + computer.beep(1500, 0.1) + + wasHelpText.text = "Спасибо за ответ." + wasHelpText.color = 0x666666 + yesButton:delete() + stripLabel:delete() + noButton:delete() + + MineOSInterface.OSDraw() + end + + yesButton.onTouch = function() + go(1) + end + + noButton.onTouch = function() + go(0) + end + + y = y + 1 + end + + reviewContainer.height = y + reviewContainer.panel.height = reviewContainer.height + + counter = counter + 1 + if counter > limit then + break + end + end + end + end + + layout:update() + layout.height = layout.children[#layout.children].localY + layout.children[#layout.children].height - 1 + + status("Ожидание") + else + GUI.error(reason) + end +end + +-------------------------------------------------------------------------------- + +local function applicationWidgetEventHandler(mainContainer, object, eventData) + if eventData[1] == "touch" then + object.parent.panel.colors.background = 0xE1E1E1 + MineOSInterface.OSDraw() + newApplicationInfo(object.parent.application.file_id) + end +end + +local function newApplicationPreview(x, y, application) + local container = GUI.container(x, y, appWidth, appHeight) + + container.application = application + addApplicationInfo(container, application) + + container.panel.eventHandler, + container.image.eventHandler, + container.nameLabel.eventHandler, + container.versionLabel.eventHandler, + container.rating.eventHandler = + applicationWidgetEventHandler, + applicationWidgetEventHandler, + applicationWidgetEventHandler, + applicationWidgetEventHandler, + applicationWidgetEventHandler + + return container +end + +-------------------------------------------------------------------------------- + +editPublication = function() + contentContainer:deleteChildren() + + local layout = contentContainer:addChild(GUI.layout(1, 1, contentContainer.width, contentContainer.height, 3, 1)) + layout:setCellAlignment(1, 1, GUI.alignment.horizontal.right, GUI.alignment.vertical.center) + layout:setCellAlignment(2, 1, GUI.alignment.horizontal.left, GUI.alignment.vertical.center) + layout:setCellFitting(2, 1, true, false) + layout:setCellMargin(1, 1, 1, 0) + + layout:addChild(GUI.text(1, 1, 0x2D2D2D, "Категория:")) + layout:addChild(GUI.text(1, 1, 0x2D2D2D, "Лицензия:")) + layout:addChild(GUI.text(1, 1, 0x2D2D2D, "Имя публикации:")) + layout:addChild(GUI.text(1, 1, 0x2D2D2D, "URL главного файла:")) + local iconHint = layout:addChild(GUI.text(1, 1, 0x2D2D2D, "URL иконки:")) + local pathHint = layout:addChild(GUI.text(1, 1, 0x2D2D2D, "Путь главного файла:")) + layout:addChild(GUI.text(1, 1, 0x2D2D2D, "Описание:")) + layout:addChild(GUI.object(1, 1, 1, 1)) + layout:addChild(GUI.object(1, 1, 1, 1)) + + layout.defaultColumn = 2 + + layout:addChild(GUI.label(1, 1, 36, 1, 0x0, "Опубликовать ПО")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + + local categoryComboBox = layout:addChild(GUI.comboBox(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0x999999, 0xE1E1E1)) + for i = 1, #categories do + categoryComboBox:addItem(categories[i]) + end + + local licenseComboBox = layout:addChild(GUI.comboBox(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0x999999, 0xE1E1E1)) + for i = 1, #licenses do + licenseComboBox:addItem(licenses[i]) + end + + local nameInput = layout:addChild(GUI.input(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "My Script")) + local mainUrlInput = layout:addChild(GUI.input(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "http://example.com/Main.lua")) + local iconUrlInput = layout:addChild(GUI.input(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "http://example.com/Icon.pic")) + local mainPathInput = layout:addChild(GUI.input(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "MyScript.lua")) + local descriptionInput = layout:addChild(GUI.input(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "This is my cool script")) + + layout:addChild(GUI.label(1, 1, 36, 1, 0x0, "Зависимости и ресурсы")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + + local dependenciesLayout = layout:addChild(GUI.layout(1, 1, 36, 1, 2, 1)) + dependenciesLayout:setColumnWidth(1, GUI.sizePolicies.percentage, 1.0) + dependenciesLayout:setColumnWidth(2, GUI.sizePolicies.absolute, 8) + dependenciesLayout:setCellFitting(1, 1, true, false) + dependenciesLayout:setCellMargin(2, 1, 1, 0) + dependenciesLayout:setCellAlignment(1, 1, GUI.alignment.horizontal.left, GUI.alignment.vertical.top) + dependenciesLayout:setCellAlignment(2, 1, GUI.alignment.horizontal.left, GUI.alignment.vertical.top) + dependenciesLayout:setCellDirection(1, 1, GUI.directions.horizontal) + dependenciesLayout:setCellDirection(2, 1, GUI.directions.horizontal) + local dependenciesComboBox = dependenciesLayout:addChild(GUI.comboBox(1, 1, 29, 1, 0xFFFFFF, 0x666666, 0x999999, 0xE1E1E1)) + dependenciesLayout.defaultColumn = 2 + + local addButton = dependenciesLayout:addChild(GUI.button(1, 1, 3, 1, 0x666666, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "+")) + local removeButton = dependenciesLayout:addChild(GUI.button(1, 1, 3, 1, 0x666666, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "-")) + + local function checkRemoveButton() + local count = dependenciesComboBox:count() + removeButton.disabled = count == 0 + dependenciesComboBox.selectedItem = count + end + checkRemoveButton() + + addButton.onTouch = function() + local container = MineOSInterface.addUniversalContainer(window, "Добавить зависимость") + + container.layout:setCellFitting(2, 1, false, false) + + local dependencyTypeComboBox = container.layout:addChild(GUI.comboBox(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0x999999, 0xE1E1E1)) + dependencyTypeComboBox:addItem("Существующая публикация") + dependencyTypeComboBox:addItem("Файл ресурсов", categoryComboBox.selectedItem > 1) + + local publicationNameInput = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "Double Buffering")) + local urlInput = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "http://example.com/English.lang")) + local pathInput = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "Localization/English.lang")) + + local button = container.layout:addChild(GUI.button(1, 1, 36, 3, 0x666666, 0xFFFFFF, 0x0, 0xFFFFFF, "Добавить")) + button.onTouch = function() + if dependencyTypeComboBox.selectedItem == 1 then + dependenciesComboBox:addItem(publicationNameInput.text).publication_name = publicationNameInput.text + else + local item = dependenciesComboBox:addItem(pathInput.text) + item.path = pathInput.text + item.source_url = urlInput.text + end + + checkRemoveButton() + + container:delete() + MineOSInterface.OSDraw() + end + + publicationNameInput.onInputFinished = function() + if dependencyTypeComboBox.selectedItem == 1 then + button.disabled = #publicationNameInput.text == 0 + else + button.disabled = #pathInput.text == 0 or #urlInput.text == 0 + end + end + pathInput.onInputFinished, urlInput.onInputFinished = publicationNameInput.onInputFinished, publicationNameInput.onInputFinished + + dependencyTypeComboBox.onItemSelected = function() + pathInput.hidden = dependencyTypeComboBox.selectedItem == 1 + urlInput.hidden = pathInput.hidden + publicationNameInput.hidden = not pathInput.hidden + + MineOSInterface.OSDraw() + end + + publicationNameInput.onInputFinished() + dependencyTypeComboBox.onItemSelected() + end + + removeButton.onTouch = function() + dependenciesComboBox:getItem(dependenciesComboBox.selectedItem):delete() + checkRemoveButton() + MineOSInterface.OSDraw() + end + + local publishButton = layout:addChild(GUI.adaptiveRoundedButton(1, 1, 2, 0, 0x666666, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "Опубликовать")) + + nameInput.onInputFinished = function() + publishButton.disabled = not (#nameInput.text > 0 and #mainUrlInput.text > 0 and (iconUrlInput.hidden and true or #iconUrlInput.text > 0) and (mainPathInput.hidden and true or #mainPathInput.text > 0) and #descriptionInput.text > 0) + end + mainUrlInput.onInputFinished, mainPathInput.onInputFinished, iconUrlInput.onInputFinished, descriptionInput.onInputFinished = nameInput.onInputFinished, nameInput.onInputFinished, nameInput.onInputFinished, nameInput.onInputFinished + + categoryComboBox.onItemSelected = function() + iconHint.hidden = categoryComboBox.selectedItem > 1 + iconUrlInput.hidden = iconHint.hidden + + pathHint.hidden = not iconHint.hidden + mainPathInput.hidden = pathHint.hidden + + nameInput.onInputFinished() + MineOSInterface.OSDraw() + end + + publishButton.onTouch = function() + local dependencies = {} + for i = 1, dependenciesComboBox:count() do + local item = dependenciesComboBox:getItem(i) + if item.publication_name then + table.insert(dependencies, { + publication_name = item.publication_name + }) + else + table.insert(dependencies, { + source_url = item.source_url, + path = "Resources/" .. item.path + }) + end + end + + if categoryComboBox.selectedItem == 1 then + table.insert(dependencies, { + source_url = iconUrlInput.text, + path = "Resources/Icon.pic" + }) + end + + local success, reason = RawAPIRequest("upload", { + token = config.user.token, + name = web.encode(nameInput.text), + source_url = mainUrlInput.text, + path = web.encode(categoryComboBox.selectedItem == 1 and "Main.lua" or mainPathInput.text), + description = web.encode(descriptionInput.text), + license_id = licenseComboBox.selectedItem, + dependencies = dependencies, + category_id = categoryComboBox.selectedItem, + }) + + if success then + window.tabBar.selectedItem = categoryComboBox.selectedItem + config.orderBy = 2 + updateFileList(window.tabBar.selectedItem) + else + GUI.error(reason) + end + end + + categoryComboBox.onItemSelected() +end + +-------------------------------------------------------------------------------- + +updateFileList = function(category_id) + status("Обновление списка приложений...") + + -- Получаем общий список приложений + local list, reason = fieldAPIRequest("list", "list", { + publications_only = true, + category_id = category_id, + fields = { + "average_rating", + "dependencies", + "publication_name", + "user_name", + "path", + "source_url", + }, + order_by = orderBys[config.orderBy], + order_direction = orderDirections[config.orderDirection], + offset = currentPage * appsPerPage, + count = appsPerPage + 1, + search = search + }) + + if list then + contentContainer:deleteChildren() + + local y = 2 + + local layout = contentContainer:addChild(GUI.layout(1, y, contentContainer.width, 1, 1, 1)) + layout:setCellDirection(1, 1, GUI.directions.horizontal) + layout:setCellSpacing(1, 1, 2) + + local input = layout:addChild(GUI.input(1, 1, 20, layout.height, 0xFFFFFF, 0x2D2D2D, 0x666666, 0xFFFFFF, 0x2D2D2D, search or "", "Поиск", true)) + input.onInputFinished = function() + if #input.text == 0 then + search = nil + else + search = input.text + end + + updateFileList(category_id) + end + + local orderByComboBox = layout:addChild(GUI.comboBox(1, 1, 18, layout.height, 0xFFFFFF, 0x666666, 0x999999, 0xE1E1E1)) + orderByComboBox:addItem("По рейтингу") + orderByComboBox:addItem("По дате") + orderByComboBox:addItem("По имени") + orderByComboBox.selectedItem = config.orderBy + + local orderDirectionComboBox = layout:addChild(GUI.comboBox(1, 1, 18, layout.height, 0xFFFFFF, 0x666666, 0x999999, 0xE1E1E1)) + orderDirectionComboBox:addItem("По убыванию") + orderDirectionComboBox:addItem("По возрастанию") + orderDirectionComboBox.selectedItem = config.orderDirection + + orderByComboBox.onItemSelected = function() + config.orderBy = orderByComboBox.selectedItem + config.orderDirection = orderDirectionComboBox.selectedItem + updateFileList(category_id) + saveConfig() + end + orderDirectionComboBox.onItemSelected = orderByComboBox.onItemSelected + + if config.user.token then + local uploadButton = layout:addChild(GUI.adaptiveRoundedButton(1, 1, 1, 0, 0x666666, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "Опубликовать ПО")) + uploadButton.onTouch = function() + editPublication() + end + end + + y = y + layout.height + 1 + + local navigationLayout = contentContainer:addChild(GUI.layout(1, contentContainer.height - 1, contentContainer.width, 1, 1, 1)) + navigationLayout:setCellDirection(1, 1, GUI.directions.horizontal) + navigationLayout:setCellSpacing(1, 1, 2) + + local function switchPage(forward) + currentPage = currentPage + (forward and 1 or -1) + updateFileList(category_id) + end + + local backButton = navigationLayout:addChild(GUI.adaptiveRoundedButton(1, 1, 1, 0, 0xFFFFFF, 0x666666, 0x2D2D2D, 0xFFFFFF, "<")) + backButton.disabled = currentPage == 0 + backButton.onTouch = function() + switchPage(false) + end + + navigationLayout:addChild(GUI.text(1, 1, 0x666666, "Страница " .. (currentPage + 1))) + local nextButton = navigationLayout:addChild(GUI.adaptiveRoundedButton(1, 1, 1, 0, 0xFFFFFF, 0x666666, 0x2D2D2D, 0xFFFFFF, ">")) + nextButton.disabled = #list <= appsPerPage + nextButton.onTouch = function() + switchPage(true) + end + + local xStart = math.floor(1 + contentContainer.width / 2 - (appsPerWidth * (appWidth + appHSpacing) - appHSpacing) / 2) + local x, counter = xStart, 1 + for i = 1, #list do + -- Сам ты пидор! + list[i].category_id = category_id + -- Если мы чекаем приложухи, и в этой публикации есть какие-то зависимости + if category_id == 1 and list[i].dependencies then + -- Получаем лист этих зависимостей по идшникам, выдавая только путь и урлку + local dependencies, reason = fieldAPIRequest("list", "list", { + file_ids = list[i].dependencies, + fields = { + "path", + "source_url" + } + }) + + if dependencies then + list[i].expandedDependencies = dependencies + else + GUI.error(reason) + end + end + + contentContainer:addChild(newApplicationPreview(x, y, list[i])) + + x = x + appWidth + appHSpacing + if counter >= appsPerPage then + break + elseif counter % appsPerWidth == 0 then + x, y = xStart, y + appHeight + appVSpacing + end + counter = counter + 1 + + -- Если мы тока шо создали приложеньку, от отрисовываем содержимое сразу же + if category_id == 1 then + MineOSInterface.OSDraw() + end + end + else + GUI.error(reason) + end + + status("Ожидание") +end + +window.onResize = function(width, height) + window.backgroundPanel.width = width + window.backgroundPanel.height = height - 4 + contentContainer.width = width + contentContainer.height = window.height - 4 + window.tabBar.width = width + statusWidget.width = window.width + statusWidget.localY = window.height + + appsPerWidth = math.floor((contentContainer.width + appHSpacing) / (appWidth + appHSpacing)) + appsPerHeight = math.floor((contentContainer.height - 6 + appVSpacing) / (appHeight + appVSpacing)) + appsPerPage = appsPerWidth * appsPerHeight +end + +local function account() + contentContainer:deleteChildren() + + local layout = contentContainer:addChild(GUI.layout(1, 1, contentContainer.width, contentContainer.height, 1, 1)) + + if config.user.token then + local list, reason = fieldAPIRequest("list", "list", { + file_ids = {file_id}, + fields = { + "publication_id", + "publication_name", + "file_id", + }, + publications_only = true, + user_id = config.user.id, + order_by = "publication_name", + }) + + if list then + layout:addChild(GUI.text(1, 1, 0x2D2D2D, "Профиль")) + layout:addChild(GUI.label(1, 1, 36, 1, 0x888888, "Имя: " .. config.user.name)) + layout:addChild(GUI.label(1, 1, 36, 1, 0x888888, "E-Mail: " .. config.user.email)) + layout:addChild(GUI.label(1, 1, 36, 1, 0x888888, "Дата регистрации: " .. os.date("%d.%m.%Y", config.user.timestamp))) + + layout:addChild(GUI.adaptiveRoundedButton(1, 1, 2, 0, 0xAAAAAA, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "Выход")).onTouch = function() + config.user = {} + saveConfig() + account() + end + + if #list > 0 then + layout:addChild(GUI.text(1, 1, 0x2D2D2D, "Публикации")) + + local comboBox = layout:addChild(GUI.comboBox(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0x999999, 0xE1E1E1)) + for i = 1, #list do + comboBox:addItem(list[i].publication_name) + end + + local buttonsLayout = layout:addChild(GUI.layout(1, 1, layout.width, 1, 1, 1)) + buttonsLayout:setCellDirection(1, 1, GUI.directions.horizontal) + buttonsLayout:setCellSpacing(1, 1, 3) + buttonsLayout:addChild(GUI.adaptiveRoundedButton(1, 1, 1, 0, 0xAAAAAA, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "Открыть")).onTouch = function() + newApplicationInfo(list[comboBox.selectedItem].file_id) + end + buttonsLayout:addChild(GUI.adaptiveRoundedButton(1, 1, 1, 0, 0xAAAAAA, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "Изменить")) + buttonsLayout:addChild(GUI.adaptiveRoundedButton(1, 1, 1, 0, 0xAAAAAA, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "Удалить")) + end + + + else + GUI.error(reason) + end + else + local function addShit(register) + layout:deleteChildren() + + local text = register and "Register" or "Login" + layout:addChild(GUI.label(1, 1, 36, 1, 0x0, text)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + + if register then + layout.nameInput = layout:addChild(GUI.input(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "Username")) + end + + layout.emailInput = layout:addChild(GUI.input(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, config.user.email or "", register and "E-mail" or "E-Mail или никнейм")) + layout.passwordInput = layout:addChild(GUI.input(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, config.user.password or "", "Password", false, "*")) + + if register then + layout.submit = layout:addChild(GUI.button(1, 1, 36, 3, 0xAAAAAA, 0xFFFFFF, 0x666666, 0xFFFFFF, text)) + end + end + + addShit(false) + + layout:addChild(GUI.button(1, 1, 36, 3, 0xAAAAAA, 0xFFFFFF, 0x666666, 0xFFFFFF, "Login")).onTouch = function() + local user, reason = fieldAPIRequest("user", "login", { + [(string.find(layout.emailInput.text, "@") and "email" or "name")] = layout.emailInput.text, + password = layout.passwordInput.text + }) + + if user then + config.user = { + token = user.token, + name = user.name, + id = user.id, + email = user.email, + timestamp = user.timestamp, + password = layout.passwordInput.text, + } + saveConfig() + account() + else + GUI.error(reason) + end + end + + local registerLayout = layout:addChild(GUI.layout(1, 1, layout.width, 1, 1, 1)) + registerLayout:setCellDirection(1, 1, GUI.directions.horizontal) + + local registerText = registerLayout:addChild(GUI.text(1, 1, 0xAAAAAA, "Еще не зарегистрированы?")) + registerLayout:addChild(GUI.adaptiveButton(1, 1, 0, 0, nil, 0x666666, nil, 0x0, "Создать аккаунт")).onTouch = function() + addShit(true) + + layout.submit.onTouch = function() + local information, reason = fieldAPIRequest("information", "register", { + name = layout.nameInput.text, + email = layout.emailInput.text, + password = layout.passwordInput.text, + }) + + if information then + GUI.error("Все заебись! Чекни свое мыло (" .. layout.emailInput.text .. ") и папку спама, чтобы подтвердить свой акк") + else + GUI.error(reason) + end + end + end + end +end + +local function loadCategory(id) + currentPage = 0 + updateFileList(id) +end + +window.tabBar:addItem(categories[1]).onTouch = function() + loadCategory(1) +end + +window.tabBar:addItem(categories[2]).onTouch = function() + loadCategory(2) +end + +window.tabBar:addItem(categories[3]).onTouch = function() + loadCategory(3) +end + +window.tabBar:addItem("Обновления").onTouch = function() + +end + +window.tabBar:addItem("Аккаунт").onTouch = function() + account() +end + +-------------------------------------------------------------------------------- + +loadConfig() +window:resize(window.width, window.height) +-- window.tabBar:getItem(2).onTouch() +newApplicationInfo(169) + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/EBAMARKET2.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/EBAMARKET2.app/Resources/Icon.pic new file mode 100644 index 00000000..1e0deecf Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/EBAMARKET2.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/FlappyBird.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/FlappyBird.lnk new file mode 100644 index 00000000..3a698afa --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/FlappyBird.lnk @@ -0,0 +1 @@ +/MineOS/Applications/FlappyBird.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/ForceAdmin.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/ForceAdmin.lnk new file mode 100644 index 00000000..3d9b653c --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/ForceAdmin.lnk @@ -0,0 +1 @@ +/MineOS/Applications/ForceAdmin.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/FuckTheRain.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/FuckTheRain.lnk new file mode 100644 index 00000000..00ce646a --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/FuckTheRain.lnk @@ -0,0 +1 @@ +/MineOS/Applications/FuckTheRain.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/GeoScan2.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/GeoScan2.lnk new file mode 100644 index 00000000..8e5ffbc4 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/GeoScan2.lnk @@ -0,0 +1 @@ +/MineOS/Applications/GeoScan2.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Graph2.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Graph2.app/Main.lua new file mode 100644 index 00000000..04ce8571 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Graph2.app/Main.lua @@ -0,0 +1,146 @@ + +require("advancedLua") +local fs = require("filesystem") +local buffer = require("doubleBuffering") +local GUI = require("GUI") +local unicode = require("unicode") +local MineOSInterface = require("MineOSInterface") + +--------------------------------------------------------------------------------------------------------- + +local mainContainer, window = MineOSInterface.addWindow(MineOSInterface.filledWindow(1, 1, 110, 25, 0xF0F0F0)) +local yDependencyString = "math.sin(x)" +local xOffset, yOffset, xDrag, yDrag, points = 0, 0, 1, 1 + +--------------------------------------------------------------------------------------------------------- + +window.backgroundPanel.localY, window.backgroundPanel.height = 4, window.backgroundPanel.height - 3 +local titlePanel = window:addChild(GUI.panel(1, 1, window.width, 3, 0x2D2D2D)) +local layout = window:addChild(GUI.layout(1, 1, window.width, 3, 1, 1)) +layout:setCellDirection(1, 1, GUI.directions.horizontal) +layout:setCellSpacing(1, 1, 3) + +local switchAndLabel = layout:addChild(GUI.switchAndLabel(1, 1, 16, 6, 0x66DB80, 0x1E1E1E, 0xF0F0F0, 0xBBBBBB, "Quants:", false)) +local scaleSlider = layout:addChild(GUI.slider(1, 1, 12, 0x66DB80, 0x0, 0xFFFFFF, 0xBBBBBB, 1, 1000, 400, false, "Scale: ", "%")) +local rangeSlider = layout:addChild(GUI.slider(1, 1, 12, 0x66DB80, 0x0, 0xFFFFFF, 0xBBBBBB, 2, 60, 25, false, "Range: ", "")) +local precisionSlider = layout:addChild(GUI.slider(1, 1, 12, 0x66DB80, 0x0, 0xFFFFFF, 0xBBBBBB, 10, 99, 72, false, "Step: 0.", "")) +local functionButton = window:addChild(GUI.button(1, 1, 1, 3, 0xF0F0F0, 0x3C3C3C, 0xCCCCCC, 0x3C3C3C, "")) + +window.actionButtons:moveToFront() + +local graph = window:addChild(GUI.object(1, 4, window.width, window.height - 3)) +graph.draw = function(graph) + local x1, x2, y1, y2 = buffer.getDrawLimit() + buffer.setDrawLimit(graph.x, graph.y, graph.x + graph.width - 1, graph.y + graph.height - 1) + + local xCenter, yCenter = graph.x + xOffset + graph.width / 2 - 1, graph.y + yOffset + graph.height / 2 - 1 + + buffer.semiPixelLine(math.floor(graph.x), math.floor(yCenter * 2), math.floor(graph.x + graph.width - 1), math.floor(yCenter * 2), 0xD2D2D2) + buffer.semiPixelLine(math.floor(xCenter), math.floor(graph.y * 2 - 1), math.floor(xCenter), math.floor(graph.y + graph.height - 1) * 2, 0xD2D2D2) + + for i = 1, #points - 1 do + local x1, x2, y1, y2 = math.floor(xCenter + points[i].x), math.floor(yCenter - points[i].y + 1) * 2, math.floor(xCenter + points[i + 1].x), math.floor(yCenter - points[i + 1].y + 1) * 2 + buffer.semiPixelLine(x1, x2, y1, y2, 0x0) + if switchAndLabel.switch.state then + buffer.semiPixelSet(x1, x2, 0x66DB80) + end + end + + buffer.setDrawLimit(x1, x2, y1, y2) +end + +local function update() + functionButton.text = "f(x)=" .. yDependencyString:gsub("%s+", "") + functionButton.width = unicode.len(functionButton.text) + 4 + functionButton.localX = window.width - functionButton.width + 1 + titlePanel.width = window.width - functionButton.width + layout.width = titlePanel.width + + points = {} + local scale = scaleSlider.value / 100 + local xRange = rangeSlider.value + local step = precisionSlider.value / 100 + + for x = -xRange, xRange, step do + local success, y = pcall(load("local x = " .. x .. "; local y = " .. yDependencyString .. "; return y")) + if success and tonumber(y) then + if not (y ~= y) then + table.insert(points, { + x = x * scale, + y = y * scale + }) + end + else + GUI.error("Invalid input function") + return + end + end +end + +functionButton.onTouch = function() + local container = MineOSInterface.addUniversalContainer(window, "Set function f(x)") + local inputField = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x666666, 0xEEEEEE, 0x262626, yDependencyString, "f(x)", false)) + inputField.onInputFinished = function() + if inputField.text then + yDependencyString = inputField.text + update() + + container:delete() + mainContainer:draw() + buffer.draw() + end + end + + mainContainer:draw() + buffer.draw() +end + +scaleSlider.onValueChanged = function() + update() + mainContainer:draw() + buffer.draw() +end +rangeSlider.onValueChanged = scaleSlider.onValueChanged +precisionSlider.onValueChanged = scaleSlider.onValueChanged + +scaleSlider.roundValues, rangeSlider.roundValues, precisionSlider.roundValues = true, true, true + +window.onResize = function(width, height) + window.backgroundPanel.width, window.backgroundPanel.height = width, height - 3 + graph.width, graph.height = width, height - 3 + + update() +end + +graph.eventHandler = function(mainContainer, graph, eventData) + if eventData[1] == "touch" then + xDrag, yDrag = eventData[3], eventData[4] + elseif eventData[1] == "drag" then + xOffset, yOffset = xOffset + (eventData[3] - xDrag), yOffset + (eventData[4] - yDrag) + mainContainer:draw() + buffer.draw() + + xDrag, yDrag = eventData[3], eventData[4] + elseif eventData[1] == "scroll" then + scaleSlider.value = scaleSlider.value + eventData[5] * 10 + if scaleSlider.value < scaleSlider.minimumValue then + scaleSlider.value = scaleSlider.minimumValue + elseif scaleSlider.value > scaleSlider.maximumValue then + scaleSlider.value = scaleSlider.maximumValue + end + + update() + + mainContainer:draw() + buffer.draw() + end +end + +--------------------------------------------------------------------------------------------------------- + +update() +mainContainer:draw() +buffer.draw() + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Graph2.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Graph2.app/Resources/Icon.pic new file mode 100644 index 00000000..dbdfb997 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Graph2.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/GuessWord.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/GuessWord.lnk new file mode 100644 index 00000000..25f4d112 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/GuessWord.lnk @@ -0,0 +1 @@ +/MineOS/Applications/GuessWord.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/HEX.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/HEX.lnk new file mode 100644 index 00000000..1b7a24e1 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/HEX.lnk @@ -0,0 +1 @@ +/MineOS/Applications/HEX.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/HoloClock.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/HoloClock.lnk new file mode 100644 index 00000000..b254f30d --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/HoloClock.lnk @@ -0,0 +1 @@ +/MineOS/Applications/HoloClock.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/HoloEdit.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/HoloEdit.lnk new file mode 100644 index 00000000..7ec71be4 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/HoloEdit.lnk @@ -0,0 +1 @@ +/MineOS/Applications/HoloEdit.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/InfoPanel.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/InfoPanel.lnk new file mode 100644 index 00000000..c79e511c --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/InfoPanel.lnk @@ -0,0 +1 @@ +/MineOS/Applications/InfoPanel.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/.icons b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/.icons new file mode 100644 index 00000000..3588aaf4 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/.icons @@ -0,0 +1 @@ +{["Main.lua"]={["y"]=2,["x"]=17},["Resources"]={["y"]=2,["x"]=3}} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/Main.lua new file mode 100644 index 00000000..4a587361 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/Main.lua @@ -0,0 +1,299 @@ + +-- package.loaded.color = nil +-- package.loaded.GUI = nil + +require("advancedLua") +local computer = require("computer") +local component = require("component") +local fs = require("filesystem") +local buffer = require("doubleBuffering") +local GUI = require("GUI") +local unicode = require("unicode") +local image = require("image") +local keyboard = require("keyboard") +local color = require("color") + +local resourcesPath = fs.path(getCurrentScript()) .. "/Resources/" +local toolsPath = resourcesPath .. "/Tools/" + +--------------------------------------------------------------------------------------------------------- + +-- /MineOS/Desktop/PS4.app/Main.lua +local mainContainer = GUI.fullScreenContainer() +mainContainer.backgroundPanel = mainContainer:addChild(GUI.panel(1, 2, mainContainer.width, mainContainer.height - 1, 0x262626)) + +--------------------------------------------------------------------------------------------------------- + +mainContainer.drawingZone = mainContainer:addChild(GUI.object(8, 3, 1, 1)) +mainContainer.drawingZone.layers = {current = 1} + +local function mergeLayersAtPixel(x, y) + local background, foreground, alpha, symbol = image.get(mainContainer.drawingZone.layers[1], x, y) + + for layer = 2, #mainContainer.drawingZone.layers do + local backgroundNext, foregroundNext, alphaNext, symbolNext = image.get(mainContainer.drawingZone.layers[layer], x, y) + if backgroundNext then + if background then + background, alpha = color.blendRGBA(background, backgroundNext, alpha / 255, alphaNext / 255) + alpha = alpha * 255 + else + background, alpha = backgroundNext, alphaNext / 255 + end + + foreground = foregroundNext + symbol = symbolNext + end + end + + return background or 0x0, foreground or 0x0, alpha or 255, symbol or " " +end + +mainContainer.drawingZone.draw = function(object) + local step = false + for y = 1, object.height do + for x = 1, object.width do + local background, foreground, alpha, symbol = mergeLayersAtPixel(x, y) + buffer.set( + object.x + x - 1, + object.y + y - 1, + color.blend(step and 0xFFFFFF or 0xDDDDDD, background, alpha / 255), + foreground, + symbol + ) + + step = not step + end + end +end + +mainContainer.drawingZone.eventHandler = function(mainContainer, object, eventData) + mainContainer.leftToolbar.toolsContainer.children[mainContainer.leftToolbar.toolsContainer.current].module.onEvent(mainContainer, eventData) +end + +--------------------------------------------------------------------------------------------------------- + +mainContainer.menu = mainContainer:addChild(GUI.menu(1, 1, mainContainer.width, 0xDDDDDD, 0x666666, 0x3366CC, 0xFFFFFF)) +mainContainer.menu:addItem("PS", 0x0) +mainContainer.menu:addItem("File", 0x444444).onTouch = function() + +end +mainContainer.menu:addItem("Edit", 0x444444).onTouch = function() + +end + +--------------------------------------------------------------------------------------------------------- + +local layersToolbarWidth = math.floor(mainContainer.width * 0.2) +mainContainer.layersToolbar = mainContainer:addChild(GUI.container(mainContainer.width - layersToolbarWidth + 1, 2, layersToolbarWidth, mainContainer.height - 1)) +mainContainer.layersToolbar.layersObject = mainContainer.layersToolbar:addChild(GUI.object(1, 1, mainContainer.layersToolbar.width, mainContainer.layersToolbar.height)) +mainContainer.layersToolbar.layersObject.offset = 0 + +mainContainer.layersToolbar.layersObject.draw = function(object) + buffer.square(object.x, object.y, object.width, object.height, 0x444444, 0x555555, " ") + + local y = object.y + object.offset + buffer.text(object.x, y, 0x262626, string.rep("─", object.width)) + buffer.text(object.x + 5, y, 0x262626, "┬") + y = y + 1 + for i = #mainContainer.drawingZone.layers, 1, -1 do + if i == mainContainer.drawingZone.layers.current then + buffer.square(object.x, y, object.width, 3, 0x555555, 0xAAAAAA, " ") + end + + -- Миниатюра + buffer.square(object.x + 7, y, 6, 3, 0xFFFFFF) + + -- Текст + buffer.text(object.x + 14, y + 1, 0xAAAAAA, mainContainer.drawingZone.layers[i].text) + + -- Кнопочка оффанья + if mainContainer.drawingZone.layers[i].hidden then + buffer.set(object.x + 2, y + 1, 0x3C3C3C, 0xAAAAAA, " ") + else + buffer.set(object.x + 2, y + 1, 0x3C3C3C, 0xAAAAAA, "*") + end + + -- Рамки + for i = 1, 3 do + buffer.text(object.x + 5, y + i - 1, 0x262626, "│") + end + buffer.text(object.x, y + 3, 0x262626, string.rep("─", object.width)) + buffer.text(object.x + 5, y + 3, 0x262626, i > 1 and "┼" or "┴") + + + y = y + 4 + end +end + +mainContainer.layersToolbar.layersObject.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + local index = math.ceil((eventData[4] - object.y - object.offset + 1) / 4) + + mainContainer.drawingZone.layers.current = #mainContainer.drawingZone.layers - index + 1 + + mainContainer:draw() + buffer.draw() + elseif eventData[1] == "scroll" then + object.offset = object.offset + eventData[5] + if object.offset > 0 then + object.offset = 0 + end + + mainContainer:draw() + buffer.draw() + end +end + +local function newLayer(text) + local atIndex = #mainContainer.drawingZone.layers > 0 and mainContainer.drawingZone.layers.current + 1 or 1 + + table.insert( + mainContainer.drawingZone.layers, + atIndex, + { + text = text, + hidden = false, + [1] = mainContainer.drawingZone.width, + [2] = mainContainer.drawingZone.height + } + ) +end + +--------------------------------------------------------------------------------------------------------- + +mainContainer.leftToolbar = mainContainer:addChild(GUI.container(1, 2, 5, mainContainer.height - 1)) +mainContainer.leftToolbar:addChild(GUI.panel(1, 1, mainContainer.leftToolbar.width, mainContainer.leftToolbar.height, 0x444444)) +mainContainer.leftToolbar.toolsContainer = mainContainer.leftToolbar:addChild(GUI.container(1, 1, mainContainer.leftToolbar.width, mainContainer.leftToolbar.height)) + +local function toolDraw(object) + local background, foreground = object.state and 0x3C3C3C or 0x555555, object.state and 0xAAAAAA or 0xAAAAAA + buffer.square(object.x, object.y, object.width, object.height, background, foreground, " ") + buffer.set(math.floor(object.x + object.width / 2), math.floor(object.y + object.height / 2), background, foreground, object.module.shortcut) + + return object +end + +local function selectTool(index) + mainContainer.leftToolbar.toolsContainer.current = index + for i = 1, #mainContainer.leftToolbar.toolsContainer.children do + mainContainer.leftToolbar.toolsContainer.children[i].state = i == index + end +end + +local function toolEventHandler(mainContainer, object, eventData) + if eventData[1] == "touch" then + selectTool(object:indexOf()) + + mainContainer:draw() + buffer.draw() + end +end + +local function newTool(y, path) + local object = GUI.object(1, y, mainContainer.leftToolbar.width, 3) + + local success, reason = dofile(path) + if success then + object.module = success + else + error("Failed to load module: " .. tostring(reason)) + end + object.draw = toolDraw + object.eventHandler = toolEventHandler + + return object +end + +local y = 1 +local toolsList = fs.sortedList(toolsPath, "name", false) +for i = 1, #toolsList do + y = y + mainContainer.leftToolbar.toolsContainer:addChild(newTool(y, toolsPath .. toolsList[i])).height +end + +--------------------------------------------------------------------------------------------------------- + +local function colorSelectorDraw(object) + buffer.square(object.x, object.y, object.width, object.height, object.color, 0x0, " ") +end + +local function colorSelectorEventHandler(mainContainer, object, eventData) + if eventData[1] == "touch" then + object.color = require("palette").show(math.floor(mainContainer.width / 2 - 35), math.floor(mainContainer.height / 2 - 12), object.color) or object.color + mainContainer:draw() + buffer.draw() + end +end + +local function newColorSelector(x, y, width, height, color) + local object = GUI.object(x, y, width, height) + + object.color = color + object.draw = colorSelectorDraw + object.eventHandler = colorSelectorEventHandler + + return object +end + +local colorSelectorsY = mainContainer.leftToolbar.height - 4 +mainContainer.leftToolbar.secondColorSelector = mainContainer.leftToolbar:addChild(newColorSelector(2, colorSelectorsY + 1, 4, 2, 0xFF0000)) +mainContainer.leftToolbar.firstColorSelector = mainContainer.leftToolbar:addChild(newColorSelector(1, colorSelectorsY, 4, 2, 0x0000FF)) + +--------------------------------------------------------------------------------------------------------- + +local function new(width, height, background, foreground, alpha, symbol) + mainContainer.drawingZone.width, mainContainer.drawingZone.height = width, height + newLayer("Layer 1") +end + +--------------------------------------------------------------------------------------------------------- + +mainContainer.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "key_down" then + for i = 1, #mainContainer.leftToolbar.toolsContainer.children do + if mainContainer.leftToolbar.toolsContainer.children[i].module.keyCode == eventData[4] then + selectTool(i) + mainContainer:draw() + buffer.draw() + + break + end + end + + -- N + if eventData[4] == 49 then + newLayer("Layer " .. #mainContainer.drawingZone.layers + 1) + mainContainer:draw() + buffer.draw() + elseif eventData[4] == 45 then + mainContainer.leftToolbar.firstColorSelector.color, mainContainer.leftToolbar.secondColorSelector.color = mainContainer.leftToolbar.secondColorSelector.color, mainContainer.leftToolbar.firstColorSelector.color + mainContainer:draw() + buffer.draw() + end + end +end + +--------------------------------------------------------------------------------------------------------- + +buffer.flush() +buffer.draw(true) + +selectTool(2) +new(51, 19, 0x0, 0xFFFFFF, 0x0, "A") +mainContainer:draw() +buffer.draw(true) +mainContainer:startEventHandling() + + + + + + + + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/Resources/Icon.pic new file mode 100644 index 00000000..e7d2f0be Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/Resources/Tools/01_Move.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/Resources/Tools/01_Move.lua new file mode 100644 index 00000000..e842eba5 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/Resources/Tools/01_Move.lua @@ -0,0 +1,34 @@ + +local image = require("image") +local buffer = require("doubleBuffering") +local tool = {} + +--------------------------------------------------------------------------------------------------------- + +tool.shortcut = "M" +tool.keyCode = 47 +tool.lastTouch = {x = 0, y = 0} +tool.offset = {x = 0, y = 0} + +tool.onSelected = function(mainContainer) + +end + +tool.onDeselected = function(mainContainer) + +end + +tool.onEvent = function(mainContainer, eventData) + if eventData[1] == "touch" then + tool.lastTouch.x, tool.lastTouch.y = eventData[3], eventData[4] + elseif eventData[1] == "drag" then + local offset = eventData[3] - tool.lastTouch.x, eventData[3] - tool.lastTouch.y + + mainContainer:draw() + buffer.draw() + end +end + +--------------------------------------------------------------------------------------------------------- + +return tool \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/Resources/Tools/02_Brush.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/Resources/Tools/02_Brush.lua new file mode 100644 index 00000000..f28e91ed --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/Resources/Tools/02_Brush.lua @@ -0,0 +1,31 @@ + +local image = require("image") +local buffer = require("doubleBuffering") +local tool = {} + +--------------------------------------------------------------------------------------------------------- + +tool.shortcut = "B" +tool.keyCode = 48 + +tool.onSelected = function(mainContainer) + +end + +tool.onDeselected = function(mainContainer) + +end + +tool.onEvent = function(mainContainer, eventData) + if eventData[1] == "touch" or eventData[1] == "drag" then + local x, y = eventData[3] - mainContainer.drawingZone.x + 1, eventData[4] - mainContainer.drawingZone.y + 1 + image.set(mainContainer.drawingZone.layers[mainContainer.drawingZone.layers.current], x, y, mainContainer.leftToolbar.firstColorSelector.color, 0x0, 0x0, " ") + + mainContainer:draw() + buffer.draw() + end +end + +--------------------------------------------------------------------------------------------------------- + +return tool \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/Resources/Tools/03_Eraser.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/Resources/Tools/03_Eraser.lua new file mode 100644 index 00000000..2a5cc178 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PS4.app/Resources/Tools/03_Eraser.lua @@ -0,0 +1,31 @@ + +local image = require("image") +local buffer = require("doubleBuffering") +local tool = {} + +--------------------------------------------------------------------------------------------------------- + +tool.shortcut = "E" +tool.keyCode = 18 + +tool.onSelected = function(mainContainer) + +end + +tool.onDeselected = function(mainContainer) + +end + +tool.onEvent = function(mainContainer, eventData) + if eventData[1] == "touch" or eventData[1] == "drag" then + local x, y = eventData[3] - mainContainer.drawingZone.x + 1, eventData[4] - mainContainer.drawingZone.y + 1 + image.set(mainContainer.drawingZone.layers[mainContainer.drawingZone.layers.current], x, y, 0x0, 0x0, 0xFF, " ") + + mainContainer:draw() + buffer.draw() + end +end + +--------------------------------------------------------------------------------------------------------- + +return tool \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Palette.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Palette.lnk new file mode 100644 index 00000000..13ba3a77 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Palette.lnk @@ -0,0 +1 @@ +/MineOS/Applications/Palette.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PrintImage.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PrintImage.lnk new file mode 100644 index 00000000..9c847d93 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/PrintImage.lnk @@ -0,0 +1 @@ +/MineOS/Applications/PrintImage.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/QuantumCube.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/QuantumCube.lnk new file mode 100644 index 00000000..693aa456 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/QuantumCube.lnk @@ -0,0 +1 @@ +/MineOS/Applications/QuantumCube.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Radio.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Radio.lnk new file mode 100644 index 00000000..12aee897 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Radio.lnk @@ -0,0 +1 @@ +/MineOS/Applications/Radio.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/RayWalk.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/RayWalk.lnk new file mode 100644 index 00000000..c576d268 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/RayWalk.lnk @@ -0,0 +1 @@ +/MineOS/Applications/RayWalk.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/RunningString.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/RunningString.lnk new file mode 100644 index 00000000..2cee86d8 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/RunningString.lnk @@ -0,0 +1 @@ +/MineOS/Applications/RunningString.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Shooting.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Shooting.lnk new file mode 100644 index 00000000..8ca2bf42 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Shooting.lnk @@ -0,0 +1 @@ +/MineOS/Applications/Shooting.app \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Main.lua new file mode 100644 index 00000000..ce205e53 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Main.lua @@ -0,0 +1,93 @@ + +require("advancedLua") +local fs = require("filesystem") +local buffer = require("doubleBuffering") +local color = require("color") +local image = require("image") +local GUI = require("GUI") + +------------------------------------------------------------------------------------------ + +local spinnersPath = fs.path(getCurrentScript()) .. "/Resources/" +local spinners = {} +local currentSpinner = 1 +local spinnerLimit = 8 +local spinnerHue = math.random(0, 360) +local spinnerHueStep = 20 + +local mainContainer = GUI.fullScreenContainer() +mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x0)) +local spinnerImage = mainContainer:addChild(GUI.image(1, 1, {1, 1})) + +------------------------------------------------------------------------------------------ + +local function changeColor(hue, saturation) + for i = 1, #spinners do + for y = 1, image.getHeight(spinners[i]) do + for x = 1, image.getWidth(spinners[i]) do + local background, foreground, alpha, symbol = image.get(spinners[i], x, y) + local hBackground, sBackground, bBackground = color.IntegerToHSB(background) + local hForeground, sForeground, bForeground = color.IntegerToHSB(foreground) + image.set( + spinners[i], + x, + y, + color.HSBToInteger(hue, saturation, bBackground), + color.HSBToInteger(hue, saturation, bForeground), + alpha, + symbol + ) + end + end + end + spinnerImage.image = spinners[currentSpinner] +end + +mainContainer.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "key_down" then + mainContainer:stopEventHandling() + elseif eventData[1] == "touch" then + spinnerHue = spinnerHue + spinnerHueStep * (eventData[5] == 1 and -1 or 1) + if spinnerHue > 360 then + spinnerHue = 0 + elseif spinnerHue < 0 then + spinnerHue = 360 + end + changeColor(spinnerHue, 1) + end + + currentSpinner = currentSpinner + 1 + if currentSpinner > #spinners then + currentSpinner = 1 + end + spinnerImage.image = spinners[currentSpinner] + + mainContainer:draw() + buffer.draw() +end + +------------------------------------------------------------------------------------------ + +for i = 1, spinnerLimit do + spinners[i] = image.load(spinnersPath .. i .. ".pic") +end +spinnerImage.width = image.getWidth(spinners[currentSpinner]) +spinnerImage.height = image.getHeight(spinners[currentSpinner]) +spinnerImage.localX = math.floor(mainContainer.width / 2 - spinnerImage.width / 2) +spinnerImage.localY = math.floor(mainContainer.height / 2 - spinnerImage.height/ 2) + +changeColor(spinnerHue, 1) +buffer.flush() +mainContainer:draw() +buffer.draw(true) + +mainContainer:startEventHandling(0) + + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/1.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/1.pic new file mode 100644 index 00000000..21a56038 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/1.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/2.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/2.pic new file mode 100644 index 00000000..013dc0d5 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/2.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/3.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/3.pic new file mode 100644 index 00000000..d16757fa Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/3.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/4.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/4.pic new file mode 100644 index 00000000..1a268af1 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/4.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/5.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/5.pic new file mode 100644 index 00000000..c9b6149e Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/5.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/6.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/6.pic new file mode 100644 index 00000000..5eabac92 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/6.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/7.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/7.pic new file mode 100644 index 00000000..6615f5cc Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/7.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/8.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/8.pic new file mode 100644 index 00000000..393a0e83 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/8.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/Icon.pic new file mode 100644 index 00000000..34e35112 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Spinner.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Stargate.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Stargate.lnk new file mode 100644 index 00000000..fe581214 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Stargate.lnk @@ -0,0 +1 @@ +/MineOS/Applications/Stargate.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Translate.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Translate.app/Main.lua new file mode 100644 index 00000000..954d0cbc --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Translate.app/Main.lua @@ -0,0 +1,192 @@ + +require("advancedLua") +local fs = require("filesystem") +local json = require("json") +local web = require("web") +local GUI = require("GUI") +local buffer = require("doubleBuffering") +local image = require("image") +local unicode = require("unicode") + +------------------------------------------------------------------------------------------------------------------ + +local resourcesPath = fs.path(getCurrentScript()) .. "/Resources/" +local configPath = resourcesPath .. "Config.cfg" +local config = { + APIKey = "trnsl.1.1.20170831T153247Z.6ecf9d7198504994.8ce5a3aa9f9a2ecbe7b2377af37ffe5ad379f4ca", + fromLanguage = "Русский", + toLanguage = "Английский", + languages = {}, +} + +local function saveConfig() + table.toFile(configPath, config) +end + +if fs.exists(configPath) then + config = table.fromFile(configPath) +end + +------------------------------------------------------------------------------------------------------------------ + +local mainContainer = GUI.fullScreenContainer() +mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x1E1E1E)) +local actionButtons = mainContainer:addChild(GUI.actionButtons(2, 1)) +local layout = mainContainer:addChild(GUI.layout(1, 1, mainContainer.width, mainContainer.height, 1, 1)) + +local logo = layout:addChild(GUI.image(1, 1, image.load(resourcesPath .. "Logo.pic"))) +local elementWidth = image.getWidth(logo.image) +layout:addChild(GUI.object(1, 1, 1, 1)) + +local fromLanguageContainer = layout:addChild(GUI.container(1, 1, elementWidth, 1)) +local fromLanguageAutoDetectButton = fromLanguageContainer:addChild(GUI.adaptiveButton(1, 1, 2, 0, 0x2D2D2D, 0xBBBBBB, 0x666666, 0xBBBBBB, "Определить язык")) +fromLanguageAutoDetectButton.localX = fromLanguageContainer.width - fromLanguageAutoDetectButton.width + 1 +local fromComboBox = fromLanguageContainer:addChild(GUI.comboBox(1, 1, fromLanguageAutoDetectButton.localX - 3, 1, 0x2D2D2D, 0xAAAAAA, 0x444444, 0x888888)) +local fromInputField = layout:addChild(GUI.input(1, 1, elementWidth, 5, 0x2D2D2D, 0x666666, 0x444444, 0x3C3C3C, 0xBBBBBB, nil, "Введите текст", true)) + +local switchButton = layout:addChild(GUI.adaptiveRoundedButton(1, 1, 3, 1, 0x2D2D2D, 0xBBBBBB, 0x666666, 0xBBBBBB, "←→")) + +local toComboBox = layout:addChild(GUI.comboBox(1, 1, elementWidth, 1, 0x2D2D2D, 0xAAAAAA, 0x444444, 0x888888)) +local toInputField = layout:addChild(GUI.input(1, 1, elementWidth, 5, 0x2D2D2D, 0x666666, 0x444444, 0x3C3C3C, 0xBBBBBB, nil, nil)) + +layout:addChild(GUI.label(1, 1, elementWidth, 1, 0xAAAAAA, "API Key:"):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) +local APIKeyInputField = layout:addChild(GUI.input(1, 1, elementWidth, 1, 0x1E1E1E, 0x666666, 0x444444, 0x1E1E1E, 0xBBBBBB, config.APIKey, "Введите API Key", true)) + +local infoLabel = layout:addChild(GUI.label(1, 1, elementWidth, 1, 0xFF6D40, " "):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) + +------------------------------------------------------------------------------------------------------------------ + +local function status(text) + infoLabel.text = text + mainContainer:draw() + buffer.draw() +end + +local function getLanguageIndex(text, short) + local type = short and 1 or 2 + for i = 1, #config.languages do + if config.languages[i][type] == text then + return i + end + end +end + +local function fillLanguages() + for i = 1, #config.languages do + fromComboBox:addItem(config.languages[i][2]) + toComboBox:addItem(config.languages[i][2]) + end +end + +local function checkLanguages() + if #config.languages == 0 then + local result, reason = web.request("https://translate.yandex.net/api/v1.5/tr.json/getLangs?key=" .. config.APIKey .. "&ui=ru") + if result then + fromComboBox:clear() + toComboBox:clear() + + local yandexArray = json:decode(result) + for key, value in pairs(yandexArray.langs) do + table.insert(config.languages, {key, value}) + end + table.sort(config.languages, function(a, b) return a[2] < b[2] end) + fillLanguages() + saveConfig() + else + error("Ошибка получения списка языков") + end + else + fillLanguages() + end +end + +local function translate() + if unicode.len(fromInputField.text or "") > 0 then + status("Отправка запроса на перевод...") + + local result, reason = web.request( + "https://translate.yandex.net/api/v1.5/tr.json/translate?key=" .. config.APIKey .. + "&text=" .. string.optimizeForURLRequests(fromInputField.text) .. + "&lang=" .. config.languages[getLanguageIndex(fromComboBox:getItem(fromComboBox.selectedItem).text, false)][1] .. "-" .. + config.languages[getLanguageIndex(toComboBox:getItem(toComboBox.selectedItem).text, false)][1] + ) + + if result then + toInputField.text = json:decode(result).text[1] + status(" ") + + config.fromLanguage = fromComboBox:getItem(fromComboBox.selectedItem).text + config.toLanguage = toComboBox:getItem(toComboBox.selectedItem).text + saveConfig() + else + status("Ошибка во время запроса на перевод") + end + end +end + +fromLanguageAutoDetectButton.onTouch = function() + if unicode.len(fromInputField.text or "") > 0 then + status("Отправка запроса на определение языка...") + + local result, reason = web.request( + "https://translate.yandex.net/api/v1.5/tr.json/detect?key=" .. config.APIKey .. + "&text=" .. string.optimizeForURLRequests(fromInputField.text) + ) + + if result then + result = json:decode(result) + if result.lang then + fromComboBox.selectedItem = getLanguageIndex(result.lang, true) + translate() + else + status("Невозможно определить язык") + end + else + status("Ошибка во время запроса на определение языка") + end + end +end + +actionButtons.close.onTouch = function() + mainContainer:stopEventHandling() +end + +switchButton.onTouch = function() + fromComboBox.selectedItem, toComboBox.selectedItem = toComboBox.selectedItem, fromComboBox.selectedItem + fromInputField.text, toInputField.text = toInputField.text, fromInputField.text + translate() +end + +fromInputField.onInputFinished = function() + translate() +end + +fromComboBox.onItemSelected = function() + translate() +end + +toComboBox.onItemSelected = function() + translate() +end + +APIKeyInputField.onInputFinished = function() + if APIKeyInputField.text then + config.APIKey = APIKeyInputField.text + translate() + saveConfig() + end +end + +toInputField.eventHandler = nil + +------------------------------------------------------------------------------------------------------------------ + +checkLanguages() +fromComboBox.selectedItem = getLanguageIndex(config.fromLanguage, false) +toComboBox.selectedItem = getLanguageIndex(config.toLanguage, false) + +mainContainer:draw() +buffer.draw(true) +mainContainer:startEventHandling() + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Translate.app/Resources/Config.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Translate.app/Resources/Config.cfg new file mode 100644 index 00000000..06e6cdfb --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Translate.app/Resources/Config.cfg @@ -0,0 +1 @@ +{["toLanguage"]="Казахский",["languages"]={[1]={[1]="az",[2]="Азербайджанский"},[2]={[1]="sq",[2]="Албанский"},[3]={[1]="am",[2]="Амхарский"},[4]={[1]="en",[2]="Английский"},[5]={[1]="ar",[2]="Арабский"},[6]={[1]="hy",[2]="Армянский"},[7]={[1]="af",[2]="Африкаанс"},[8]={[1]="eu",[2]="Баскский"},[9]={[1]="ba",[2]="Башкирский"},[10]={[1]="be",[2]="Белорусский"},[11]={[1]="bn",[2]="Бенгальский"},[12]={[1]="my",[2]="Бирманский"},[13]={[1]="bg",[2]="Болгарский"},[14]={[1]="bs",[2]="Боснийский"},[15]={[1]="cy",[2]="Валлийский"},[16]={[1]="hu",[2]="Венгерский"},[17]={[1]="vi",[2]="Вьетнамский"},[18]={[1]="ht",[2]="Гаитянский"},[19]={[1]="gl",[2]="Галисийский"},[20]={[1]="nl",[2]="Голландский"},[21]={[1]="mrj",[2]="Горномарийский"},[22]={[1]="el",[2]="Греческий"},[23]={[1]="ka",[2]="Грузинский"},[24]={[1]="gu",[2]="Гуджарати"},[25]={[1]="da",[2]="Датский"},[26]={[1]="he",[2]="Иврит"},[27]={[1]="yi",[2]="Идиш"},[28]={[1]="id",[2]="Индонезийский"},[29]={[1]="ga",[2]="Ирландский"},[30]={[1]="is",[2]="Исландский"},[31]={[1]="es",[2]="Испанский"},[32]={[1]="it",[2]="Итальянский"},[33]={[1]="kk",[2]="Казахский"},[34]={[1]="kn",[2]="Каннада"},[35]={[1]="ca",[2]="Каталанский"},[36]={[1]="ky",[2]="Киргизский"},[37]={[1]="zh",[2]="Китайский"},[38]={[1]="ko",[2]="Корейский"},[39]={[1]="xh",[2]="Коса"},[40]={[1]="km",[2]="Кхмерский"},[41]={[1]="lo",[2]="Лаосский"},[42]={[1]="la",[2]="Латынь"},[43]={[1]="lv",[2]="Латышский"},[44]={[1]="lt",[2]="Литовский"},[45]={[1]="lb",[2]="Люксембургский"},[46]={[1]="mk",[2]="Македонский"},[47]={[1]="mg",[2]="Малагасийский"},[48]={[1]="ms",[2]="Малайский"},[49]={[1]="ml",[2]="Малаялам"},[50]={[1]="mt",[2]="Мальтийский"},[51]={[1]="mi",[2]="Маори"},[52]={[1]="mr",[2]="Маратхи"},[53]={[1]="mhr",[2]="Марийский"},[54]={[1]="mn",[2]="Монгольский"},[55]={[1]="de",[2]="Немецкий"},[56]={[1]="ne",[2]="Непальский"},[57]={[1]="no",[2]="Норвежский"},[58]={[1]="pa",[2]="Панджаби"},[59]={[1]="pap",[2]="Папьяменто"},[60]={[1]="fa",[2]="Персидский"},[61]={[1]="pl",[2]="Польский"},[62]={[1]="pt",[2]="Португальский"},[63]={[1]="ro",[2]="Румынский"},[64]={[1]="ru",[2]="Русский"},[65]={[1]="ceb",[2]="Себуанский"},[66]={[1]="sr",[2]="Сербский"},[67]={[1]="si",[2]="Сингальский"},[68]={[1]="sk",[2]="Словацкий"},[69]={[1]="sl",[2]="Словенский"},[70]={[1]="sw",[2]="Суахили"},[71]={[1]="su",[2]="Сунданский"},[72]={[1]="tl",[2]="Тагальский"},[73]={[1]="tg",[2]="Таджикский"},[74]={[1]="th",[2]="Тайский"},[75]={[1]="ta",[2]="Тамильский"},[76]={[1]="tt",[2]="Татарский"},[77]={[1]="te",[2]="Телугу"},[78]={[1]="tr",[2]="Турецкий"},[79]={[1]="udm",[2]="Удмуртский"},[80]={[1]="uz",[2]="Узбекский"},[81]={[1]="uk",[2]="Украинский"},[82]={[1]="ur",[2]="Урду"},[83]={[1]="fi",[2]="Финский"},[84]={[1]="fr",[2]="Французский"},[85]={[1]="hi",[2]="Хинди"},[86]={[1]="hr",[2]="Хорватский"},[87]={[1]="cs",[2]="Чешский"},[88]={[1]="sv",[2]="Шведский"},[89]={[1]="gd",[2]="Шотландский (гэльский)"},[90]={[1]="emj",[2]="Эмодзи"},[91]={[1]="eo",[2]="Эсперанто"},[92]={[1]="et",[2]="Эстонский"},[93]={[1]="jv",[2]="Яванский"},[94]={[1]="ja",[2]="Японский"}},["APIKey"]="trnsl.1.1.20170831T153247Z.6ecf9d7198504994.8ce5a3aa9f9a2ecbe7b2377af37ffe5ad379f4ca",["fromLanguage"]="Русский"} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Translate.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Translate.app/Resources/Icon.pic new file mode 100644 index 00000000..026f5a0c Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Translate.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Translate.app/Resources/Logo.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Translate.app/Resources/Logo.pic new file mode 100644 index 00000000..e5bed51b Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Translate.app/Resources/Logo.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/TurretControl.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/TurretControl.lnk new file mode 100644 index 00000000..3b50c1e3 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/TurretControl.lnk @@ -0,0 +1 @@ +/MineOS/Applications/TurretControl.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/VK.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/VK.lnk new file mode 100644 index 00000000..d8da35d4 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/VK.lnk @@ -0,0 +1 @@ +/MineOS/Applications/VK.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Weather.lnk b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Weather.lnk new file mode 100644 index 00000000..086fbc09 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Desktop/Weather.lnk @@ -0,0 +1 @@ +/MineOS/Applications/Weather.app/ \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/AhsokaTano.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/AhsokaTano.pic new file mode 100755 index 00000000..ed942c48 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/AhsokaTano.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Block.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Block.pic new file mode 100755 index 00000000..d2b162ba Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Block.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Catniss.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Catniss.pic new file mode 100755 index 00000000..bb0c4024 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Catniss.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Ciri.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Ciri.pic new file mode 100755 index 00000000..2d5fe3ce Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Ciri.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Girl.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Girl.pic new file mode 100755 index 00000000..a8bcf38f Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Girl.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/HilbertCurve.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/HilbertCurve.pic new file mode 100644 index 00000000..f7bfbb90 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/HilbertCurve.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/MoonTouch.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/MoonTouch.pic new file mode 100755 index 00000000..cf323262 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/MoonTouch.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Mystery.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Mystery.pic new file mode 100755 index 00000000..ba98860c Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Mystery.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Nettle.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Nettle.pic new file mode 100755 index 00000000..2e63b65d Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Nettle.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Raspberry.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Raspberry.pic new file mode 100755 index 00000000..1da69c1a Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Raspberry.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Space.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Space.pic new file mode 100755 index 00000000..c2a53e53 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Space.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Tatu.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Tatu.pic new file mode 100644 index 00000000..c016ae8d Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/Tatu.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/TyanSunset.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/TyanSunset.pic new file mode 100644 index 00000000..90ed02ef Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Pictures/TyanSunset.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/168.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/168.pic new file mode 100644 index 00000000..1e0deecf Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/168.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/170.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/170.pic new file mode 100644 index 00000000..f913804b Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/170.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/174.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/174.pic new file mode 100644 index 00000000..a959182b Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/174.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/176.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/176.pic new file mode 100644 index 00000000..3a4281b9 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/176.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/239.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/239.pic new file mode 100644 index 00000000..dbdfb997 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/239.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/244.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/244.pic new file mode 100644 index 00000000..f1b0f8f1 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/244.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/247.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/247.pic new file mode 100644 index 00000000..026f5a0c Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/247.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/249.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/249.pic new file mode 100644 index 00000000..46c7ddbe Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/249.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/251.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/251.pic new file mode 100644 index 00000000..bb47d9e3 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Cache/251.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Config.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Config.cfg new file mode 100644 index 00000000..efdc2668 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/AppMarket/Config.cfg @@ -0,0 +1 @@ +{["orderDirection"]=1,["orderBy"]=1,["user"]={["id"]=14,["email"]="ECS@mail.ru",["token"]="e33d3ad0f24cde9f5b1873c161a2348cbdc70b99c87717e705",["name"]="ECS",["password"]="1234",["timestamp"]=1517160803},["descriptionLanguage"]="en"} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/FlappyBird/Scores.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/FlappyBird/Scores.cfg new file mode 100644 index 00000000..80fc5953 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/FlappyBird/Scores.cfg @@ -0,0 +1 @@ +{["ECS"]=0} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/HoloClock/Settings.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/HoloClock/Settings.cfg new file mode 100644 index 00000000..71d8c413 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/HoloClock/Settings.cfg @@ -0,0 +1 @@ +{["holoScale"]=0.3,["dateColor"]=12969348} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/MineCode IDE/Config.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/MineCode IDE/Config.cfg new file mode 100644 index 00000000..33af9dfa --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/MineCode IDE/Config.cfg @@ -0,0 +1 @@ +{["enableAutocompletion"]=false,["highlightLuaSyntax"]=true,["doubleClickDelay"]=0.4,["screenResolution"]={["width"]=160,["height"]=44},["scrollSpeed"]=8,["syntaxColorScheme"]={["scrollBarForeground"]=5921370,["compares"]=16777112,["background"]=1973790,["text"]=15658734,["strings"]=10092416,["boolean"]=16767808,["comments"]=8947848,["selection"]=5592405,["loops"]=16777112,["numbers"]=6740991,["lineNumbersBackground"]=2960685,["indentation"]=3947580,["lineNumbersText"]=13421772,["scrollBarBackground"]=2960685,["logic"]=16764006,["functions"]=16764006},["enableAutoBrackets"]=true,["leftTreeViewWidth"]=26,["cursorColor"]=43263,["cursorSymbol"]="┃",["cursorBlinkDelay"]=0.5} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/Palette/Favourites.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/Palette/Favourites.cfg new file mode 100644 index 00000000..5d33ba10 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/Palette/Favourites.cfg @@ -0,0 +1 @@ +{[5]=8752085,[1]=10045887,[2]=1115374,[3]=14459809,[4]=11547445,[6]=10869252} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/Stargate/Contacts.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/Stargate/Contacts.cfg new file mode 100644 index 00000000..fd562f2d --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/Stargate/Contacts.cfg @@ -0,0 +1 @@ +{["last"]="BFU0-VZS-JH"} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/Weather/Forecast.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/Weather/Forecast.cfg new file mode 100644 index 00000000..8b9628d1 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Application data/Weather/Forecast.cfg @@ -0,0 +1 @@ +{["forecast"]={[1]={["day"]="Fri",["code"]=28,["temperature"]="2 / -6°"},[2]={["day"]="Sat",["code"]=26,["temperature"]="5 / 0°"},[3]={["day"]="Sun",["code"]=28,["temperature"]="6 / 4°"},[4]={["day"]="Mon",["code"]=12,["temperature"]="6 / 4°"},[5]={["day"]="Tue",["code"]=39,["temperature"]="5 / 2°"},[6]={["day"]="Wed",["code"]=28,["temperature"]="2 / 0°"},[7]={["day"]="Thu",["code"]=28,["temperature"]="1 / -0°"},[8]={["day"]="Fri",["code"]=26,["temperature"]="2 / -0°"},[9]={["day"]="Sat",["code"]=12,["temperature"]="2 / 1°"},[10]={["day"]="Sun",["code"]=28,["temperature"]="1 / -0°"}},["myCity"]="saint-petersburg",["pressure"]="Давление: 753 мм",["city"]="St. Petersburg, Russia",["humidity"]="Влажность: 92%",["wind"]="Ветер: восточный, 1 м/с",["temperature"]="2°"} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Applications.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Applications.cfg new file mode 100644 index 00000000..0b1ce8b9 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Applications.cfg @@ -0,0 +1,1129 @@ +{ + { + path="/OS.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/OS.lua", + type="Script", + forceDownload=true, + version=4.11, + }, + { + path="/MineOS/Pictures/MoonTouch.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Wallpapers/MoonTouch.pic", + type="Wallpaper", + version=1.01, + }, + { + path="/MineOS/Pictures/Raspberry.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Wallpapers/Raspberry.pic", + type="Wallpaper", + version=1.01, + }, + { + path="/MineOS/Pictures/Catniss.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Wallpapers/Catniss.pic", + type="Wallpaper", + version=1.01, + }, + { + path="/MineOS/Pictures/Ciri.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Wallpapers/Ciri.pic", + type="Wallpaper", + version=1.01, + }, + { + path="/MineOS/Pictures/Girl.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Wallpapers/Girl.pic", + type="Wallpaper", + version=1.01, + }, + { + path="/MineOS/Pictures/Space.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Wallpapers/Space.pic", + type="Wallpaper", + version=1.0, + }, + { + path="/MineOS/Pictures/Block.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Wallpapers/Block.pic", + type="Wallpaper", + version=1.0, + }, + { + path="/MineOS/Pictures/Road.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Wallpapers/Road.pic", + type="Wallpaper", + version=1.0, + }, + { + path="/MineOS/Pictures/TyanSunset.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Wallpapers/TyanSunset.pic", + type="Wallpaper", + version=1.01, + }, + { + path="/MineOS/System/Localization/Russian.lang", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Localization/Russian.lang", + type="Script", + forceDownload=true, + version=1.39, + }, + { + path="/MineOS/System/Localization/English.lang", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Localization/English.lang", + type="Script", + forceDownload=true, + version=1.39, + }, + ----------------------------------------------------- Ассоциация говна -------------------------------------------------------------------------- + { + path="/MineOS/System/Extensions/Lua/ContextMenu.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Extensions/Lua/ContextMenu.lua", + type="Script", + forceDownload=true, + version=1.04, + }, + { + path="/MineOS/System/Extensions/Lua/Launcher.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Extensions/Lua/Launcher.lua", + type="Script", + forceDownload=true, + version=1.04, + }, + { + path="/MineOS/System/Extensions/Pic/ContextMenu.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Extensions/Pic/ContextMenu.lua", + type="Script", + forceDownload=true, + version=1.04, + }, + { + path="/MineOS/System/Extensions/Arc/Launcher.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Extensions/Arc/Launcher.lua", + type="Script", + forceDownload=true, + version=1.04, + }, + + ----------------------------------------------------- Системные иконки -------------------------------------------------------------------------- + { + path="/MineOS/System/Icons/Application.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/Application.pic", + type="Icon", + version=1.0, + }, + { + path="/MineOS/System/Icons/3DModel.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/3DModel.pic", + type="Icon", + version=1.01, + }, + { + path="/MineOS/System/Icons/Computer.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/Computer.pic", + type="Icon", + version=1.0, + }, + { + path="/MineOS/System/Icons/Robot.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/Robot.pic", + type="Icon", + version=1.0, + }, + { + path="/MineOS/System/Icons/Tablet.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/Tablet.pic", + type="Icon", + version=1.0, + }, + { + path="/MineOS/System/Icons/Pastebin.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/Pastebin.pic", + type="Icon", + version=1.0, + }, + { + path="/MineOS/System/Icons/HDD.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/HDD.pic", + type="Icon", + version=1.01, + }, + { + path="/MineOS/System/Icons/Floppy.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/Floppy.pic", + type="Icon", + version=1.01, + }, + { + path="/MineOS/System/Icons/Steve.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/Steve.pic", + type="Icon", + version=1.0, + }, + { + path="/MineOS/System/Icons/Folder.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/Folder.pic", + type="Icon", + version=1.02, + }, + { + path="/MineOS/System/Icons/FileNotExists.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/FileNotExists.pic", + type="Icon", + version=1.0, + }, + { + path="/MineOS/System/Icons/Script.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/Script.pic", + type="Icon", + version=1.0, + }, + { + path="/MineOS/System/Icons/Text.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/Text.pic", + type="Icon", + version=1.02, + }, + { + path="/MineOS/System/Icons/Config.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/Config.pic", + type="Icon", + version=1.01, + }, + { + path="/MineOS/System/Icons/Image.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/Image.pic", + type="Icon", + version=1.03, + }, + { + path="/MineOS/System/Icons/Lua.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/Lua.pic", + type="Icon", + version=1.02, + }, + { + path="/MineOS/System/Icons/SampleIcon.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/SampleIcon.pic", + type="Icon", + version=1.0, + }, + { + path="/MineOS/System/Icons/Archive.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/Archive.pic", + type="Icon", + version=1.02, + }, + { + path="/MineOS/System/Icons/Trash.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Icons/Trash.pic", + type="Icon", + version=1.01, + }, + + ----------------------------------------------------- Библиотеки -------------------------------------------------------------------------- + + { + path="/lib/MineOSCore.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/MineOSCore.lua", + type="Library", + preloadFile=true, + version=2.02, + }, + { + path="/lib/MineOSNetwork.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/MineOSNetwork.lua", + type="Library", + version=1.08, + }, + { + path="/lib/MineOSInterface.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/MineOSInterface.lua", + type="Library", + version=1.26, + }, + { + path="/lib/MineOSPaths.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/MineOSPaths.lua", + type="Library", + preloadFile=true, + version=1.01, + }, + { + path="/lib/advancedLua.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/advancedLua.lua", + type="Library", + preloadFile=true, + version=1.31, + }, + { + path="/lib/web.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/web.lua", + type="Library", + preloadFile=true, + version=1.09, + }, + { + path="/lib/event.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/event.lua", + type="Library", + version=1.10, + }, + { + path="/lib/ECSAPI.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/ECSAPI.lua", + type="Library", + version=1.15, + }, + { + path="/lib/color.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/color.lua", + type="Library", + preloadFile=true, + version=1.11, + }, + { + path="/lib/FormatModules/OCIF.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/FormatModules/OCIF.lua", + type="Library", + preloadFile=true, + version=1.03, + }, + { + path="/lib/FormatModules/OCAF.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/FormatModules/OCAF.lua", + type="Library", + preloadFile=true, + version=1.01, + }, + { + path="/lib/archive.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/archive.lua", + type="Library", + version=1.00, + }, + { + path="/lib/image.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/image.lua", + type="Library", + preloadFile=true, + version=1.30, + }, + { + path="/lib/serialization.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/serialization.lua", + type="Library", + version=1.07, + }, + { + path="/lib/GUI.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/GUI.lua", + type="Library", + preloadFile=true, + version=2.03, + }, + { + path="/lib/rayEngine.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/rayEngine.lua", + type="Library", + version=1.44, + }, + { + path="/lib/json.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/json.lua", + type="Library", + version=1.0, + }, + { + path="/lib/bigLetters.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/bigLetters.lua", + type="Library", + version=1.0, + }, + { + path="/lib/context.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/context.lua", + type="Library", + version=1.0, + }, + { + path="/lib/syntax.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/syntax.lua", + type="Library", + version=1.18, + }, + { + path="/lib/palette.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/palette.lua", + type="Library", + version=1.22, + }, + { + path="/lib/doubleBuffering.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/doubleBuffering.lua", + type="Library", + preloadFile=true, + version=1.39, + }, + { + path="/lib/xmlParser.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/xmlParser.lua", + type="Library", + version=1.0, + }, + { + path="/lib/SHA2.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/SHA2.lua", + type="Library", + version=1.01, + }, + { + path="/lib/vector.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/vector.lua", + type="Library", + version=1.10, + }, + { + path="/lib/OpenComputersGL/Main.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/OpenComputersGL/Main.lua", + type="Library", + version=1.11, + }, + { + path="/lib/OpenComputersGL/Materials.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/OpenComputersGL/Materials.lua", + type="Library", + version=1.11, + }, + { + path="/lib/OpenComputersGL/Renderer.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/OpenComputersGL/Renderer.lua", + type="Library", + version=1.11, + }, + { + path="/lib/MeowEngine/Main.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/MeowEngine/Main.lua", + type="Library", + version=1.11, + }, + + ----------------------------------------------------- Скрипты и дополнения к ним -------------------------------------------------------------------------- + + { + path="/bin/clear.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/clear.lua", + type="Script", + forceDownload=true, + version=1.01, + }, + { + path="/bin/scale.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/scale.lua", + type="Script", + forceDownload=true, + version=1.01, + }, + ----------------------------------------------------- Screensavers -------------------------------------------------------------------------- + { + path="/MineOS/System/Screensavers/Matrix.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Screensavers/Matrix.lua", + type="Script", + forceDownload=true, + version=1.02, + }, + { + path="/MineOS/System/Screensavers/Mandala.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Screensavers/Mandala.lua", + type="Script", + forceDownload=true, + version=1.00, + }, + { + path="/MineOS/System/Screensavers/Clock.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Screensavers/Clock.lua", + type="Script", + forceDownload=true, + version=1.00, + }, + { + path="/MineOS/System/Screensavers/Lines.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Screensavers/Lines.lua", + type="Script", + forceDownload=true, + version=1.01, + }, + { + path="/MineOS/System/Screensavers/XCOM.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Screensavers/XCOM.lua", + type="Script", + forceDownload=true, + version=1.00, + }, + { + path="/MineOS/System/Screensavers/NyanCat.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Screensavers/NyanCat.lua", + type="Script", + forceDownload=true, + version=1.00, + }, + ----------------------------------------------------- Приложения -------------------------------------------------------------------------- + { + path="/MineOS/Applications/MineCode IDE", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/MineCodeIDE/Main.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/MineCodeIDE/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/MineCodeIDE/Icon.pic", + forceDownload=true, + version=1.86, + resources={ + { + path="/Localization/Russian.lang", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/MineCodeIDE/Localization/Russian.lang" + }, + { + path="/Localization/English.lang", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/MineCodeIDE/Localization/English.lang" + }, + } + }, + { + path="/MineOS/Applications/Camera", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Camera/Main.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Camera/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Camera/Icon.pic", + createShortcut=true, + version=1.06, + }, + { + path="/MineOS/Applications/3DTest", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/3DTest/3DTest.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/3DTest/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/3DTest/Icon.pic", + createShortcut=true, + forceDownload=true, + version=1.23, + }, + { + path="/MineOS/Applications/HEX", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/HEX/Main.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/HEX/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/HEX/Icon.pic", + createShortcut=true, + version=1.08, + }, + { + path="/MineOS/Applications/Spinner", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Spinner/Main.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Spinner/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Spinner/Icon.pic", + createShortcut=true, + version=1.01, + resources={ + { + path="/1.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Spinner/1.pic" + }, + { + path="/2.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Spinner/2.pic" + }, + { + path="/3.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Spinner/3.pic" + }, + { + path="/4.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Spinner/4.pic" + }, + { + path="/5.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Spinner/5.pic" + }, + { + path="/6.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Spinner/6.pic" + }, + { + path="/7.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Spinner/7.pic" + }, + { + path="/8.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Spinner/8.pic" + }, + } + }, + { + path="/MineOS/Applications/Translate", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Translate/Main.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Translate/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Translate/Icon.pic", + createShortcut=true, + version=1.06, + resources={ + { + path="/Logo.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Translate/Logo.pic" + }, + } + }, + { + path="/MineOS/Applications/Braille", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Braille/Main.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Braille/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Braille/Icon.pic", + createShortcut=true, + version=1.07, + }, + { + path="/MineOS/Applications/GeoScan2", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/GeoScan2/Main.lua", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/GeoScan2/Icon.pic", + createShortcut=true, + version=1.11, + resources={ + { + path="/Earth.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/GeoScan2/Earth.pic", + } + }, + }, + { + path="/MineOS/Applications/VK", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/VK/Main.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/VK/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/VK/Icon.pic", + createShortcut=true, + version=1.39, + resources={ + { + path="/VKLogo.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/VK/VKLogo.pic", + }, + }, + }, + { + path="/MineOS/Applications/Finder", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Finder/Main.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Finder/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Finder/Icon.pic", + forceDownload=true, + version=1.37, + }, + { + path="/MineOS/Applications/Weather", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Weather/Weather.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Weather/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Weather/Icon.pic", + createShortcut=true, + version=1.18, + resources={ + { + path="/Cloudy.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Weather/Cloudy.pic", + }, + { + path="/Cloudy.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Weather/Cloudy.pic", + }, + { + path="/Rainy.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Weather/Rainy.pic", + }, + { + path="/Snowy.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Weather/Snowy.pic", + }, + { + path="/Stormy.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Weather/Stormy.pic", + }, + { + path="/Sunny.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Weather/Sunny.pic", + }, + { + path="/SunnyWithClouds.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Weather/SunnyWithClouds.pic", + }, + }, + }, + { + path="/MineOS/Applications/3DPrint", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/3DPrint/3DPrint.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/3DPrint/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/3DPrint/Icon.pic", + createShortcut=true, + version=1.14, + }, + { + path="/MineOS/Applications/FlappyBird", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/FlappyBird/FlappyBird.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/FlappyBird/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/FlappyBird/Icon.pic", + createShortcut=true, + version=1.17, + resources={ + { + path="/Flappy.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/FlappyBird/Flappy.pic", + }, + }, + }, + { + path="/MineOS/Applications/RayWalk", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Main.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Icon.pic", + createShortcut=true, + version=1.70, + resources={ + { + path="/Localization/Russian.lang", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Localization/Russian.lang" + }, + { + path="/Localization/English.lang", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Localization/English.lang" + }, +------------ + { + path="/RayEngine.cfg", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/RayEngine.cfg", + }, +------------ + { + path="/Weapons/Weapons.cfg", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Weapons/Weapons.cfg", + }, +------------ + { + path="/Weapons/CrosshairTextures/Angled.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Weapons/CrosshairTextures/Angled.pic", + }, + { + path="/Weapons/CrosshairTextures/Default.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Weapons/CrosshairTextures/Default.pic", + }, + { + path="/Weapons/CrosshairTextures/Half.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Weapons/CrosshairTextures/Half.pic", + }, + { + path="/Weapons/CrosshairTextures/Dotted.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Weapons/CrosshairTextures/Dotted.pic", + }, +------------ + { + path="/Weapons/FireTextures/PowderFire.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Weapons/FireTextures/PowderFire.pic", + }, + { + path="/Weapons/FireTextures/Plasma.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Weapons/FireTextures/Plasma.pic", + }, +------------ + { + path="/Weapons/WeaponTextures/Pistol.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Weapons/WeaponTextures/Pistol.pic", + }, + { + path="/Weapons/WeaponTextures/Sniper.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Weapons/WeaponTextures/Sniper.pic", + }, + { + path="/Weapons/WeaponTextures/Rifle.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Weapons/WeaponTextures/Rifle.pic", + }, + { + path="/Weapons/WeaponTextures/Plasmer.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Weapons/WeaponTextures/Plasmer.pic", + }, +------------ + { + path="/Worlds/ExampleWorld/Map.cfg", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Worlds/ExampleWorld/Map.cfg", + }, + { + path="/Worlds/ExampleWorld/Player.cfg", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Worlds/ExampleWorld/Player.cfg", + }, + { + path="/Worlds/ExampleWorld/World.cfg", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Worlds/ExampleWorld/World.cfg", + }, + { + path="/Worlds/ExampleWorld/Blocks.cfg", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Worlds/ExampleWorld/Blocks.cfg", + }, +------------ + { + path="/Worlds/SundownBeams/Map.cfg", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Worlds/SundownBeams/Map.cfg", + }, + { + path="/Worlds/SundownBeams/Player.cfg", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Worlds/SundownBeams/Player.cfg", + }, + { + path="/Worlds/SundownBeams/World.cfg", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Worlds/SundownBeams/World.cfg", + }, + { + path="/Worlds/SundownBeams/Blocks.cfg", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RayWalk/Worlds/SundownBeams/Blocks.cfg", + }, + }, + }, + { + path="/MineOS/Applications/GuessWord", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/GuessWord/GuessWord.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/GuessWord/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/GuessWord/Icon.pic", + createShortcut=true, + version=1.0, + }, + { + path="/MineOS/Applications/Calendar", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Calendar/Main.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Calendar/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Calendar/Icon.pic", + createShortcut=true, + version=1.01, + }, + { + path="/MineOS/Applications/PrintImage", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/PrintImage/Main.lua", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/PrintImage/Icon.pic", + createShortcut=true, + version=1.17, + }, + { + path="/MineOS/Applications/Palette", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Palette/Palette.lua", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Palette/Icon.pic", + createShortcut=true, + version=1.06, + }, + { + path="/MineOS/Applications/Stargate", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Stargate/Main.lua", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Stargate/Icon.pic", + createShortcut=true, + version=1.14, + resources={ + { + path="/Ch1.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Stargate/Ch1.pic", + }, + { + path="/Ch2.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Stargate/Ch2.pic", + }, + { + path="/OnOn.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Stargate/OnOn.pic", + }, + { + path="/OnOff.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Stargate/OnOff.pic", + }, + { + path="/OffOn.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Stargate/OffOn.pic", + }, + { + path="/OffOff.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Stargate/OffOff.pic", + }, + }, + }, + { + path="/MineOS/Applications/RunningString", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RunningString/RunningString.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RunningString/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/RunningString/Icon.pic", + createShortcut=true, + version=1.01, + }, + { + path="/MineOS/Applications/Graph2", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Graph2/Main.lua", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Graph2/Icon.pic", + createShortcut=true, + version=1.04, + }, + { + path="/MineOS/Applications/Battleship", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Battleship/Battleship.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Battleship/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Battleship/Icon.pic", + createShortcut=true, + version=1.0, + }, + { + path="/MineOS/Applications/Radio", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Radio/Radio.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Radio/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Radio/Icon.pic", + createShortcut=true, + version=1.04, + }, + { + path="/MineOS/Applications/FuckTheRain", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/FuckTheRain/FuckTheRain.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/FuckTheRain/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/FuckTheRain/Icon.pic", + createShortcut=true, + version=1.0, + }, + { + path="/MineOS/Applications/ForceAdmin", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/ForceAdmin/ForceAdmin.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/ForceAdmin/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/ForceAdmin/Icon.pic", + createShortcut=true, + version=1.0, + }, + { + path="/MineOS/Applications/QuantumCube", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/QuantumCube/QuantumCube.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/QuantumCube/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/QuantumCube/Icon.pic", + createShortcut=true, + version=1.0, + }, + { + path="/MineOS/Applications/Control", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Control/Main.lua", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Control/Icon.pic", + forceDownload=true, + version=5.11, + resources={ + { + path="/Localization/Russian.lang", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Control/Localization/Russian.lang" + }, + { + path="/Localization/English.lang", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Control/Localization/English.lang" + }, + { + path="/Modules/1.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Control/Modules/1.lua" + }, + { + path="/Modules/2.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Control/Modules/2.lua" + }, + { + path="/Modules/3.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Control/Modules/3.lua" + }, + { + path="/Modules/4.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Control/Modules/4.lua" + }, + } + }, + { + path="/MineOS/Applications/Photoshop", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Photoshop/Photoshop.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Photoshop/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Photoshop/Icon.pic", + forceDownload=true, + version=1.10, + resources={ + { + path="/Localization/Russian.lang", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Photoshop/Localization/Russian.lang" + }, + { + path="/Localization/English.lang", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Photoshop/Localization/English.lang" + }, + } + }, + { + path="/MineOS/Applications/Shooting", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Shooting/Shooting.lua", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Shooting/Icon.pic", + createShortcut=true, + version=1.02, + }, + { + path="/MineOS/Applications/HoloClock", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/HoloClock/HoloClock.lua", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/HoloClock/Icon.pic", + createShortcut=true, + version=1.07, + }, + { + path="/MineOS/Applications/AppMarket", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/AppMarket/Main.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/AppMarket/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/AppMarket/Icon.pic", + forceDownload=true, + version=1.76, + resources={ + { + path="/Update.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/AppMarket/Update.pic", + }, + { + path="/Localization/Russian.lang", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/AppMarket/Localization/Russian.lang", + }, + { + path="/Localization/English.lang", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/AppMarket/Localization/English.lang", + }, + }, + }, + { + path="/MineOS/Applications/CodeDoor", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/CodeDoor/CodeDoor.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/CodeDoor/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/CodeDoor/Icon.pic", + createShortcut=true, + version=1.0, + }, + { + path="/MineOS/Applications/ChristmasTree", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/ChristmasTree/ChristmasTree.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/ChristmasTree/About/", + type="Application", + createShortcut=true, + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/ChristmasTree/Icon.pic", + version=1.0, + }, + -- Приложение InfoPanel + { + path="/MineOS/Applications/InfoPanel", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/InfoPanel/InfoPanel.lua", + type="Application", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/InfoPanel/About/", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/InfoPanel/Icon.pic", + createShortcut=true, + version=1.01, + resources = { + { + path="/Pages/Rules.txt", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/InfoPanel/Rules.txt", + }, + { + path="/Pages/Main.txt", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/InfoPanel/Main.txt", + }, + { + path="/Pages/SSPI.txt", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/InfoPanel/SSPI.txt", + }, + { + path="/Pages/Claims.txt", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/InfoPanel/Claims.txt", + }, + } + }, + { + path="/MineOS/Applications/TurretControl", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/TurretControl/TurretControl.lua", + type="Application", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/TurretControl/About/", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/TurretControl/Icon.pic", + createShortcut=true, + version=1.05, + resources={ + { + path="/Turret.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/TurretControl/Turret.pic", + }, + }, + }, + { + path="/MineOS/Applications/HoloEdit", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/HoloEdit/HoloEdit.lua", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/HoloEdit/Icon.pic", + createShortcut=true, + version=1.02, + resources={ + { + path="/Localization/Russian.lang", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/HoloEdit/Localization/Russian.lang", + }, + { + path="/Localization/English.lang", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/HoloEdit/Localization/English.lang", + }, + }, + }, + { + path="/MineOS/Applications/BufferDemo", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/BufferDemo/BufferDemo.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/BufferDemo/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/BufferDemo/Icon.pic", + createShortcut=true, + version=1.03, + resources={ + { + path="/Wallpaper.pic", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/BufferDemo/Wallpaper.pic", + }, + }, + }, + { + path="/MineOS/Applications/OpenSecurity", + url="https://raw.githubusercontent.com/FelixBanan/OpenSecurity/master/MineOS/Applications/OpenSecurity.app/Main.lua", + type="Application", + icon="https://raw.githubusercontent.com/FelixBanan/OpenSecurity/master/MineOS/Applications/OpenSecurity.app/Resources/Icon.pic", + createShortcut=true, + version=1.01, + resources={ + { + path="/Modules/1.lua", + url="https://raw.githubusercontent.com/FelixBanan/OpenSecurity/master/MineOS/Applications/OpenSecurity.app/Resources/Modules/1.lua" + }, + { + path="/Modules/2.lua", + url="https://raw.githubusercontent.com/FelixBanan/OpenSecurity/master/MineOS/Applications/OpenSecurity.app/Resources/Modules/2.lua" + }, + { + path="/Modules/3.lua", + url="https://raw.githubusercontent.com/FelixBanan/OpenSecurity/master/MineOS/Applications/OpenSecurity.app/Resources/Modules/3.lua" + }, + } + }, +} diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/AutorunManager/Filelist.txt b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/AutorunManager/Filelist.txt new file mode 100644 index 00000000..e3176e9f --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/AutorunManager/Filelist.txt @@ -0,0 +1 @@ +{[1]={["path"]="OS.lua",["enabled"]=true,["size"]=44},[2]={["path"]="/bin/resolution.lua",["enabled"]=true,["size"]=1}} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Extensions/Arc/Launcher.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Extensions/Arc/Launcher.lua new file mode 100755 index 00000000..e4a38b23 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Extensions/Arc/Launcher.lua @@ -0,0 +1,9 @@ + +local args = {...} + +local success, reason = require("archive").unpack(args[1], require("filesystem").path(args[1])) +if not success then + require("GUI").error(reason) +end + +require("computer").pushSignal("MineOSCore", "updateFileList") \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Extensions/Lua/ContextMenu.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Extensions/Lua/ContextMenu.lua new file mode 100755 index 00000000..210c5854 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Extensions/Lua/ContextMenu.lua @@ -0,0 +1,29 @@ + +local args = {...} +local component = require("component") +local computer = require("computer") +local fs = require("filesystem") +local MineOSPaths = require("MineOSPaths") +local MineOSCore = require("MineOSCore") +local MineOSInterface = require("MineOSInterface") + +local icon, menu = args[1], args[2] +menu:addItem(MineOSCore.localization.edit).onTouch = function() + MineOSInterface.safeLaunch(MineOSPaths.editor, icon.path) +end + +menu:addSeparator() + +menu:addItem(MineOSCore.localization.launchWithArguments).onTouch = function() + MineOSInterface.launchWithArguments(MineOSInterface.mainContainer, icon.path) +end + +menu:addItem(MineOSCore.localization.flashEEPROM, not component.isAvailable("eeprom") or fs.size(icon.path) > 4096).onTouch = function() + computer.beep(1500, 0.2) + local file = io.open(icon.path, "r") + component.eeprom.set(file:read("*a")) + file:close() + for i = 1, 2 do + computer.beep(2000, 0.2) + end +end \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Extensions/Lua/Launcher.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Extensions/Lua/Launcher.lua new file mode 100755 index 00000000..dafb76ca --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Extensions/Lua/Launcher.lua @@ -0,0 +1,8 @@ + +local args = {...} +local MineOSInterface = require("MineOSInterface") + +MineOSInterface.clearTerminal() +if MineOSInterface.safeLaunch(args[1]) then + MineOSInterface.waitForPressingAnyKey() +end diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Extensions/Pic/ContextMenu.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Extensions/Pic/ContextMenu.lua new file mode 100755 index 00000000..d2abe4a8 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Extensions/Pic/ContextMenu.lua @@ -0,0 +1,13 @@ + +local args = {...} +local computer = require("computer") +local MineOSCore = require("MineOSCore") +local MineOSInterface = require("MineOSInterface") + +local icon, menu = args[1], args[2] +menu:addItem(MineOSCore.localization.setAsWallpaper).onTouch = function() + MineOSCore.properties.wallpaperEnabled = true + MineOSCore.properties.wallpaper = icon.path + MineOSCore.saveProperties() + computer.pushSignal("MineOSCore", "updateWallpaper") +end diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/3DModel.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/3DModel.pic new file mode 100755 index 00000000..21abbe72 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/3DModel.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Application.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Application.pic new file mode 100755 index 00000000..9d7cd339 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Application.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Archive.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Archive.pic new file mode 100755 index 00000000..969d6cd0 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Archive.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Computer.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Computer.pic new file mode 100755 index 00000000..a7c0cd22 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Computer.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Config.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Config.pic new file mode 100755 index 00000000..7dcecefd Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Config.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/FileNotExists.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/FileNotExists.pic new file mode 100755 index 00000000..beb2616d Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/FileNotExists.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Floppy.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Floppy.pic new file mode 100644 index 00000000..3bfb5153 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Floppy.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Folder.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Folder.pic new file mode 100755 index 00000000..b85aab8c Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Folder.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/HDD.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/HDD.pic new file mode 100644 index 00000000..2d9a6c21 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/HDD.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Image.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Image.pic new file mode 100755 index 00000000..269a6401 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Image.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Lua.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Lua.pic new file mode 100755 index 00000000..bd03e501 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Lua.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Pastebin.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Pastebin.pic new file mode 100755 index 00000000..038d95ba Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Pastebin.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Robot.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Robot.pic new file mode 100755 index 00000000..107fdce4 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Robot.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/SampleIcon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/SampleIcon.pic new file mode 100755 index 00000000..06a0bcaa Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/SampleIcon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Script.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Script.pic new file mode 100755 index 00000000..8adc3360 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Script.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Steve.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Steve.pic new file mode 100755 index 00000000..5d8bcc4d Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Steve.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Tablet.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Tablet.pic new file mode 100755 index 00000000..55c834b2 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Tablet.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Text.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Text.pic new file mode 100755 index 00000000..3ade1c48 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Text.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Trash.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Trash.pic new file mode 100755 index 00000000..c36191ae Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Icons/Trash.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Installer.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Installer.lua new file mode 100755 index 00000000..5c80a36b --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Installer.lua @@ -0,0 +1,324 @@ + +-- package.loaded.web = nil +-- package.loaded.GUI = nil + +local fs = require("filesystem") +local component = require("component") +local computer = require("computer") +local unicode = require("unicode") +local shell = require("shell") +local serialization = require("serialization") +local gpu = component.gpu +local screen = component.screen + +------------------------------------------------------------------------------------------------------------------------------------ + +local reasons = {} + +if not _G._OSVERSION or tonumber(_G._OSVERSION:sub(8, 10)) < 1.5 then + table.insert(reasons, "Old version of OpenComputers mod detected: MineOS requires OpenComputers 1.5 or newer to work properly.") +end + +-- if computer.getArchitecture and computer.getArchitecture() ~= "Lua 5.2" then +-- table.insert(reasons, "Unsupported CPU architecture detected: please take CPU in your hands, switch it to Lua 5.2 arhitecture and try again.") +-- end + +if component.isAvailable("tablet") then + table.insert(reasons, "Tablet PC detected: MineOS can't be installed on tablets.") +end + +if screen.setPrecise and screen.setPrecise(false) == nil then + table.insert(reasons, "Low-tier screen detected: MineOS requires Tier3 screen to work properly.") +else + if gpu.maxResolution() < 160 then + table.insert(reasons, "Low-tier GPU detected: MineOS requires Tier3 GPU to work properly.") + end +end + +if computer.totalMemory() < 2097152 then + table.insert(reasons, "Not enough RAM: MineOS requires at least 2MB (2x Tier3 RAM modules) to work properly.") +end + +if #reasons > 0 then + print(" ") + for i = 1, #reasons do + print(reasons[i]) + print(" ") + end + + return +end + +------------------------------------------------------------------------------------------------------------------------------------ + +local paths = { + applicationList = "/MineOS/System/OS/Applications.cfg", + OSSettings = "/MineOS/System/OS/OSSettings.cfg", +} + +local urls = { + applicationList = "https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications.cfg", + installer = "https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Installer/", + EFI = "https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/EFI.lua", +} + +------------------------------------------------------------------------------------------------------------------------------------ + +local function unserializeFile(path) + local file = io.open(path, "r") + local data = serialization.unserialize(file:read("*a")) + file:close() + return data +end + +local function wget(url, path) + fs.makeDirectory(fs.path(path)) + shell.execute("wget " ..url .. " " .. path .. " -fq") +end + +print("Downloading MineOS file list...") +wget(urls.applicationList, paths.applicationList) +applicationList = unserializeFile(paths.applicationList) + +print(" ") +for i = 1, #applicationList do + if applicationList[i].preloadFile then + print("Downloading framework \"" .. fs.name(applicationList[i].path) .. "\"") + wget(applicationList[i].url, applicationList[i].path) + end +end + +------------------------------------------------------------------------------------------------------------------------------------ + +print(" ") +print("Loading installer images...") +local image = require("image") + +local images = { + languages = [[3C100000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0068FF▄003CFF▄009EFF▄6D9900▄6D9E00▄6D9900▄6C6D00▄673700▄3C0000 0067FF▄0067FF▄0055FF▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0055FFВ0055FFи0055FFб0055FFе0055FFр0055FFі0055FFт0055FFь0000FF 0055FFм0055FFо0055FFв0055FFу0000FF 0000FF 0000FF 0000FF 003DFF▄003DFF▄3D6D00▄689E00▄9EAC00▄9E6800▄993700▄379E00▄6D9E00▄6D3C00▄3C0000 6D3700▄67AA00▄808100▄810000 678000▄547E00▄360000 0054FF▄002AFF▄0000FF 0000FF 0000FF 007EFFC007EFFh007EFFo007EFFi007EFFs007EFFi007EFFs007EFFs007EFFe007EFFz0000FF 007EFFv007EFFo007EFFt007EFFr007EFFe0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 003CFF▄3D9E00▄6D0000 6D9E00▄0C6D00▄6D3D00▄D53C00▄D59E00▄D59E00▄D6D700▄6DD600▄D56D00▄817E00▄376600▄6C0000 6CAA00▄800000 AA0000 7E6600▄7E9700▄7E6600▄547E00▄2A5300▄002AFF▄0000FF 0000FF 0000FF 0000FF 0000FF 007EFFl007EFFa007EFFn007EFFg007EFFu007EFFe0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0029FFC0029FFa0029FFm0029FFb0029FFi0029FFa0029FFr0000FF 0029FFl0029FFa0000FF 0000FF 0000FF 0000FF 0000FF 3C0C00▄6C3700▄0C9E00▄6D6800▄680C00▄379E00▄3D3700▄0CCE00▄CEFE00▄3D3700▄D50C00▄9C3C00▄3DCD00▄6B6C00▄3B9D00▄6CCE00▄9D0000 CD9C00▄C89D00▄979800▄970000 669200▄660000 7E0000 535400▄295300▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0029FFl0029FFe0029FFn0029FFg0029FFu0029FFa0000FF 0000FF 0000FF 0000FF 0000FF 0D0C00▄0C3700▄3D0C00▄0C3C00▄3D0C00▄376D00▄379900▄3D0C00▄0C3700▄3CCD00▄F89D00▄9D6C00▄9D6B00▄9CC800▄CD9C00▄ABCD00▄CD6C00▄C70C00▄CECD00▄979C00▄370C00▄98C800▄980000 929700▄668000▄7F0000 545500▄2A5300▄0000FF 0000FF 0000FF 0000FF 0053FFW0053FFy0053FFb0053FFi0053FFe0053FFr0053FFz0000FF 0053FFs0053FFw0053FFó0053FFj0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 380C00▄0C3700▄0C3700▄370000 3C0C00▄6D0C00▄6DD700▄0C3700▄6BCD00▄3DCD00▄CD3D00▄9D3800▄6B3700▄0CCD00▄6B0C00▄CD9C00▄CD0C00▄0CC700▄07C800▄07C800▄9D0000 C79800▄079700▄979200▄7E9200▄7F7E00▄666100▄7E6600▄365500▄292A00▄0000FF 0000FF 0053FFj0053FFę0053FFz0053FFy0053FFk0000FF 0053FF(0053FFk0053FFu0053FFr0053FFw0053FFa0053FF)0055FFВ0055FFы0055FFб0055FFе0055FFр0055FFи0055FFт0055FFе0000FF 0055FFя0055FFз0055FFы0055FFк0000FF 003DFF▄6D3700▄3D3700▄0C0000 0C0000 370700▄0C0700▄370000 376D00▄F8D700▄3DD600▄3DCD00▄3DFE00▄3DF800▄CD3700▄0C0000 9C0C00▄370700▄970700▄C80700▄C79700▄C8C300▄C80000 986700▄7E9700▄936600▄939800▄7E6100▄7E5500▄540000 2A0000 0028FF▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 373D00▄0C0000 0C6800▄0C3700▄0C0000 370C00▄6D0C00▄0CC800▄C8D700▄F3F800▄F90000 F9F300▄F90000 F80000 F9C800▄0CF900▄F9CE00▄F9CE00▄CE0000 C80000 C80700▄C39200▄C30000 C8C300▄06C800▄069800▄069800▄060000 360600▄545300▄2A0000 280000 0000FF 0000FF 0055FFا0055FFخ0055FFت0055FFر0000FF 0055FFل0055FFغ0055FFت0055FFك0000FF 0000FF 0000FF 0000FF 0080FFS0080FFc0080FFe0080FFg0080FFl0080FFi0000FF 0080FFl0080FFa0000FF 0000FF 0000FF 0000FF 0C0000 0C0000 3D0C00▄370000 370C00▄0C0700▄FEF900▄F90000 FEF900▄F8F300▄F90000 C8F900▄C8F900▄C8F900▄F9F300▄C8CE00▄D6C800▄C3C800▄CECD00▄CDC800▄C3C800▄079200▄C30700▄C89800▄C89800▄980000 980600▄060000 060000 362A00▄2A2800▄282900▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0080FFl0080FFi0080FFn0080FFg0080FFu0080FFa0000FF 0000FF 0000FF 0000FF 003CFF▀370000 373C00▄370700▄0C0000 070C00▄F8CD00▄F9CD00▄D7CD00▄FECD00▄F8C800▄F9F800▄C80000 D60000 F9CD00▄CE0000 C8CD00▄C3C800▄C80000 C80000 C8C700▄929D00▄079D00▄979300▄983700▄069200▄370600▄060000 060000 2A2900▄2A2800▄0028FF▀0000FF 0000FF 002AFFא002AFFת0000FF 002AFFה002AFFש002AFFפ002AFFה0000FF 002AFFש002AFFל002AFFך0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0C3C00▄370C00▄370C00▄370000 0C9E00▄9D3C00▄9DCE00▄D6CE00▄D7CD00▄D70000 F9CE00▄CDCE00▄C8CD00▄37CD00▄D6CD00▄C8CD00▄D5C700▄CE9D00▄C89C00▄AC9D00▄9DAA00▄AA9D00▄AA9700▄AA8100▄540600▄060000 063600▄062900▄2A2800▄280000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 002AFFב002AFFח002AFFר0000FF 0000FF 0000FF 0000FF 0000FF 0054FFV0054FFa0054FFl0054FFi0054FFt0054FFs0054FFe0000FF 0054FFk0054FFi0054FFe0054FFl0054FFi0000FF 0000FF 0000FF 376700▄0C3700▄070C00▄073700▄070000 9E0C00▄CE0700▄AB6800▄D66D00▄D56D00▄CE0C00▄D56C00▄C83B00▄9D6B00▄9DD500▄6C8100▄AAAC00▄97AB00▄9D9700▄970000 AA9700▄986B00▄360600▄060000 060000 060000 292800▄280000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0C0000 070000 070C00▄070000 070000 070000 6D6700▄070600▄370000 073700▄9D0600▄6C9D00▄816B00▄6C6600▄666B00▄816B00▄AA6600▄6C6B00▄976600▄986600▄063100▄060000 060000 062800▄282900▄280000 0000FF 0000FF 0000FF 007EFFW007EFFä007EFFh007EFFl007EFFe007EFFn0000FF 007EFFs007EFFi007EFFe0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0007FF▀370600▄370600▄370000 370600▄670600▄060000 060000 070600▄063700▄070C00▄6B0000 6B6600▄6B0000 6B6600▄363B00▄660000 660000 663600▄060000 062A00▄292800▄280000 0028FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 007EFFi007EFFh007EFFr007EFFe0000FF 007EFFs007EFFp007EFFr007EFFa007EFFc007EFFh007EFFe0000FF 0000FF 0000FFC0000FFh0000FFo0000FFo0000FFs0000FFe0000FF 0000FFl0000FFa0000FFn0000FFg0000FFu0000FFa0000FFg0000FFe0000FF 0000FF 0000FF 0006FF▀0037FF▀370600▄063700▄060000 060000 060000 060000 543700▄927E00▄660000 666100▄666100▄665500▄543600▄062900▄062900▄2A2800▄002AFF▀0029FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0036FF▀0006FF▀0031FF▀062900▄312900▄312800▄532800▄532800▄532800▄002AFF▀0029FF▀0028FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF ]], + OS = [[5A14AA0000 AA2900MAA2900iAA2900nAA2900eAA2900OAA2900SAA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AAAB00▄AB0000 AB0000 AB0000 ABAA00▄AA0000 ABAA00▄AB0000 ABAA00▄AB0000 AB0000 AB0000 ACAB00▄AC0000 ABAC00▄AB0000 AB0000 AB0000 AB0000 AB0000 AB0000 AB0000 AB0000 AB0000 AB0000 AB0000 ABAA00▄AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 ABAA00▄AAAB00▄AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 AA0000 280000 290000 290000 280000 280000 290000 280000 290000 290000 282900▄290000 290000 290000 292A00▄290000 290000 290000 290000 2A5300▄2A5300▄2A0000 545500▄7E0000 7E5400▄2A0000 536100▄2A5300▄290000 532900▄2A5300▄555400▄530000 555300▄7E7F00▄7F7E00▄819800▄7F8100▄7E8000▄535500▄530000 535400▄2A5300▄545300▄540000 540000 545300▄545300▄2A5300▄2A0000 2A0000 292A00▄290000 292A00▄290000 290000 290000 292800▄290000 282900▄280000 280000 290000 292800▄280000 280000 2A2900▄530000 2A0000 2A0000 290000 290000 290000 290000 290000 290000 280000 280000 280000 280000 280000 280000 280000 280000 280000 280000 280000 280000 280000 280000 280000 280000 290000 280000 534300.FF0000 FF1800▄FF1800▄FF0000 290000 290000 290000 290000 290000 29A700▀290000 290000 292A00▄535400▄532A00▄002200▀000000 00E300▄000000 002200▀669200▄669200▄920000 292900F29E400#29E400E290000 532A00▄545300▄552A00▄7E7F00▄7E5600▐7E5500▃7F5500▃A72A00▀7F8000▄547E00▄535400▄540000 ABAA00▄AB5500▄ABAA00▄AB5500▄530000 530000 292A00▄2A2900▄AB5500▗36D400▞553600▙AB5500▖290000 282900▄290000 280000 292800▄290000 282900▄280000 280000 292800▄280000 530000 2AFB00D2AFB00P29FB00n530000 290000 290000 290000 AC0000 A45400▄A45400▄A45400▄800000 290000 290000 290000 280000 281A00▟1AF200▗280000 280000 292800▄290000 280000 280000 280000 282900▄53FF00.FF0000 FF1800▄FF1800▄FF0000<290000 290000 2A0000 295300▀295300▀295300▀295300▀FF0000<540000 532A00▄540000 220000 002200▄000000 002200▄FF0000<920000 920000 929300▄922900▀290000 290000 7E2900▀530000 7E5400▄530000 535400▄555300▄802A00▄542A00▄7F2A00▄555400▄987F00▄7E8000▄7E5500▄7F2A00▄2A0000 7F2A00▄7F2A00▄2A0000 532A00▄530000 2A5300▄800000 805500▀800000 800000 290000 290000 290000 29D600▝D68100▄D68100▄D68100▄FF0000<290000 280000 292800▄530000 534E00▀530000 533B00▀FF0000<2A0000 290000 290000 D7AC00▀D70000 D70000 D70000 FF0000<290000 290000 290000 290000 282900▄300000 290000 FF0000<290000 290000 290000 280000 280000 290000 28FF00C28FF00a29FF00t29FF00l29FF00k290000 2A2900▄2A0000 2AFF00r29FF00p53FF00.53FF00l55FF00k2A2900▄530000 7FFF00u7FFF00a54FF00t61FF00…92FF00.92FF00l92FF00k980000 98C300▄98FF00E98FF00XC3FF00lC3FF00k980000 980000 617F00▄53FF00u55FF00r54FF00t55FF00…55FF00.AAFF00n98AA00▄7E9800▄54FF00m55FF00r7EFF00H54FF00…55FF00.54FF00n2A0000 290000 2AFF00C2AFF00m29FF00r2AFF00.2AFF00l29FF00k290000 29FF00B29FF00t28FF00t29FF00e29FF00p29FF00l29FF00n290000 28FF00328FF00P29FF00i29FF00n29FF00.29FF00n290000 290000 29FF00R29FF00y29FF00a29FF00k29FF00.29FF00n290000 290000 29FF00C2AFF00r29FF00s29FF00…29FF00.29FF00l29FF00k290000 290000 280000 290000 290000 FF0000 FF0000 290000 FF0000 FF0000 290000 2A0000 2A5300▄2AD500▁2AD500▆D50000 D50000 AB0000 290000 550000 7E0000 78FF00M78FF00i2AFF00R2AFF00l2AFF00e989300▄980000 C30000 C30000 C30000 C30000 C30000 C3C800▄C3C800▄C30000 980000 ADFF00uADFF00eAD0000 AD0000 7E0000 7F0000 800000 AA0000 2A0000 FF0000 FF0000 FF2A00▀535400▄545300▄535500▄2A0000 290000 810000 810000 810000 292A00▄290000 290000 290000 293C00▄3C0C00▄290600▄290000 290000 290000 290000 730000 B10000 FB0000 000000 290000 290000 290000 290000 FFD600▄A49E00▄734200▄484200▄D8EC00▄290000 290000 290000 00D600▀00D600▀00D600▀00D600▀00D600▀290000 290000 290000 280000 290000 290000 FF2900▀290000 290000 290000 FF2900▀290000 530000 530000 D70000 D70000 D70000 D70000 29AB00▛290000 7E0000 615400▄FF2A00IFF2A00f2A0000 2A0000 2A0000 989200▄C30000 C30000 C3A400\C8C300▄C80000 C8A400/AB0000 AB0000 C8AB00▄C80000 FF0000 FF0000 FF2A006FFAD0077F7E00▄7F8000▄547F00▄7F9800▄F60000 EE2A00▀EE2A00▀EE2A00▀545300▄532A00▄2A0000 545300▄FF0000 FF0000 FF0000 AC0000 2A0000 2A0000 290000 0C3C00▄0C0000 370700▄066600▄280000 290000 290000 290000 730000 B10000 FB0000 000000 FF0000 290000 290000 290000 7F5500▄675400▄3C3600▄0C0B00▄226900▄290000 290000 290000 000000 00F200с00F200р00F200к00F200а290000 292A00▄2A2900▄280000 290000 290000 FF0000 FF0000 290000 FF0000 FF0000<290000 530000 530000 D70000 D70000 D70000 D70000 FF0000<290000 7E5500▄540000 FF0000 FF0000 2A0000 2A0000 FF0000<920000 980000 C30000 482A00▄482A00▄FF2A00▄482A00▄AB0000 AB0000 AB0000 C80000 FF0000 FF0000 FF0000 FF0000 552A00▄807E00▄807F00▄550000 EC2A00▀EE2A00▀EE2A00▀EE2A00▀2A0000 530000 532A00▄292A00▄FF0000 FF0000 FF0000 540000 535400▄2A0000 2A0000 2A0000 2A3C00▀3C6700▄362A00▄FF0000<2A2900▄290000 290000 290000 FF0000 FF0000 FF0000 FF0000<290000 290000 290000 532900▄532900▄062800▄062800▄FF0000<290000 290000 290000 00D600▄00D600▄00D600▄00D600▄FF0000<290000 2A0000 292A00▄280000 290000 29FF00M29FF00n29FF00S2AFF00w2AFF00r2AFF00l29FF00k540000 530000 29FF00D54FF00e55FF00t53FF00.55FF00n2A0000 530000 28FF00n29FF00f29FF00P2AFF00…53FF00.53FF00l61FF00k7F5400▄98FF00o98FF00o98FF00CC3FF00…AAFF00.AAFF00nAAFF00k980000 80FF00a54FF00e53FF00d2AFF00a29FF00.61FF00n530000 2A0000 7EFF00l53FF00p54FF00y81FF00…80FF00.7FFF00n2A5300▄2AFF00H2AFF00o2AFF00o53FF00d2AFF00t2AFF00.53FF00n550000 2AFF00G2AFF00o53FF00S53FF00a53FF0022AFF00l29FF00n290000 29FF00B29FF00f29FF00e29FF00r29FF00o29FF00l29FF00k290000 29FF00P2AFF00l29FF00t2AFF00e29FF00.29FF00n290000 290000 2AFF00R2AFF00n29FF00i29FF00…2AFF00.2AFF00l2AFF00k2A0000 530000 280000 2A2900▄2A0000 2A0000 2A0000 2A0000 2A0000 2A0000 290000 540000 540000 2A0000 FD0000 FD0000 FD0000 7E0000 2A2900▄290000 280000 00FF00▄00FF00▄00FF00▄00FF00▄00FF00▀290000 2A0000 2A0000 060000 060000 060000 060000 980000 980000 7E6100▄2A5300▄2A0000 2A4800╵294800╹2A4800╹615300▄2A0000 292A00▄292A00▄555400▄2A5400▀2A5400▀7E5400▄81AA00▄7E5500▄2A5500▄292A00▄FFD800┌FF0000─FF0000─FFD800┐2A0000 542A00▄7E5500▄D50000 FFD500▀FFD500▀FFD500▀D50000 530000 540000 2A0000 292A00▄A40000 A40000 A40000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 2A0000 290000 2A2900▄290000 2A0000 2A0000 2A0000 2A0000 2A0000 2A0000 2A0000 290000 540000 540000 F70000 F7D500▄D5D600▀D5D600▀D5D600▀290000 290000 2A0000 00FF00▄00FF00▄00FF00▄00FF00▄FF0000▄2A7F00▄532800▄2A6600▄063D00C063D00l063D00e063D00tAA0000 98AA00▄617E00▄619200▄615300▄295300▄535500▄290A00▄280000 362A00▄280000 292A00▄2A0000 A44300▄A44300▄2A0000 542A00▄98AA00▄555300▄7E0000 FF0000│D80000 D80000 FF0000│545500▄2A5300▄2A0000 810000 7EFF00▒7EFF00▒55FF00▒810000 2A5400▄2A5300▄532A00▄534300▜43FF00a43FF00d43FF00i294300▛290000 2A2900▄290000 290000 290000 290000 290000 290000 290000 290000 2A0000 290000 290000 290000 290000 290000 290000 2A2900▄290000 290000 2A5300▄2A2900▄290000 2A0000 2A0000 2A0000 290000 2A0000 530000 543600▄2A0000 532A00▄7F0000 540000 7E0000 282900▄280000 280000 292800▄292800▄2A0000 295300▄2A6600▄939200▄C30000 C30000 989300▄920000 980000 C80000 C80000 C80000 939800▄979300▄C39200▄920000 920000 610000 2A5C00▄292A00▄290000 282900▄290000 282900▄292800▄545500▄532A00▄555300▄808100▄2A5400▄7F5500▄2A5500▄2A2900▄2A0000 290000 550000 540000 2A0000 2A0000 545300▄540000 540000 555400▄545500▄545300▄292A00▄290000 2A2900▄2A0000 2A0000 290000 290000 290000 290000 290000 292A00▄290000 290000 290000 290000 290000 290000 290000 290000 2A2900▄2A2900▄2A2900▄290000 290000 290000 2A0000 2A2900▄290000 290000 2A0000 2A0000 290000 2A0000 2A2900▄540000 540000 290000 7F0000 550000 7E0000 535400▄295300▄2A6100▄535500▄557F00▄7F9800▄7F9800▄7F9800▄980000 980000 980000 980000 980000 980000 AB0000 AB0000 C3AA00▄930000 930000 920000 920000 92C200▄920000 5B8D00▄305C00▄5B0000 8D0000 5B0000 2A0000 292A00▄290000 535400▄530000 555300▄987F00▄2A7E00▄555300▄535500▄292A00▄2A0000 292A00▄532900▄540000 7E5400▄530000 530000 530000 2A5300▄530000 545300▄530000 530000 2A5300▄290000 290000 2A0000 2A0000 292A00▄290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 282900▄2A0000 290000 290000 292A00▄2A0000 2A2900▄290000 2A5300▄290000 540000 545500▄2A0000 7F7E00▄557E00▄550000 556100▄530000 669200▄920000 7F9200▄989300▄930000 989300▄930000 980000 980000 939200▄939200▄989300▄AB0000 AC0000 AB0000 920000 920000 920000 920000 920000 92BD00▄920000 928D00▄928D00▄5B6100▄560000 5B0000 5B0000 290000 280000 2A2900▄545300▄2A5300▄987F00▄549800▄7E5300▄7E7F00▄2A0000 290000 2A0000 2A2900▄532A00▄540000 540000 530000 530000 2A0000 2A0000 530000 530000 530000 2A0000 292A00▄290000 290000 2A2900▄292A00▄290000 290000 290000 290000 290000 2A0000 290000 290000 290000 292800▄290000 290000 290000 290000 290000 280000 290000 290000 290000 2A2900▄532A00▄2A2900▄290000 2A0000 290000 545300▄550000 2A0000 550000 7E7F00▄550000 550000 2A0000 666100▄660000 920000 920000 920000 939200▄920000 930000 930000 920000 920000 939200▄AB0000 AC0000 ABAC00▄920000 928D00▄920000 920000 920000 920000 928D00▄8D6100▄615C00▄8D5B00▄565B00▄5B5C00▄5B0000 293000▄282900▄292800▄2A0000 530000 545300▄980000 2A0000 7F5500▄535400▄2A0000 2A5300▄290000 290000 540000 545500▄535400▄532A00▄2A5300▄2A0000 2A0000 530000 530000 2A5300▄2A0000 290000 290000 290000 2A2900▄292A00▄290000 290000 290000 2A2900▄2A2900▄2A2900▄2A2900▄292800▄290000 290000 290000 292800▄292800▄282900▄280000 290000 290000 282900▄290000 2A5300▄290000 290000 532A00▄290000 530000 550000 530000 530000 7F7E00▄7E0000 615500▄556100▄530000 610000 610000 610000 928D00▄928D00▄920000 920000 926600▄920000 618D00▄615C00▄986100▄989200▄989200▄615B00▄615C00▄610000 8D0000 8D0000 8D0000 8D0000 610000 5C0000 5C5B00▄5B0000 5B5600▄5C5B00▄300000 290000 282900▄292800▄290000 557E00▄540000 988000▄557E00▄7F7E00▄545300▄2A5300▄532A00▄530000 292A00▄532900▄550000 545500▄2A5300▄545300▄2A5300▄2A0000 2A0000 532A00▄530000 292A00▄290000 290000 292800▄290000 290000 290000 280000 280000 292800▄292800▄290000 290000 290000 290000 290000 290000 282900▄280000 280000 290000 292800▄280000 290000 290000 290000 290000 530000 292A00▄530000 550000 530000 530000 540000 540000 7E5500▄530000 610000 530000 615300▄610000 920000 920000 920000 920000 920000 615300▄2A5300▄292A00▄2A2900▄2A5C00▄532900▄2A2900▄2A2900▄610000 8D0000 8D0000 8D0000 610000 5C6100▄5B5C00▄2A0000 300000 2B0000 302900▄290000 290000 290000 290000 290000 532A00▄547F00▄7F0000 7E0000 535400▄7E5500▄530000 530000 2A5300▄532A00▄292A00▄290000 532900▄540000 530000 535400▄530000 530000 2A0000 2A0000 530000 530000 292A00▄290000 290000 280000 290000 290000 292800▄280000 292800▄290000 290000 290000 290000 290000 290000 290000 292800▄280000 290000 280000 280000 292800▄290000 290000 290000 532A00▄2A0000 530000 530000 2A0000 530000 2A0000 550000 7F0000 530000 2A0000 532A00▄2A5300▄615C00▄610000 610000 8D6100▄920000 929300▄930000 7F9800▄617E00▄536100▄2A0000 2A5300▄610000 8D0000 8D0000 8D0000 8D0000 610000 29D600▀29FF00▀29FF00▀29D600▀300000 300000 290000 290000 544800S540000 540000 540000 282900▄555400▄545500▄555400▄54D700▒2AD700▒7FD700▒55D700▐557E00▄292A00▄532A00▄2A5300▄292A00▄290000 2A0000 530000 555400▄545500▄530000 530000 2A0000 292A00▄2A0000 2A0000 290000 290000 292800▄290000 290000 290000 282900▄290000 280000 282900▄280000 290000 290000 290000 290000 280000 290000 290000 280000 280000 290000 290000 290000 2A0000 2A0000 2A0000 545300▄290000 2A5300▄540000 540000 550000 557E00▄2A5300▄2A2900▄530000 532A00▄5C0000 5C0000 615C00▄610000 926600▄932A00▄8D3000▄5B3000▄8D0000 55D500╚55D500╬55D500╬55D500╝935400▄987F00▄7F0000 7F5500▄295500-295500c295500o295500m545500▄550000 540000 540000 FF0000 FF0000 FF0000 FF0000 540000 540000 7F0000 7F0000 7FAC00▜7EAC00▒55AC00▒7F7E00▄818000▄7E7F00▄295300▄2A2900▄530000 2A5300▄290000 290000 532A00▄530000 555300▄555400▄530000 530000 2A0000 290000 290000 290000 290000 282900▄292800▄290000 280000 290000 290000 282900▄290000 290000 290000 290000 290000 280000 290000 290000 282900▄280000 290000 290000 290000 2A0000 290000 2A0000 540000 2A2900▄530000 540000 535400▄2A0000 7E0000 535400▄530000 290000 530000 530000 530000 535C00▄296100▄285C00▄295C00▄2A5B00▄930000 939800▄93C900▄93AA00▄93C400▄930000 7F0000 7F9800▄7F9800▄980000 980000 980000 800000 7F0000 7F0000 7F0000 7E0000 7F0000 7F0000 7F0000 7F0000 7F0000 7F0000 7F0000 7F0000 818000▄808100▄810000 7F8000▄7F0000 7F0000 818000▄7F0000 2A5400▄292A00▄532A00▄530000 290000 290000 290000 530000 545300▄540000 540000 2A5300▄2A0000 292A00▄290000 290000 290000 290000 280000 292800▄280000 292800▄290000 290000 290000 290000 290000 290000 ]], + downloading = [[3F100000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 410000 410000 0B0000 0B0000 410000 410000 0B0000 0B0000 500000 500000 500000 500000 500000 500000 0B0000 0B0000 410000 410000 0B0000 0B0000 3B0000 3B0000 3B0000 3B0000 0B0000 0B0000 410000 410000 0B0000 0B0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 410000 410000 0B0000 0B0000 410000 410000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 410000 410000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 410000 410000 0B0000 0B0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 180000 0018FF▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 410000 410000 0B0000 0B0000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 0B0000 0B0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 180000 180000 180000 0018FF▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 410000 410000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 180000 180000 180000 180000 180000 0018FF▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 410000 410000 0B0000 0B0000 410000 410000 410000 410000 0B0000 0B0000 290000 290000 290000 290000 0B0000 0B0000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 0B0000 0B0000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 0018FF▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 410000 410000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 290000 290000 290000 290000 0B0000 0B0000 410000 410000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 410000 410000 0B0000 0B0000 410000 410000 410000 410000 0B0000 0B0000 290000 290000 290000 290000 0B0000 0B0000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 0B0000 0B0000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 180000 0018FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 410000 410000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 290000 290000 290000 290000 0B0000 0B0000 410000 410000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 180000 180000 180000 180000 180000 0018FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 410000 410000 0B0000 0B0000 410000 410000 410000 410000 0B0000 0B0000 290000 290000 290000 290000 0B0000 0B0000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 0B0000 0B0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 180000 180000 180000 0018FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 410000 410000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 290000 290000 290000 290000 0B0000 0B0000 410000 410000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 180000 0018FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 410000 410000 0B0000 0B0000 410000 410000 410000 410000 0B0000 0B0000 290000 290000 290000 290000 0B0000 0B0000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 0B0000 0B0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 410000 410000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 290000 290000 290000 290000 0B0000 0B0000 410000 410000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 410000 410000 0B0000 0B0000 410000 410000 410000 410000 0B0000 0B0000 290000 290000 290000 290000 0B0000 0B0000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 410000 0B0000 0B0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 410000 410000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 290000 290000 290000 290000 0B0000 0B0000 410000 410000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 0B0000 ]], + OK = [[24120000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF DDE700▄DDE200▄DDE200▄DDE200▄D8E200▄DDDD00▄D8DD00▄D8DD00▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 00FBFF▄ECF600▄ECF100▄ECF100▄ECEC00▄E7F100▄E7EC00▄E7EC00▄E7E7FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 00FBFF▄FBFB00▄F6FB00▄FBFB00▄F6FB00▄F6FB00▄F6FB00▄F6FB00▄F6F6FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF A5A500▄A5A500▄D0A500▄D0A500▄D0A500▄D0D000▄D0D000▄FBD100▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 794E00▄794E00▄794E00▄794E00▄A54E00▄A54E00▄797900▄A57900▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 232300▄232300▄232300▄4E2300▄232300▄4E2300▄4E2300▄4E2300▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0025FF▄242500▄242400▄242400▄242400▄242400▄232400▄242400▄7B7BFF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0026FF▄252600▄252600▄262600▄252600▄252600▄252500▄255100▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 1818FF▀1D1300▄1D1300▄1D1300▄1D1800▄1D1800▄221800▄221800▄001DFF▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF A92700▄272200▄272700▄272700▄272700▄262700▄272700▄2626FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0E0EFF▀0E0900▄0E0900▄0E0900▄0E0900▄130E00▄130900▄130E00▄130E00▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 4D1800▄1D1800▄221800▄221800▄221D00▄221D00▄221D00▄2222FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 043400▄042F00▄090400▄040400▄090400▄090400▄090400▄090400▄0039FF▄0000FF 0000FF 0000FF 0000FF 0E0900▄0E0900▄130900▄130E00▄130E00▄130E00▄180E00▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 2F2FFF▀2F5A00▄2F5A00▄2F2F00▄2F2F00▄042F00▄2F2F00▄042F00▄002FFF▄0000FF 0004FF▄040400▄042F00▄040400▄040400▄090400▄040400▄090400▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 5A8600▄868600▄5AB100▄5A8600▄5A8600▄5A8600▄5A5A00▄5A8600▄2F5A00▄5A5A00▄2F5A00▄2F5A00▄2F5A00▄2F2F00▄2F2FFF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF B1B100▄B1B100▄B1DC00▄B1B100▄86DC00▄B1B100▄86B100▄86B100▄86B100▄86B100▄86B100▄868600▄8686FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF DCDCFF▀DCDB00▄DCDB00▄DCDC00▄DCDB00▄DCDC00▄DCDC00▄B1DC00▄B1DC00▄B1DC00▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF DBDBFF▀DBDA00▄DBDA00▄DBDA00▄DBDB00▄DBDA00▄DBDB00▄DBDBFF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF D9D9FF▀D9D900▄D9D900▄DAD800▄DADAFF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF D8D8FF▀D8D800▄D8D8FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF ]], + EEPROM = [[1E120000FF 0000FF 0000FF 0000FF 0000FF 0000FF 6C4100▄6C6B00▄416C00▄3B5500▄3B0000 553B00▄3B3C00▄3B5500▄3B0000 553B00▄3B3C00▄3B5500▄3B0000 553B00▄3B3C00▄363B00▄360000 363B00▄3B3600▄360000 363B00▄363B00▄360000 3B3600▄0000FF 0000FF 0000FF 0041FF▄006CFF▄006CFF▄6C3B00▄6C3B00▄413B00▄3C6C00▄3B6C00▄554600▄3B6C00▄3B6C00▄3C6C00▄554600▄3B6C00▄3B6C00▄3C7E00▄3B6C00▄3B6C00▄364100▄366C00▄364100▄3B7E00▄363C00▄364000▄360B00▄3B2A00▄362A00▄0000FF 0000FF 0000FF 6C4100▄6B6C00▄416C00▄3B0000 554100▄3B0000 716C00▄6C4100▄6C7100▄6C0000 466B00▄6C4100▄6C7100▄6C0000 466B00▄416C00▄404100▄7E6C00▄404100▄6C6B00▄406C00▄403C00▄7E4000▄417E00▄2A0000 2A0000 0B2A00▄3B0000 3B3C00▄553B00▄3B0000 3B7E00▄3B0000 416C00▄7E4000▄6C4100▄407E00▄7E4000▄404100▄3B7E00▄410000 6B5500▄CD0000 CD0000 CD0000 3B7E00▄3B4000▄3B5500▄C8CD00▄CDC800▄C8CD00▄404100▄7E0000 404100▄0B2A00▄0A2A00▄2A0000 553600▄3B0000 553600▄3C7100▄3B7100▄3C7100▄6B6C00▄417E00▄7E4100▄40CD00▄67D200▄55CD00▄406C00▄7E4100▄407E00▄CD0000 F8C800▄CD0000 3B5500▄3C3B00▄3B7E00▄CD9D00▄CDC800▄CD9D00▄667E00▄404100▄554000▄2A0000 0B2A00▄2A0B00▄360000 363B00▄3B3600▄9D7200▄729D00▄817100▄410000 407E00▄6C4100▄CDF800▄F9CD00▄CD0000 556C00▄404100▄3B6700▄CD0000 CDC800▄CD0000 3B7E00▄415500▄3B0000 C7C800▄9D0000 C7C800▄3C4000▄407E00▄7E4100▄0B2A00▄2A0A00▄2A0000 2A0000 0B2A00▄2A0000 3B0000 3B3C00▄553B00▄6C4100▄407E00▄6C4100▄CD0000 CDC800▄CEF800▄3B4100▄7E4000▄406700▄7E4100▄407E00▄7E4100▄3B0000 405500▄3C3B00▄3B7E00▄554000▄3B3C00▄7E4000▄415500▄664100▄052900▄292800▄290000 002AFF▀002AFF▀000BFF▀550500▄3B2900▄3B2900▄6C3B00▄403B00▄7E5500▄CE3B00▄CD3B00▄CD5500▄554000▄673B00▄403B00▄3B3C00▄405500▄6C3B00▄3B0000 3C3B00▄405400▄3C3B00▄3B0000 665400▄414000▄405500▄7E4100▄052900▄290500▄282900▄0000FF 0000FF 0000FF 292800▄290500▄290000 3C4000▄7E3B00▄405500▄3C3B00▄553B00▄3B3C00▄3C3B00▄553B00▄3B3C00▄554000▄3B0000 3C3B00▄543B00▄3B5500▄3B0000 543B00▄3B5400▄3C3B00▄7E4000▄417E00▄405500▄290500▄290000 052900▄360000 363B00▄3B3600▄3B0000 3C5500▄3B0000 7E3B00▄3B3C00▄3C4000▄405500▄553B00▄3B3C00▄3B6600▄553C00▄3B0000 553B00▄3C3B00▄553B00▄3B0000 3B3700▄363B00▄3C3B00▄3B3600▄543B00▄3C6B00▄404100▄417E00▄292800▄290500▄282900▄363B00▄360000 3B3600▄3C7100▄408100▄3C7100▄7E4000▄3B3C00▄554000▄3BAB00▄3CAB00▄3BAB00▄3BAB00▄3BAB00▄55AB00▄3CCE00▄55AC00▄3BAC00▄55AC00▄3BAC00▄3BAC00▄549E00▄3BAA00▄3CAA00▄3C4000▄663C00▄407E00▄290500▄290000 282900▄360000 3B3600▄360000 9D7200▄729D00▄710000 550000 3B4100▄553B00▄AB0000 AB0000 AB0000 AB0000 AB0000 AB0000 ABAC00▄AC0000 AC0000 ABAC00▄AC0000 AC0000 ABAA00▄AB0000 ABAA00▄554100▄6C4000▄403C00▄062900▄052900▄282900▄2A0000 0B2A00▄2A0B00▄407E00▄414000▄6C3C00▄3B7E00▄3B4000▄7E3B00▄D50000 D50000 D50000 FF0000 FF0000 FF0000 FF0000 FF0000 FF0000 D60000 D6D700▄D60000 D50000 D50000 D50000 363B00▄360000 3B3600▄282900▄280500▄290000 0B2A00▄2A3500▄2A0000 413B00▄7E3B00▄6C3B00▄3B0000 553B00▄3C3B00▄D5AA00▄ACAA00▄D5AA00▄FFAC00▄FFD500▄FFAC00▄FFAB00▄FFAB00▄FFAB00▄D6AC00▄D6AB00▄D7AB00▄D5AB00▄D5AB00▄D5AB00▄3B2A00▄360000 3B3600▄290000 290500▄282900▄2A0000 0B2A00▄2A0B00▄3B0000 3B5500▄3B0000 3C5500▄3B0000 553B00▄AA0000 AA8100▄AA0000 AC0000 ACD500▄AC0000 ACAB00▄ABAC00▄AB0000 ABAC00▄AB0000 AB0000 AB0000 AAAB00▄ABAA00▄360000 362A00▄0B3600▄280500▄290000 052900▄052900▄282900▄292800▄3B5500▄3C3B00▄3B0000 360000 360000 360000 0B3600▄362A00▄2A3600▄360B00▄2A3600▄360B00▄362A00▄2A0B00▄362A00▄2A0B00▄362A00▄2A0B00▄2A0000 2A0B00▄2A0000 360B00▄0B3500▄360000 282900▄290500▄282900▄282900▄052900▄290000 3B2900▄3B2900▄3C2800▄360500▄362900▄3B0500▄2A2900▄0B0500▄2A2900▄2A0500▄352900▄360500▄2A0500▄360500▄360500▄2A0500▄2A0500▄2A0500▄362800▄350600▄2A0500▄360500▄362900▄0B2900▄052900▄290500▄290000 052900▄292800▄052900▄290000 052800▄290000 290500▄290000 280500▄290000 290500▄052900▄290000 292800▄290000 290500▄290000 292800▄290000 290500▄290000 052900▄290000 290500▄282900▄292800▄052900▄282900▄290500▄282900▄]], +} + +for key in pairs(images) do + images[key] = image.fromString(images[key]) + os.sleep(0.05) +end + +------------------------------------------------------------------------------------------------------------------------------------ + +local web = require("web") +local buffer = require("doubleBuffering") +local GUI = require("GUI") + +buffer.setResolution(gpu.maxResolution()) +local mainContainer = GUI.fullScreenContainer() +mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x2D2D2D)) + +local stageContainer = mainContainer:addChild(GUI.container(math.floor(mainContainer.width / 2 - 90 / 2), math.floor(mainContainer.height / 2 - 28 / 2), 90, 28)) +stageContainer:addChild(GUI.panel(1, 1, stageContainer.width, stageContainer.height, 0xDDDDDD)) + +------------------------------------------------------------------------------------------------------------------------------------ + +local OSSettings = {} +local stages = {current = 1} +local localization + +local function addButtonsToStage() + local buttonWidth = 7 + local spaceBetween = 5 + + local totalWidth = (stages.current > 1 and buttonWidth or 0) + (stages.current > 1 and stages.current < #stages and spaceBetween or 0) + (stages.current < #stages and buttonWidth or 0) + local x = math.floor(stageContainer.width / 2 - totalWidth / 2) + 1 + local y = stageContainer.height - 3 + + if stages.current > 1 then + stageContainer.previousStageButton = stageContainer:addChild(GUI.roundedButton(x, y, buttonWidth, 3, 0xAAAAAA, 0xDDDDDD, 0x777777, 0xDDDDDD, "⇦")) + stageContainer.previousStageButton.colors.disabled.background = 0xCCCCCC + stageContainer.previousStageButton.colors.disabled.text = 0xDDDDDD + stageContainer.previousStageButton.onTouch = function() + stages.load(stages.current - 1) + end + x = x + stageContainer.previousStageButton.width + spaceBetween + end + + if stages.current < #stages then + stageContainer.nextStageButton = stageContainer:addChild(GUI.roundedButton(x, y, buttonWidth, 3, 0xAAAAAA, 0xDDDDDD, 0x777777, 0xDDDDDD, "⇨")) + stageContainer.nextStageButton.colors.disabled.background = 0xCCCCCC + stageContainer.nextStageButton.colors.disabled.text = 0xDDDDDD + stageContainer.nextStageButton.onTouch = function() + stages.load(stages.current + 1) + end + end +end + +function stages.load(stage) + stages.current = stage + stageContainer:deleteChildren(2) + + stages[stage]() + + mainContainer:draw() + buffer.draw() +end + +local function addImageToStage(y, picture) + stageContainer:addChild(GUI.image(math.floor(stageContainer.width / 2 - image.getWidth(picture) / 2), y, picture)) + return y + image.getHeight(picture) - 1 +end + +------------------------------------------------------------------------------------------------------------------------------------ + +local function loadLocalization(language) + OSSettings.language = language + localization = serialization.unserialize(web.request(urls.installer .. OSSettings.language .. ".lang")) +end + +stages[1] = function() + addButtonsToStage() + local y = addImageToStage(3, images.languages) + y = y + 3 + local comboBox = stageContainer:addChild(GUI.comboBox(math.floor(stageContainer.width / 2 - 15), y, 30, 3, 0xFFFFFF, 0x555555, 0xAAAAAA, 0xDDDDDD)) + loadLocalization("Russian") + comboBox:addItem("Russian").onTouch = function() + loadLocalization("Russian") + end + comboBox:addItem("English").onTouch = function() + loadLocalization("English") + end +end + +------------------------------------------------------------------------------------------------------------------------------------ + +local function addSwitchToStage(x, y, color, text, state) + stageContainer:addChild(GUI.label(math.floor(x + 4 - unicode.len(text) / 2), y + 1, stageContainer.width, 1, 0x555555, text)) + return stageContainer:addChild(GUI.switch(x, y, 8, color, 0x444444, 0xFFFFFF, state)) +end + +stages[2] = function() + addButtonsToStage() + stageContainer:addChild(GUI.image(1, 1, images.OS)) + local y = 22 + local spaceBetween = 22 + local x = math.floor(stageContainer.width / 2 - 25) + + stageContainer.fullInstallationSwitch = addSwitchToStage(x, y, 0xFF4940, localization.fullInstallation, true) + x = x + spaceBetween + + stageContainer.downloadWallpapersSwitch = addSwitchToStage(x, y, 0x3392FF, localization.installWallpapers, true) + x = x + spaceBetween + + stageContainer.showApplicationsHelpSwitch = addSwitchToStage(x, y, 0x66DB80, localization.showApplicationsHelp, true) +end + +------------------------------------------------------------------------------------------------------------------------------------ + +stages[3] = function() + addButtonsToStage() + local data = web.request("https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/License/" .. OSSettings.language .. ".lang") + local lines = {} + for line in data:gmatch("[^\n]+") do + table.insert(lines, line) + end + stageContainer:addChild(GUI.textBox(1, 1, 90, 20, 0xFFFFFF, 0x444444, string.wrap(lines, 88), 1, 1, 1)) + + stageContainer.nextStageButton.disabled = true + local switch = addSwitchToStage(41, 22, 0x666666, localization.terms, false) + switch.onStateChanged = function(state) + stageContainer.nextStageButton.disabled = not state + mainContainer:draw() + buffer.draw() + end +end + +------------------------------------------------------------------------------------------------------------------------------------ + +stages[4] = function() + local y = addImageToStage(5, images.downloading) + y = y + 3 + stageContainer.nextStageButton.disabled, stageContainer.previousStageButton.disabled = true, true + + local width = 62 + local x = math.floor(stageContainer.width / 2 - width / 2) + local progressBar = stageContainer:addChild(GUI.progressBar(x, y, width, 0x3392FF, 0xBBBBBB, 0x555555, 0, true, false)) + local fileLabel = stageContainer:addChild(GUI.label(x, y + 1, width, 1, 0x666666, "")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + + local thingsToDownload = {} + for i = 1, #applicationList do + if + not applicationList[i].preLoadFile and + ( + (applicationList[i].type == "Library" or applicationList[i].type == "Icon") + or + (applicationList[i].forceDownload) + or + (applicationList[i].type == "Wallpaper" and stageContainer.downloadWallpapersSwitch.state == true) + or + (applicationList[i].type == "Application" and stageContainer.fullInstallationSwitch.state == true) + ) + then + table.insert(thingsToDownload, applicationList[i]) + end + + applicationList[i] = nil + end + + applicationList = nil + + for i = 1, #thingsToDownload do + fileLabel.text = localization.downloading .. " " .. fs.name(thingsToDownload[i].path) + progressBar.value = math.ceil(i / #thingsToDownload * 100) + + mainContainer:draw() + buffer.draw() + + web.downloadMineOSApplication(thingsToDownload[i], OSSettings.language) + end + + stageContainer:deleteChildren(2) + y = addImageToStage(4, images.EEPROM) + stageContainer:addChild(GUI.label(1, y + 3, stageContainer.width, 1, 0x666666, localization.flashingEEPROM)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + mainContainer:draw() + buffer.draw() + + component.eeprom.set(web.request(urls.EFI)) + + stages.load(5) +end + +------------------------------------------------------------------------------------------------------------------------------------ + +stages[5] = function() + addImageToStage(3, images.OK) + stageContainer.children[#stageContainer.children].localPosition.x = stageContainer.children[#stageContainer.children].localPosition.x + 3 + + stageContainer:addChild(GUI.label(1, 22, stageContainer.width, 1, 0x666666, localization.needToReboot)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + stageContainer:addChild(GUI.adaptiveRoundedButton(math.floor(stageContainer.width / 2 - (unicode.len(localization.reboot) + 4) / 2), stageContainer.height - 4, 2, 1, 0xAAAAAA, 0xDDDDDD, 0x777777, 0xDDDDDD, localization.reboot)).onTouch = function() + OSSettings.wallpaper = stageContainer.downloadWallpapersSwitch.state and "/MineOS/Pictures/Space.pic" or nil + OSSettings.screensaver = "Matrix" + OSSettings.screensaverDelay = 20 + OSSettings.showHelpOnApplicationStart = stageContainer.showApplicationsHelpSwitch.state + OSSettings.dockShortcuts = { + "/MineOS/Applications/AppMarket.app/", + "/MineOS/Applications/MineCode IDE.app/", + "/MineOS/Applications/Photoshop.app/", + } + + table.toFile(paths.OSSettings, OSSettings) + + local file = io.open("/autorun.lua", "w") + file:write("dofile(\"/OS.lua\")") + file:close() + + require("computer").shutdown(true) + end +end + +------------------------------------------------------------------------------------------------------------------------------------ + +stages.load(1) +mainContainer:draw() +buffer.draw(true) +mainContainer:startEventHandling() diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Localization/English.lang b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Localization/English.lang new file mode 100755 index 00000000..fd10f447 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Localization/English.lang @@ -0,0 +1,167 @@ +{ + network = "Network", + networkTimeout = "Remote computer is not responding", + networkAccessDenied = "Access to the filesystem of the remote computer is denied. Contact it's owner to get appropriate privileges", + networkAllowReadAndWrite = "Filesystem access", + networkModemNotAvailable = "Attach modem to use network functions", + networkState = "Enable network mode", + networkComputers = "Network PCs options", + networkComputersNotFound = "Computers not fount", + networkName = "Name of this PC", + networkSearchRadius = "Searching radius", + openWith = "Open with", + select = "Choose application…", + keepInDock = "Keep in dock", + closeAllWindows = "Close all windows", + newWindow = "New window", + launchWithArguments = "Launch with arguments", + dontShowAnymore = "Don't show again", + applicationHelp = "About application", + newName = "New name", + folderName = "Folder name", + fileName = "File name", + applicationName = "Application name", + file = "File", + notExists = "not exists", + alreadyExists = "already exists", + inDirectory = "in directory", + needReplace = "Replace it?", + yes = "Yes", + no = "No", + cancel = "Cancel", + open = "Open", + applyToAll = "Apply to all", + toDirectory = "to directory", + copying = "Copying", + faylaBlyad = "file", + + resolution = "Screen resolution", + pressAnyKeyToContinue = "Press any key to continue", + screensaver = "Screensaver", + screensaverDelay = "Delay", + screensaverEnabled = "Screensaver enabled", + + areYouSure = "Are you sure?", + emptyTrash = "Empty trash", + type = "Type", + size = "Size", + date = "Date", + path = "Path", + folder = "Folder", + unknown = "Unknown", + calculatingSize = "calculating…", + + properties = "Properties", + newFolderFromChosen = "New folder from chosen", + create = "New", + newFolder = "Folder", + newFile = "File", + newFileFromURL = "File from URL", + newApplication = "MineOS application", + paste = "Paste", + copy = "Copy", + cut = "Cut", + edit = "Edit", + editInPhotoshop = "Edit in Photoshop", + rename = "Rename", + editShortcut = "Edit shortcut", + createShortcut = "Create shortcut", + addToDock = "Add to Dock", + removeFromDock = "Remove from Dock", + moveRight = "Move right", + moveLeft = "Move left", + archive = "Add to archive", + delete = "Delete", + addToFavourites = "Add to favourites", + setAsWallpaper = "Set as wallpaper", + showPackageContent = "Show package content", + showContainingFolder = "Show containing folder", + flashEEPROM = "Write on EEPROM", + + sortBy = "Sort", + sortByType = "By type", + sortByName = "By name", + sortByDate = "By date", + showExtension = "File extensions", + showHiddenFiles = "Hidden files", + showApplicationIcons = "Application icons", + + aboutSystem = "About this PC", + updates = "Updates", + update = "Refresh", + shutdown = "Shutdown", + logout = "Logout", + reboot = "Reboot", + returnToShell = "Return to Shell", + + protectYourComputer = "Computer protection", + inputPassword = "Input password", + confirmInputPassword = "Confirm password", + oldPassword = "Old password", + newPassword = "New password", + setProtectionMethod = "Change computer protection method", + wrongOldPassword = "Wrong old password!", + passwordSucessfullyChanged = "Password has been successfully changed!", + withoutProtection = "Without protection", + passwordProtection = "Password protection", + biometricProtection = "Biometric protection", + putFingerToVerify = "Put your finger to authorize", + putFingerToRegister = "Put your finger to create a biometric signature", + fingerprintCreated = "Biometric signature has been created", + accessDenied = "Access denied", + welcomeBack = "Welcome, ", + passwordsAreDifferent = "Passwords are different", + incorrectPassword = "Incorrect password", + mineOSCreatorUsedMasterPassword = "The creator of this operating system has used Master-Password", + loginToSystem = "Login", + + colorScheme = "Color scheme", + iconProperties = "Icons properties", + spaceBetweenIcons = "Space bewteen icons", + sizeOfIcons = "Size of icons", + byHorizontal = "Horizontal", + byVertical = "Vertical", + wallpaper = "Wallpaper", + wallpaperPath = "Path to wallpaper", + iconPath = "Path to icon", + wallpaperModeStretch = "Stretch", + wallpaperModeCenter = "Center", + wallpaperEnabled = "Wallpaper enabled", + wallpaperBrightness = "Wallpaper brightness", + wallpaperSwitchInfo = "Disabling this option will decrease RAM usage and increase system perfomance", + backgroundColor = "Background color", + menuColor = "Menu color", + dockColor = "Dock color", + transparencyEnabled = "Transparency enabled", + transparencySwitchInfo = "Disabling this option will increase system perfomance", + screenResolution = "Screen resolution", + changePassword = "Change password", + shortcutIsCorrupted = "Shortcut is linked to non-existent file", + sortAutomatically = "Align to grid", + onDesktop = "On desktop", + inCurrentDirectory = "In current directory", + + settings = "Preferences", + months = { + Jan = "Jan", + Feb = "Feb", + Mar = "Mar", + Apr = "Apr", + May = "May", + Jun = "Jun", + Jul = "Jul", + Aug = "Aug", + Sep = "Sep", + Oct = "Oct", + Nov = "Nov", + Dec = "Dec", + }, + timezone = "Timezone", + + errorWhileRunningProgram = "Error while running ", + sendedFeedback = "Feedback was sent", + sendFeedback = "Send feedback", + yourContacts = "Your contacts", + additionalInfo = "Additional information", + stackTraceback = "Stack traceback", +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Localization/Russian.lang b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Localization/Russian.lang new file mode 100755 index 00000000..d0f6950a --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Localization/Russian.lang @@ -0,0 +1,167 @@ +{ + network = "Сеть", + networkTimeout = "Удаленный компьютер не ответил на запрос", + networkAccessDenied = "Доступ к файловой системе удаленного компьютера запрещен. Свяжитесь с его владельцем для предоставления соответствующих привилегий", + networkAllowReadAndWrite = "Доступ к файлам", + networkModemNotAvailable = "Подключите модем для использования сетевых функций", + networkState = "Включить сетевой режим", + networkComputers = "Параметры удаленных ПК", + networkComputersNotFound = "Компьютеры в сети не обнаружены", + networkName = "Имя данного ПК", + networkSearchRadius = "Радиус обнаружения", + openWith = "Открыть с помощью", + select = "Выбрать программу…", + keepInDock = "Оставить в Dock", + closeAllWindows = "Закрыть все окна", + newWindow = "Новое окно", + launchWithArguments = "Запустить с аргументами", + dontShowAnymore = "Больше не показывать", + applicationHelp = "О приложении", + newName = "Новое имя", + folderName = "Имя папки", + fileName = "Имя файла", + applicationName = "Имя приложения", + file = "Файл", + notExists = "не существует", + alreadyExists = "уже существует", + inDirectory = "в директории", + needReplace = "Заменить?", + yes = "Да", + no = "Нет", + cancel = "Отмена", + open = "Открыть", + applyToAll = "Применить ко всем", + toDirectory = "в директории", + copying = "Копирование", + faylaBlyad = "файла", + + resolution = "Разрешение экрана", + pressAnyKeyToContinue = "Нажмите любую клавишу, чтобы продолжить", + screensaver = "Заставка", + screensaverDelay = "Задержка", + screensaverEnabled = "Использовать заставку", + + areYouSure = "Вы уверены?", + emptyTrash = "Очистить корзину", + type = "Тип", + size = "Размер", + date = "Дата", + path = "Путь", + folder = "Папка", + unknown = "Неизвестно", + calculatingSize = "идет подсчет…", + + properties = "Свойства", + newFolderFromChosen = "Новая папка из выбранного", + create = "Создать", + newFolder = "Папку", + newFile = "Файл", + newFileFromURL = "Файл по URL", + newApplication = "Приложение MineOS", + paste = "Вставить", + copy = "Копировать", + cut = "Вырезать", + edit = "Редактировать", + editInPhotoshop = "Редактировать в Photoshop", + rename = "Переименовать", + editShortcut = "Редактировать ярлык", + createShortcut = "Создать ярлык", + addToDock = "Добавить в Dock", + removeFromDock = "Удалить из Dock", + moveRight = "Передвинуть правее", + moveLeft = "Передвинуть левее", + archive = "Добавить в архив", + delete = "Удалить", + addToFavourites = "Добавить в избранное", + setAsWallpaper = "Установить как обои", + showPackageContent = "Показать содержимое пакета", + showContainingFolder = "Открыть содержащую папку", + flashEEPROM = "Записать на EEPROM", + + sortBy = "Упорядочить", + sortByType = "По типу", + sortByName = "По имени", + sortByDate = "По дате", + showExtension = "Расширения файлов", + showHiddenFiles = "Скрытые файлы", + showApplicationIcons = "Иконки приложений", + + aboutSystem = "Об этом ПК", + updates = "Обновления", + update = "Обновить", + shutdown = "Выключить", + logout = "Выйти", + reboot = "Перезагрузить", + returnToShell = "Вернуться в Shell", + + protectYourComputer = "Защита компьютера", + inputPassword = "Введите пароль", + confirmInputPassword = "Подтвердите пароль", + oldPassword = "Старый пароль", + newPassword = "Новый пароль", + setProtectionMethod = "Изменить метод защиты компьютера", + wrongOldPassword = "Неверный старый пароль", + passwordSucessfullyChanged = "Пароль успешно изменен!", + withoutProtection = "Без защиты", + passwordProtection = "Защита паролем", + biometricProtection = "Биометрическая", + putFingerToVerify = "Приложите палец для авторизации", + putFingerToRegister = "Приложите палец для создания биометрического снимка", + fingerprintCreated = "Биометрический снимок создан", + accessDenied = "Доступ запрещен", + welcomeBack = "Добро пожаловать, ", + passwordsAreDifferent = "Пароли не совпадают", + incorrectPassword = "Неверный пароль", + mineOSCreatorUsedMasterPassword = "Создатель операционной системы использовал мастер-ключ", + loginToSystem = "Вход в систему", + + colorScheme = "Цветовая схема", + iconProperties = "Параметры иконок", + spaceBetweenIcons = "Расстояние между иконками", + sizeOfIcons = "Размер иконок", + byHorizontal = "По горизонтали", + byVertical = "По вертикали", + wallpaper = "Обои", + wallpaperPath = "Путь к обоям", + iconPath = "Путь к иконке", + wallpaperModeStretch = "Растянуть", + wallpaperModeCenter = "По центру", + wallpaperEnabled = "Использовать обои", + wallpaperBrightness = "Яркость обоев", + wallpaperSwitchInfo = "Отключение этой опции существенно снизит расход оперативной памяти и увеличит производительность", + backgroundColor = "Цвет фона", + menuColor = "Цвет меню", + dockColor = "Цвет Dock", + transparencyEnabled = "Прозрачность интерфейса", + transparencySwitchInfo = "Отключение этой опции существенно снизит количество прямых обращений к CPU и увеличит производительность", + screenResolution = "Разрешение экрана", + changePassword = "Изменить пароль", + shortcutIsCorrupted = "Ярлык ссылается на несуществующий файл", + sortAutomatically = "Привязать к сетке", + onDesktop = "На рабочем столе", + inCurrentDirectory = "В текущей директории", + + settings = "Настройки", + months = { + Jan = "Января", + Feb = "Февраля", + Mar = "Марта", + Apr = "Апреля", + May = "Мая", + Jun = "Июня", + Jul = "Июля", + Aug = "Августа", + Sep = "Сентября", + Oct = "Октября", + Nov = "Ноября", + Dec = "Декабря", + }, + timezone = "Временная зона", + + errorWhileRunningProgram = "Ошибка при выполнении ", + sendedFeedback = "Отчет отправлен", + sendFeedback = "Отправить отчет", + yourContacts = "Ваши контакты", + additionalInfo = "Дополнительная информация", + stackTraceback = "Стек ошибки", +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Properties.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Properties.cfg new file mode 100644 index 00000000..2531649d --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Properties.cfg @@ -0,0 +1,86 @@ +{ + wallpaper = "/MineOS/Pictures/Girl.pic", + dockColor = 16777215, + screensaverEnabled = false, + iconWidth = 12, + timezone = 3, + showApplicationIcons = true, + network = { + enabled = true, + name = "Йа аццкий сотона2", + signalStrength = 512, + users = { + ["055ad405-a2ff-47fa-a554-12582bb22a67"] = { + allowMessages = true, + allowReadAndWrite = true + }, + ["7dd58ca3-450c-4d9f-b278-ce3722a31ae7"] = { + allowReadAndWrite = true + }, + ["3de501c7-f31a-4a11-a1f6-09c32ea94428"] = { + allowMessages = true, + allowReadAndWrite = true + } + } + }, + wallpaperEnabled = false, + iconHorizontalSpaceBetween = 1, + screensaver = "XCOM.lua", + iconVerticalSpaceBetween = 1, + showExtension = false, + protectionMethod = "withoutProtection", + transparencyEnabled = true, + biometryHash = "d9d045d9c7711d72efaf75407c8eaa9acc5dc70f9be0087099131b7ed22cbb9d", + extensionAssociations = { + [".txt"] = { + icon = "/MineOS/System/Icons//Text.pic", + launcher = "/MineOS/Applications//MineCode IDE.app/Main.lua" + }, + [".lua"] = { + icon = "/MineOS/System/Icons//Lua.pic", + contextMenu = "/MineOS/System/Extensions/Lua/ContextMenu.lua", + launcher = "/MineOS/System/Extensions/Lua/Launcher.lua" + }, + script = { + icon = "/MineOS/System/Icons//Script.pic", + contextMenu = "/MineOS/System/Extensions/Lua/ContextMenu.lua", + launcher = "/MineOS/System/Extensions/Lua/Launcher.lua" + }, + [".pic"] = { + icon = "/MineOS/System/Icons//Image.pic", + contextMenu = "/MineOS/System/Extensions/Pic/ContextMenu.lua", + launcher = "/MineOS/Applications//Photoshop.app/Main.lua" + }, + [".arc"] = { + icon = "/MineOS/System/Icons//Archive.pic", + launcher = "/MineOS/System/Extensions/Arc/Launcher.lua" + }, + [".3dm"] = { + icon = "/MineOS/System/Icons//3DModel.pic", + launcher = "/MineOS/Applications//3DPrint.app/Main.lua" + }, + [".cfg"] = { + icon = "/MineOS/System/Icons//Config.pic", + launcher = "/MineOS/Applications//MineCode IDE.app/Main.lua" + } + }, + language = "Russian", + backgroundColor = 1973790, + dockShortcuts = { + [5] = "/MineOS/Applications/Control.app/", + [1] = "/MineOS/Applications/AppMarket.app/", + [2] = "/MineOS/Applications/MineCode IDE.app/", + [3] = "/MineOS/Applications/Finder.app/", + [4] = "/MineOS/Applications/Photoshop.app/" + }, + iconHeight = 6, + wallpaperMode = 2, + screensaverDelay = 26.675, + resolution = { + [1] = 160, + [2] = 44 + }, + menuColor = 14803425, + wallpaperBrightness = 1, + showHelpOnApplicationStart = false +} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Radio/Stations.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Radio/Stations.cfg new file mode 100644 index 00000000..02f30a07 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Radio/Stations.cfg @@ -0,0 +1 @@ +{[1]={["url"]="http://galnet.ru:8000/soft",["name"]="Galnet Soft"},[2]={["url"]="http://ep256.streamr.ru",["name"]="Европа Плюс"},[3]={["url"]="http://server2.lradio.ru:8000/lradio64.aac.m3u",["name"]="L-Radio"},[4]={["url"]="http://online.radiorecord.ru:8101/rr_128.m3u",["name"]="Radio Record"},[5]={["url"]="http://livestream.rfn.ru:8080/moscowfmen128.m3u",["name"]="Moscow FM"},["currentStation"]=3} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/Clock.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/Clock.lua new file mode 100755 index 00000000..14fa2a8b --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/Clock.lua @@ -0,0 +1,70 @@ +local gpu = require("component").gpu +local event = require("event") +local w, h, t, q = gpu.getResolution() +local numb, ha, wh, p, s, u, e, gsB, gS, ti, r, slp, tn = {29850,29351,30887,18925,14735,27343,9383,31407,31147,[0]=31599}, h/2-2, {0, 8, nil, 18, 26}, "▀", " ", h%2, w/2, gpu.setBackground, gpu.set, table.insert, math.random, os.sleep, tonumber + +local function drawN(x, y, n) + local c = 0 + for i = 0, 14 do + if bit32.extract(numb[n], i) == 1 then + gsB(60928) + gS(x, y, s) + else + gsB(0) + gS(x, y, s) + end + c, x = c + 1, x + 2 + if c % 3 == 0 then + y, x = y + 1, x - 6 + end + end +end + +gsB(0) +gpu.fill(1, 1, w, h, " ") +local tbl = {x = {}, y = {}} +for x = 1, w, 2 do + for y = 1, ha-1-u do + ti(tbl.x, x) + ti(tbl.y, y) + end +end +for n = 1, #tbl.x do + k = r(n) + tbl.x[n], tbl.x[k], tbl.y[n], tbl.y[k] = + tbl.x[k], tbl.x[n], tbl.y[k], tbl.y[n] +end +while true do + q = 1 + for i = 1, #tbl.x do + gpu.setForeground(r(tbl.x[i]*tbl.y[i])*512) + gS(tbl.x[i], tbl.y[i], p) + gS(-tbl.x[i]+w, -tbl.y[i]+h+1, p) + q = q + 1 + if q == 55 then + t = os.date("%T") + for o = 1, 5 do + if o ~= 3 then + drawN(e+wh[o]-15, ha+u, tn(t:sub(o,o))) + end + end + if tn(t:sub(5, 5))%2 == 0 then + gsB(60928) + else + gsB(0) + end + gS(e, ha+1+u, s) + gS(e, ha+3+u, s) + gsB(0) + q = 1 + slp(0.05) + end + local cykaNahooy = {event.pull(0)} + if cykaNahooy[1] == "key_down" or cykaNahooy[1] == "touch" then + gpu.setBackground(0x0) + gpu.fill(1, 1, w, h, " ") + return + end + end + slp(0.05) +end \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/Lines.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/Lines.lua new file mode 100644 index 00000000..41092ad1 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/Lines.lua @@ -0,0 +1,62 @@ + +local buffer = require("doubleBuffering") +local event = require("event") + +------------------------------------------------------------------------------------- + +local lineCount = 10 +local backgroundColor = 0x0 +local lineColor = 0xFFFFFF +local bufferWidth, bufferHeight = buffer.getResolution() + +------------------------------------------------------------------------------------- + +local t = {} + +function rnd() + if math.random(0,1) == 0 then + return -1 + else + return 1 + end +end + +for i = 1, lineCount do + t[i] = { + x = math.random(1, bufferWidth), + y = math.random(1, bufferHeight * 2), + dx = rnd(), + dy = rnd() + } +end + +------------------------------------------------------------------------------------- + +buffer.clear(backgroundColor) +buffer.draw(true) + +while true do + local eventType = event.pull(0.0001) + if eventType == "touch" or eventType == "key_down" then + break + end + + for i = 1, lineCount do + t[i].x = t[i].x + t[i].dx + t[i].y = t[i].y + t[i].dy + + if t[i].x > bufferWidth then t[i].dx = -1 end + if t[i].y > bufferHeight * 2 then t[i].dy = -1 end + if t[i].x < 1 then t[i].dx = 1 end + if t[i].y < 1 then t[i].dy = 1 end + end + + buffer.clear(backgroundColor) + + for i = 1, lineCount - 1 do + buffer.semiPixelLine(t[i].x, t[i].y, t[i + 1].x, t[i + 1].y, lineColor) + end + + buffer.semiPixelLine(t[1].x, t[1].y, t[lineCount].x, t[lineCount].y, lineColor) + buffer.draw() +end \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/Mandala.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/Mandala.lua new file mode 100755 index 00000000..2affae0e --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/Mandala.lua @@ -0,0 +1,147 @@ +local gpu, r, xr, ti = require("component").gpu, math.random, bit32.bxor, table.insert +local event = require("event") + +local tbl, tbl1, S, gsF, gsB, w, h, n, c, Fc, Bc, C, D, i, j, m, k, q, p, a, b = {}, {x = {}, y = {}}, "▄", gpu.setForeground, gpu.setBackground, gpu.getResolution() + +local t = (w-h*2)/2 + +local function pix(x, y, color) + + n = y%2 + + y = (y+n)/2 + + c, Fc, Bc = gpu.get(x+t, y) + + if c ~= S then + + Fc = Bc + + end + + if n == 0 then + + Fc = color + + else + + Bc = color + + end + + gsF(Fc) + + gsB(Bc) + + gpu.set(x+t, y, S) + +end + + + +gsB(0) + +gpu.fill(1, 1, w, h, " ") + +for i = 1, h do + + tbl[i] = {} + + for j = 1, h do + + ti(tbl1.x, i) + + ti(tbl1.y, j) + + end + +end + +for n = 1, #tbl1.x do + + k = r(n) + + tbl1.x[n], tbl1.x[k], tbl1.y[n], tbl1.y[k] = + + tbl1.x[k], tbl1.x[n], tbl1.y[k], tbl1.y[n] + +end + +while true do + + for i = 1, h do + + for j = 1, h do + + tbl[i][j] = 0 + + end + + end + + for i = 1, h do + + m = r(0, 1) + + tbl[i][1], tbl[1][i] = m, m + + end + + C, D, i, j = r(0, 255), t + + for y = 2, #tbl do + + for x = y, #tbl[y] do + + q = xr(tbl[x-1][y], tbl[x][y-1]) + + tbl[x][y], tbl[y][x] = q, q + + end + + end + + for o = 1, #tbl1.x do + + i, j = tbl1.x[o], tbl1.y[o] + + p, a, b = i*j*C, -j+h*2, -i+h*2 + + if tbl[i][j] == 1 then + + pix(j, i, p) + + pix(a, b, p) + + pix(a, i, p) + + pix(j, b, p) + + else + + pix(j, i, 0) + + pix(a, b, 0) + + pix(a, i, 0) + + pix(j, b, 0) + + end + + pix(r(-D+1, 0), r(1, h*2), C) + + pix(r(h*2, w-D), r(1, h*2), C) + + end + + gsF(65280) + gsB(0) + + local e = {event.pull(1)} + if e[1] == "key_down" or e[1] == "touch" then + gpu.setBackground(0x0) + gpu.fill(1, 1, w, h, " ") + break + end +end \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/Matrix.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/Matrix.lua new file mode 100755 index 00000000..ae6b176a --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/Matrix.lua @@ -0,0 +1,96 @@ + +local event = require("event") +local gpu = require("component").gpu + +-------------------------------------------------------------------------------------------------------------------- + +local maximumLines = 60 +local minimumLineLength = 5 +local maximumLineLength = 55 +local backgroundColor = 0x000000 +local speed = 0.00 + +local chars = { "ァ", "ア", "ィ", "イ", "ゥ", "ウ", "ェ", "エ", "ォ", "オ", "カ", "ガ", "キ", "ギ", "ク", "グ", "ケ", "ゲ", "コ", "ゴ", "サ", "ザ", "シ", "ジ", "ス", "ズ", "セ", "ゼ", "ソ", "ゾ", "タ", "ダ", "チ", "ヂ", "ッ", "ツ", "ヅ", "テ", "デ", "ト", "ド", "ナ", "ニ", "ヌ", "ネ", "ノ", "ハ", "バ", "パ", "ヒ", "ビ", "ピ", "フ", "ブ", "プ", "ヘ", "ベ", "ペ", "ホ", "ボ", "ポ", "マ", "ミ", "ム", "メ", "モ", "ャ", "ヤ", "ュ", "ユ", "ョ", "ヨ", "ラ", "リ", "ル", "レ", "ロ", "ヮ", "ワ", "ヰ", "ヱ", "ヲ", "ン", "ヴ", "ヵ", "ヶ", "・", "ー", "ヽ", "ヾ" } +local lineColorsForeground = { 0xFFFFFF, 0xBBFFBB, 0x88FF88, 0x33FF33, 0x00FF00, 0x00EE00, 0x00DD00, 0x00CC00, 0x00BB00, 0x00AA00, 0x009900, 0x008800, 0x007700, 0x006600, 0x005500, 0x004400, 0x003300, 0x002200, 0x001100 } +local lineColorsBackground = { 0x004400, 0x004400, 0x003300, 0x003300, 0x002200, 0x001100 } + +-------------------------------------------------------------------------------------------------------------------- + +local lines = {} +local lineColorsForegroundCount = #lineColorsForeground +local charsCount = #chars +local screenWidth, screenHeight = gpu.getResolution() +local currentBackground, currentForeground + +local function setBackground(color) + if currentBackground ~= color then + gpu.setBackground(color) + currentBackground = color + end +end + +local function setForeground(color) + if currentForeground ~= color then + gpu.setForeground(color) + currentForeground = color + end +end + +-------------------------------------------------------------------------------------------------------------------- + +setBackground(backgroundColor) +gpu.fill(1, 1, screenWidth, screenHeight, " ") + +local i, colors, background, part, eventType +while true do + while #lines < maximumLines do + table.insert(lines, { + x = math.random(1, screenWidth), + y = 1, + length = math.random(minimumLineLength, maximumLineLength) + }) + end + + gpu.copy(1, 1, screenWidth, screenHeight, 0, 1) + setBackground(backgroundColor) + gpu.fill(1, 1, screenWidth, 1, " ") + + i, colors = 1, {} + while i <= #lines do + lines[i].y = lines[i].y + 1 + if lines[i].y - lines[i].length > 0 then + table.remove(lines, i) + else + part = math.ceil(lineColorsForegroundCount * lines[i].y / lines[i].length) + + background = lineColorsBackground[part] or 0x000000 + colors[background] = colors[background] or {} + colors[background][lineColorsForeground[part]] = colors[background][lineColorsForeground[part]] or {} + table.insert(colors[background][lineColorsForeground[part]], i) + + i = i + 1 + end + end + + for background in pairs(colors) do + setBackground(background) + for foreground in pairs(colors[background]) do + setForeground(foreground) + for i = 1, #colors[background][foreground] do + gpu.set(lines[colors[background][foreground][i]].x, 1, chars[math.random(1, charsCount)]) + end + end + end + + eventType = event.pull(speed) + if eventType == "key_down" or eventType == "touch" then + setBackground(0x000000) + setForeground(0xFFFFFF) + gpu.fill(1, 1, screenWidth, screenHeight, " ") + break + end +end + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/NyanCat.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/NyanCat.lua new file mode 100644 index 00000000..b358486c --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/NyanCat.lua @@ -0,0 +1,834 @@ +local buffer = require("doubleBuffering") +local event = require("event") + +local nyans = { + { + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ".,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,>>>>>>>,,,,,,,,>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$''$-$$@','',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$$$$$$$'**'$$$@''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&+++++++&&&&&&&&'''++'@$$$$$-$$'***$$$@'***',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++++++++++++++++++**''+'@$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++++++++++++++++++'**'''@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++#######++++++++''**''@$$$$$$-'*************',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###################''**'@$-$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "####################''''@$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###=======########====''@@$$$-$$'*%%********%%',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "======================='@@@$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "===;;;;;;;.=======;;;;'''@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;'***''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;'**'','*',,,,,'*','**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;,,,,.,,;;;.;;;;,,,'''',,'',,,,,,,'',,'',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + }, + { + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,>>>>>>>,,,,,,,,>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&+++++++&&&&&&&&+++++'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++++++++++++++++++'+++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++++++++++++++++++'*'++'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++#######++++++++'*''''@$$$$$$-$'*************',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###################****'@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###################''**'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###=======########==='''@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "======================='@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "===;;;;;;;========;;;;;''@@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;;'**'''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;;'**','*',,,,,,**','**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;,,.,,,,;;;;;;;;,,,,''',,,'',,,,,,''',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,..,,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + }, + { + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,..,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,.,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,", + ">>,,,,,,,>>>>>>>>,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++&&&&&&&++++++++&&&&&&'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++++++++++++++++++++++'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++++++++++++++++++++++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "##+++++++########++++++'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "######################''@$$$$$$-$'*************',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###################'''''@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "==#######========#'****'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "==================='''='@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;=======;;;;;;;;======'@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;;;''@@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";.;;;;;;;;;;;;;;;;;;;;;'*'''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ".,.;;;;;;,,,,,,,,;;;;;;'**',**',,,,,,**','**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",.,,,,,,,,,,,,,,,,,,,,,''',,''',,,,,,''',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + }, + { + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,", + ">>,,,,,,,>>>>>>>>,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++&&&&&&&++++++++&&&&&&'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++++++++++++++++++++++'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++++++++++++++++++++++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "##+++++++########++++++'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "#####################'''@$$$$$$-$'*************',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###################''**'@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "==#######========##****'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "=================='*'=='@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;=======;;;;;;;;=='==='@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;;;''@@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;;'**'''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,;;;;;;;,,,,,,,,;;;;;'**','*',,,,,,'*','**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,''',,,'',,,,,,,'',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + }, + { + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,>>>>>>>,,,,,,,,>>>>>>>''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$''$-$$@','',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&+++++++&&&&&&&&+++++'@$$$$$$$$'**'$$$@''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++++++++++++++++++++++'@$$$$$-$$'***$$$@'***',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++++++++++++++++++'''++'@$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++#######+++++++'**''''@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "#################'****''@$$$$$$-'*************',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "##################''''*'@$-$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###=======########==='''@$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "======================='@@$$$-$$'*%%********%%',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "===;;;;;;;========;;;;''@@@$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;''''@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;'***'''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;,,,,,,,;;;;;;;;,,'**','**,,,,,,'**,'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,''',,,'',,,,,,,'',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + }, + { + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,>>>>>>>,,,,,,,,>>>>>>>''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$''$$$@@','',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$'**'-$$@''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&+++++++&&&&&&&&+++++'@$$$$$$$$'***$$$@'***',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++++++++++++++++++'+++'@$$$$$-$$'***''''****',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++++++++++++++++++'*'++'@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++#######++++++++'*''''@$$$$$$$'*************',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###################****'@$$$$$$-'***.'****.'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###################''**'@$-$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###=======########==='''@$$$$$$$'*%%********%%',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "======================='@@$$$-$$$'***''''''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "===;;;;;;;========;;;;''@@@$$$$$$$'*********',,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;'*''@@@@@@@@@@''''''''',,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;'***''''''''''''''''*',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;,,,,,,,;;;;;;;;,,'**','**,,,,,,'**,'**',,,,,,,,,,,,,,,,,,..,.,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,''',,''',,,,,,''',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + }, + { + ".,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ".,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,..,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>,,,,,,,>>>>>>>>,,,,,,,'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$''$-$$@','',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$$$$$$$'**'$$$@''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++&&&&&&&++++++++&'''&&'@$$$$$-$$'***$$$@'***',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++++++++++++++++++'*''+'@$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++++++++++++++++++'**'''@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "##+++++++########++'**''@$$$$$$-'*************',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###################''**'@$-$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "####################''''@$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "==#######========#####''@@$$$-$$'*%%********%%',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "======================='@@@$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;=======;;;;;;;;====='''@@@@@@@@@'*********',,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;'***''''''''''''''''''',,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;'**'','*',,,,,'**,'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,;;;;;;;,,,,,,,,;;;;'''',,'',,,,,,,'',,'',,,,,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + }, + { + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>,,,,,,,>>>>>>>>,,,,,,,'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++&&&&&&&++++++++&&&&&&'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++++++++++++++++++'+++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++++++++++++++++++'*'++'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "##+++++++########+'*''''@$$$$$$-$'*************',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###################****'@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###################''**'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "==#######========####'''@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "======================='@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;=======;;;;;;;;======''@@@@@@@@@@'*********',,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;;'**'''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;;'**','*',,,,,,**','**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,;;;;;;;,,,,,,,,;;;;;''',,,'',,,,,,''',,''',,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + }, + { + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,..,...,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,>>>>>>>,,,,,,,,>>>>>>>''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&+++++++&&&&&&&&+++++'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++++++++++++++++++++++'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++++++++++++++++++++++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++#######++++++++#####'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "######################''@$$$$$$-$'*************',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###################'''''@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###=======########'****'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "==================='''='@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "===;;;;;;;========;;;;;'@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;;;''@@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;;;'*'''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;,,,,,,,;;;;;;;;,,,,,'**',**',,,,,,**'.'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,''',,''',,,,,,''',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,", + }, + { + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,>>>>>>>,,,,,,,,>>>>>>>''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&+++++++&&&&&&&&+++++'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++++++++++++++++++++++'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++++++++++++++++++++++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++#######++++++++#####'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "#####################'''@$$$$$$-$'*************',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###################''**'@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###=======########=****'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "=================='*'=='@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "===;;;;;;;========;';;;'@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;;;''@@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;;'**'''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;,,,,,,,;;;;;;;;,,,,'**','*',,..,.**','**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,''',,,'',,,,.,''',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + }, + { + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ".,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ".,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>,,,,,,,>>>>>>>>,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$''$-$$@','',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++&&&&&&&++++++++&&&&&&'@$$$$$$$$'**'$$$@''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++++++++++++++++++++++'@$$$$$-$$'***$$$@'***',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++++++++++++++++++'''++'@$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "##+++++++########'**''''@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "#################'****''@$$$$$$-'*************',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "##################''''*'@$-$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "==#######========####'''@$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "======================='@@$$$-$$'*%%********%%',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;=======;;;;;;;;=====''@@@$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;;''''@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;'***'''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,;;;;;;;,,,,,,,,;;;'**'.'**..,,,,'**''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,''',,,'',,,,,,,''',''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ".,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + }, + { + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>,,,,,,,>>>>>>>>,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ">>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$''$$$@@','',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$'**'-$$@''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++&&&&&&&++++++++&&&&&&'@$$$$$$$$'***$$$@'***',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "+++++++++++++++++++'+++'@$$$$$-$$'***''''****',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "++++++++++++++++++'*'++'@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "##+++++++########+'*''''@$$$$$$$'*************',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###################****'@$$$$$$-'***.'****.'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "###################''**'@$-$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "==#######========####'''@$$$$$$$'*%%********%%',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + "======================='@@$$$-$$$'***''''''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;=======;;;;;;;;=.===''@@@$$$$$$$'*********',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;.'*''@@@@@@@@@@''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ";;;;;;;;;;;;;;;;;;;;'***''''''''''''''''*',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,;;;;;;;,,,,,,,.;;;'**','**,,,,,,'**''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,''',,''',,,,,,''',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", + } +} + +local colors = { + [","] = 0x00005f, -- Blue background + ["."] = 0xffffff, -- White stars + ["'"] = 0x000000, -- Black border + ["@"] = 0xffffd7, -- Tan poptart + ["$"] = 0xd787af, -- Pink poptart + ["-"] = 0xd70087, -- Red poptart + [">"] = 0xff0000, -- Red rainbow + ["&"] = 0xffaf00, -- Orange rainbow + ["+"] = 0xffff00, -- Yellow Rainbow + ["#"] = 0x87ff00, -- Green rainbow + ["="] = 0x0087ff, -- Light blue rainbow + [";"] = 0x0000af, -- Dark blue rainbow + ["*"] = 0x585858, -- Gray cat face + ["%"] = 0xd787af -- Pink cheeks +} + +buffer.clear() +buffer.draw(true) + +local sizeX,sizeY = 80, 50 +while true do + for frame=1, #nyans do + for y=1, sizeY do + for x=1, sizeX do + local pos = (y <= sizeX and x <= sizeX) and string.sub(nyans[frame][y], x, x) or "," + buffer.square(x * 2 - 1, y, 2, 1, colors[pos], 0x0, " ") + end + end + buffer.draw() + local eventType = event.pull(0) + if eventType == "touch" or eventType == "key_down" then + return + end + end +end \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/XCOM.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/XCOM.lua new file mode 100755 index 00000000..843ed011 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/System/Screensavers/XCOM.lua @@ -0,0 +1,29 @@ + +local image = require("image") +local buffer = require("doubleBuffering") +local event = require("event") + +local source = image.fromString([[402A000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⣄000B00⢤001600⣤281700⣤001700⣤281C00⣤004C00⣤284D00⣤004C00⣤004700⣤001C00⣤004700⣤284C00⣤057800⣤287700⣤287700⣤004700⣤287800⣤004C00⣤065200⡤287700⣤287700⣤284D00⣤287700⣤285200⣤057700⣤284C00⣤284700⣤004700⣤284C00⣤284700⣤004700⣤281C00⣤001700⣤004700⣤001700⣤001700⣤001700⣤001600⣤000600⠄000000⠀002800⡀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⢀002800⢂000600⡐061C00⢂0B2100⣒002200⠒282200⠒281C00⠗281C00⠖281C00⠗282100⠲287D00⠚287D00⠒287D00⠚28A900⠒284D00⠒282100⠛062200⠒285200⠒285200⠒065200⠒285200⠒06A900⠒28A900⠓067D00⠚285200⠒287D00⠒067D00⠒287D00⠒285200⠒055200⠒282200⠒285200⠒282200⠒282200⠒282100⠚285200⠒285200⠒005200⠒0B5200⢒061C00⣒001000⣊000600⠂002800⢐000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠠002800⠠000100⠠280B00⢼065200⠤0B5200⠭000600⠡280600⢤000600⠥280600⠱002100⣤000600⠘004D00⢠000B00⠧280600⢕004700⢠001C00⡄280600⠥000600⡧001700⢠285200⡤007D00⢤001100⡄280B00⢥280600⠍284D00⠤280600⠧000600⠭004C00⢠004700⡄280600⠵280600⠥000600⠇002200⣠005200⠤001700⡄280600⠱000600⠬000600⠬000600⡔001700⠨0C7D00⠤292100⡅000600⠄000600⠄002800⠆000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⣘000100⠐000600⣨281700⢀0B2200⣘004C00⡃000600⣘000600⣐285200⠒000600⣃004D00⠘067D00⣀005200⠃000600⣊280600⣃004D00⢘001C00⡃280600⣋000600⡒117D00⢂004700⡀004D00⢀284C00⡄000600⣊000600⡃0B5200⣐280600⡃000600⣃285200⢘004D00⡂000B00⣃000600⣓001C00⢸005200⣃000B00⣂285200⣘001600⠇005200⠐004700⠂000600⣓000600⡙0BA900⢚0B7D00⣃280B00⣣000600⠐000600⡀002800⡂000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠄002800⠦000100⠄000600⢦067D00⠤0B7D00⠤000B00⠣000600⡲280600⠴000600⠱000600⠢000600⠢004700⠉000600⠦000600⠢000600⡢001600⠈281600⠁000600⠦000600⠕001100⠈004700⠉001700⠉000B00⠵000600⠔000600⠔001700⠈280600⠔000600⠦001700⠈284C00⠉000C00⠁000600⠢000600⠢004700⠈051C00⠉004100⠁000600⠪000600⠢000600⠧280600⠣000600⠦007700⠸16A900⠤004D00⠄000600⠤000600⠠002800⠠002800⠁000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⢀000600⢀000600⢐000C00⢀065200⣀1CA900⣈007800⡃000600⣜280600⣪005200⢠284D00⡞005200⠙284C00⠛000600⣏004D00⢀067D00⡞007D00⠛067D00⢣285200⡀050B00⣝117D00⣑007D00⣄0B7D00⣘280B00⣍000600⣇067D00⢸06A900⣋004700⡁000600⣍285200⢘284C00⡇280600⣝003C00⢸297D00⡟004C00⠛007D00⣄280600⢑004D00⢀285200⡜005200⠙282100⢳004C00⡄280600⣏001100⠈11A900⢉11A900⣁281100⡄000600⡄000100⠂000100⡀002800⠂000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⢢000100⢀000600⢂281100⠰064D00⠴0B4D00⡶000B00⠳280600⠶280600⡶001100⠘007D00⠶004C00⠤005200⠶280B00⢾001100⠘007D00⠶004D00⠤007D00⠶281100⠣280B00⣶064D00⠶051700⠘067D00⠶280B00⣷280B00⣶064D00⠰004100⠇050B00⣷280B00⣶064C00⠰051C00⠇280600⡶001100⠸067800⠦004D00⠴004D00⠇000600⣲001100⠘005200⠶001C00⠤005200⠶280C00⠃000600⢖000600⠧281C00⠸112100⠷281700⡦000600⡂000600⠂002800⠆002800⠂000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⡨002800⡭000600⢅000600⢦064D00⢨17A900⣭28A900⡅280B00⣼280B00⣽007D00⢠00A900⣠007D00⣀007D00⣄007D00⣤287D00⣤287D00⣤287D00⣤287D00⣤287D00⣤287D00⣤287D00⣤067D00⣀287D00⣤287D00⣤287D00⣤287D00⣤28A900⣀287D00⣤287D00⣤287D00⣠287D00⣤287D00⣤284D00⣤287D00⣤284D00⣄004D00⣄284D00⣄004D00⣤005200⣄007D00⣄004D00⣤007D00⣄005200⣠280B00⡭050600⡯001100⠈0C5200⢩0B5200⣭281100⡅000600⢈000600⠈002800⡌000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⢐000600⠐000100⡈000600⢆280B00⣓06A900⣲16D400⡒001100⠃280B00⣷050B00⣷000C00⡘06A900⠳11A900⡒117D00⡒117D00⢒117D00⢒16A900⠒16A900⡒16A900⡒16A900⠒16A900⢒11A900⢒117D00⡒16A900⢒16A900⠒16A900⢒16A900⢒16A900⠒16A900⢒16A900⠒16A900⡒117D00⠒11A900⠒117D00⠒117D00⠒115200⡒114D00⡒105200⣒114D00⡒0B5200⣒114C00⢒107D00⠒0C5200⡒004700⠃280600⣺280B00⡲000600⣃00A900⢐117D00⡒281C00⣆000600⣒000600⢐000100⠐002800⠠000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠬000600⠔000600⠥000600⣭284D00⢨1CD400⢭29D400⡍000B00⣽280C00⢭060B00⠭060B00⡭000C00⣭06A900⠹16A900⡭16A900⠭16A900⡭16A900⢭1CA900⡭16A900⠭16A900⠭16A900⠭16A900⢭16A900⠭16A900⢭16A900⢭16A900⠭16A900⠭16A900⠭16A900⠭16A900⠭11A900⠭11A900⠭11A900⠭11A900⠭11A900⠭117D00⠭0B7D00⣭117D00⠭117D00⠭117D00⠭0B4D00⣭067D00⡭007800⠁280B00⣭280B00⣭280B00⣭280B00⢽004100⠈17A900⢭0BA900⣥000B00⡭000600⠤000600⠠000100⠁002800⢀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⡘000600⡀000600⡣280B00⣒281C00⣐0CD400⣐47D400⡒004100⣓061100⣒281100⣚060C00⢐281100⣒281100⣒051100⣓067700⠘16A900⢒1CA900⣒1CA900⣒17A900⣛1CA900⣒17A900⣒16A900⣒16A900⣒17A900⣒16A900⣒16A900⣓16A900⣒16A900⣒11A900⢒16A900⣒16A900⣒11A900⣒11A900⣒117D00⣒117D00⣒117D00⣒117D00⣒0C7D00⣒11A900⣒117D00⣒11A900⣒28A900⠛280B00⣳280B00⣳280B00⣓280B00⣗280B00⣳280B00⣻280C00⣀287D00⢘17A900⣒287800⡂280B00⣇000600⣃000600⢂000500⡀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠠000600⠠000600⠨280600⠮281100⠤0B7D00⢤4CFF00⠤06D400⡇11FF00⠠06D400⣤061600⡬061600⠤061100⠥061100⠬061100⠬061100⠬067200⠈06A900⠽16A900⠭16A900⠭16A900⠭16A900⠭17A900⠭17A900⠭16A900⠭17A900⠭41A900⠭3CA900⠭107D00⠯0B2100⠭0CA900⠭16A900⠬16A900⠭16A900⠭16A900⠭16A900⠬16A900⠭167D00⠭11A900⠥117D00⠭117D00⠬287700⠏050B00⣽280B00⢯280B00⡯280B00⡯050B00⣯280B00⡿004700⢠06A900⠼067200⡌16D400⠭11D400⠤281600⠤280600⠤000600⠅000100⠄002800⠄000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⣘000600⣈000600⣚280B00⣻054700⢚17D400⣘21D700⣛0BA900⣁4CD400⣓21D400⣛6DD400⣓0BD400⣀061700⣛061700⣓061600⣓061100⣓291100⣛061100⣚28A400⠛16A900⣛16A900⣛16A900⣛16A900⣛16A900⣛16A900⣛16A900⣛17A900⣂16A900⣀0BA900⣀0B4D00⣛11A900⣀16A900⣀16A900⣚16A900⣛16A900⣛16A900⣛11A900⣛11A900⣛11A900⣛0B7D00⡛284700⠃060B00⣓280B00⣻280B00⣻280B00⣻060C00⢀284D00⢀06D400⣐11A900⣛11A900⣛11D400⣃29A900⢸1CD400⣛067D00⣂280B00⣏000600⣃000600⢑002800⢑000000⠀000000⠀000000⠀000000⠀000000⠀002800⠠002800⠲000600⠦280600⡺281100⠴287D00⢴4CD400⠤0BD400⠇11D400⢼4CA900⠶4CD400⠤4CA900⠴4CA900⠾0BD400⣶0B4C00⡄061600⠶061100⠦061100⠦291100⠴061100⠤284700⠹11A900⠶16A900⠤16A900⠤16A900⠦16A900⠤17A900⠦16A900⠴16A900⠤117D00⠦0C7800⠴117D00⠶117D00⠴16A900⠴16A900⠤167D00⠴16A900⠤167D00⠦117D00⠦287800⠏281100⠵060B00⠴280B00⢿280B00⢿060B00⠴000C00⠖285200⢰0C7D00⠶167D00⠶16A900⠴167D00⠦16A900⠶064700⡮117D00⠿0B7D00⠧280C00⠦280600⠦000600⠢000600⠠002800⠂000000⠀000000⠀000000⠀000000⠀002800⢬000600⢡050600⣹050C00⣈061C00⣉1CD400⣸4CD400⣉16A900⣉7CD400⣉51D400⣉4CD400⣉77D400⣉77D400⣉51D400⣉51D400⣉11D400⣄0B7D00⡀0B1700⣍0B1100⣩0B1100⣉0B1100⣍067D00⠈11A900⢩47A900⣉47A900⣉47A900⣉47A900⣉47A900⣉47A900⣉17A900⣉1CA900⣉1CA900⣉17A900⣉47A900⣉1CA900⣉42A900⣉47A900⣉1CA900⣉28A900⠋061100⡁061100⡁060C00⢀060C00⢁060C00⠁06A900⣀11A900⣜47A900⣉1CA900⣉47A900⣉47A900⣉47A900⣉47D400⣉11D400⣁11A900⢉47A900⣉067D00⣁050B00⣯280600⣋000100⢌000500⠂002800⢀000000⠀000000⠀002800⠐000100⠐000600⡒280600⡶281100⢲067800⢲4DA900⠖11D400⠗0BA900⣾4CA900⠶4CA900⠶7CA900⠖4CA900⠶16A900⠺4CA900⠶21D400⠶1CA900⠶16D400⠶067D00⣆061600⠶061100⠲061100⠒061100⠒061100⠆06A900⠲17A900⠖16A900⠖17A900⠖177D00⠖16A900⠖16A900⠶167D00⠶167D00⠖16A900⠖16A900⠖16A900⠖16A900⠖0B7D00⠶061700⠃281100⠶280C00⠶060B00⠶280C00⠶064200⢀287D00⡶17A900⠲16A900⠲16A900⠖16A900⠶0BA900⠲1CA900⠶17A900⢶1CA900⠶1CD400⠶064C00⡖17D400⠶0BA900⡶290C00⠄280600⡖000600⠆000600⠂002800⠂000000⠀000000⠀002800⡡000600⡡000600⢭060B00⡨064700⢨17D400⣨78D400⡭16A900⢭4DD400⣭4CD400⢭4CD400⠭4CD400⠍17D400⡍16A900⣭16D400⢍47D400⠭4CD400⠍1CD400⣭1CD400⣭16A900⣧06A900⣄061700⢭061100⡭061600⡭061100⣭06D400⠉16A900⢭16A900⣭16A900⣭16D400⣭16A900⣭1BA900⣭17A900⣭16A900⣭16A900⣭16A900⣭0BA900⡍294700⠁061100⡉291100⡡061100⣁061100⢉287D00⣤16A900⣬16A900⣭16A900⣭17D400⠭16D400⠉11D400⠉105200⣭17D400⠉47D400⠩4CD400⢩4DD400⣩0BD400⣏11D700⢹1CD400⣍067800⣅061100⡀280600⡭000600⠌000100⠄002800⠄002800⠐000600⠐000600⡘280B00⣲061600⠐0B7D00⢲47D400⣖16D400⡓10D400⣲4CD400⠒4CD400⠒4CD400⠒17D400⡒16D400⣒16A900⡒16D400⣒17D400⡒1CD400⣒1CD400⠒1CD400⣒1CD400⢒1CD400⢒06D400⣖067200⡒061600⣒061600⣒281600⢒064700⠘0CA900⠒16A900⢒16A900⢒16A900⢒16A900⠒16A900⢒16A900⠒16A900⡒06A900⠒061100⠒061100⠒061100⠒061100⠒287700⣀0BD400⢒16A900⢒16A900⡒16A900⠒16A900⢒16D400⠒11D400⣒11A900⡖117D00⠒11D400⣖16D400⣒4CD400⠒4CD400⠒47D400⣒0B5200⡚21D700⠒0BD400⣖281700⣂280B00⣗000600⢓000100⠐002800⡐002800⠬000600⠌000600⡬280B00⣯061700⠬11D700⢬51D400⠭117D00⠭4CD400⠭4CD400⠭4CD400⠭4CD400⠭4CD400⠭4CD400⠭1CD400⠭51D400⠭4CD400⠭4CD400⠭4CD400⠭21D400⠭1CD400⠭1CD400⡭1CD400⠭6DD400⠥06D400⠤061600⠭061600⠭051100⣭284700⠬06A900⠹0B7D00⠯0B7D00⠭0BA900⠩0B7D00⠽067D00⠽287D00⠉061100⠬051100⠭291100⠭281C00⠩0BA900⠤16A900⠭16A900⠭16A900⢭1BD400⠭1CA900⠭1CD400⠭1CA900⠭1CD400⠭47D400⠭17D400⠬4CD400⠭47D400⠭4CD400⠭4CD400⠭4CD400⠭0BD400⡥11D400⠽1CD400⠭287800⡥051100⡅280600⠥000600⠅000100⠄002800⣚000600⣊280600⣺281100⣒28A900⢐77D400⣒16D400⡗11D400⣲4CD400⣒4CD400⣒4CD400⣒4CD400⣒4CD400⣒4DD400⣒4CD400⣒21D400⣓17D400⣓41D400⣛1CA900⣛1CD400⣚1CD400⣒1CD400⣐11A900⣖11D400⣒11A900⣲0CA900⣒06D400⣀281100⣛061100⣒061100⡂28A900⠙16A900⢒17A900⣒06A900⡛281600⠃051100⣚061100⡒287700⢀06A900⣰11D400⣒0CD400⣐0BA900⣒0C7D00⣢16D400⣀11D400⣀117800⣛11A900⣛11D400⣛11D400⡚17D400⠒4CD400⢒1CD400⣒1CD400⣒4CD400⣒4CD400⣒1CD400⣛47D400⣒0B7800⣚4CD400⣒0BD400⣂061600⡀280600⣓000600⣃000100⠁000600⠠000600⡢280B00⡯061700⠤11D700⢴4CD400⠤117D00⠥4CD400⠤47D400⠬16D400⠭16D400⠿1CD400⠭17D400⠤1CD400⠤11D400⠿1CD400⠭42D400⠤1CD400⠬1CD400⠬16D400⠭11A900⠯41D400⠤1CD400⠭17D400⠤1CD400⠤1CD400⠬17A900⠬06D400⠦281700⡄280C00⠥050C00⠥287700⠈004C00⠏003600⡽060B00⠬280C00⠭287D00⢠11A900⠬16A900⠬16A900⠤16A900⠤16A900⠬11A900⠤11A900⠬0BA900⠯11D400⠭11D400⠤11D400⠤11A900⠭0C7D00⠵0CD400⠤16D400⠤11A900⠭167D00⠽0CA900⠿11D400⠭17D400⠬0BD400⡥0BD400⠽47D400⠤064D00⠄280B00⡯000600⠦000600⠂000600⣈050600⣺281100⣙0BA900⣀4DD700⣛17D700⡋0BA900⣛16D400⣉47D400⣁72D400⣀4DD400⣐1CA900⣓17D400⣁72D400⣒4CD400⣐47D400⣒47D400⣒47D400⣒72D400⣐11A900⣛1CD400⣒47D400⣒1CA900⣀1CD400⣀16A900⣀11A900⣀11A900⣈10A900⣉367D00⣉064C00⣄280B00⣻280B00⣻280B00⣛050B00⣻281700⢠0B7800⣌37A900⣉0BA900⣉11A900⣀11A900⣀16A900⣀16A900⣀16A900⣀17A900⣀11A900⣂0B7D00⣐42A900⣐42D400⣀17A900⣒42D400⣐47D400⣒42D400⣀11A900⣐1CA900⣒47D400⣀1CD400⣀16D400⣈0BD400⣋067800⣙21D400⣛11D400⣃064C00⡀280600⣙000600⡐000600⠰280B00⡺281700⢴0BA900⢾1CA900⠷0B7800⠧1CD400⠾4CA900⠶4CD400⠤11A900⠿16A900⢤17A900⢶4CA900⠶4CA900⠶4CA900⠶4CA900⠶4CA900⠶47A900⠶17A900⠦0BA900⠶1CA900⠶1CA900⠶11A900⠶06A900⠷0B7700⠿114700⢋0B4D00⡥0B7D00⠤287D00⠶281700⠂280B00⢾280B00⠾000B00⠾280B00⠷280B00⡾007800⠲067D00⠦0B7800⡤0B4700⣍0B4C00⠚067800⠾06A900⠶117D00⠶167D00⠦0CA900⠦064700⠴16A900⠶16A900⠶16A900⠶1BA900⠴1CA900⠶1CA900⠦21A900⠶0BD400⠦0B7D00⠿16A900⠶17A900⠶4CD400⠤06A900⡆0BD400⢸16A900⠶064C00⠆280600⡶000600⠢280600⣩061000⢨0B7800⢩4CD400⣉47D400⡉11A900⣹4CD400⣉7CD400⣉17D400⣍16A900⣩4DD400⣉4CD400⣉4CD400⣉4CD400⣉77D400⣉77D400⣉7CD400⣉4CD400⣉1CD400⡍11A900⣉11A900⡉11A900⣥1CA900⣄47A900⣉1CA900⣉42A900⣉1CA900⡉06A900⠋061100⡁060B00⣩280B00⣟00A900⣠0BA900⣤284700⡀060B00⣉060B00⣅285200⠈0B7D00⢫16A900⣉17A900⣉47A900⣉41A900⣀0CA900⣤0B7D00⡍0B7800⣁117D00⡈1CA900⠉1CA900⣍1CA900⣉1CA900⣩47D400⣉4CD400⣉4CD400⣉47D400⣉17D400⣁11A900⡉47D400⢉4CD400⣉1CD400⣍0BA900⢈47D400⣉11A900⣁281100⡇280600⡍280600⠲281100⠶06A900⢸21D400⠲0B7D00⠗11D400⣾21A900⢶47D400⠖107D00⠲17A900⢲4CD400⠒4CA900⢶21D400⡶17D400⠒1CD400⠒47A900⠒16A900⣶11A900⣶1CD400⠖1CA900⠲0CA900⡶067800⣦0B1C00⡛06A900⠓067D00⠶06A900⠖281100⡳060B00⠶280C00⢲281100⢂007800⣴117D00⠒117D00⠒0B7D00⣶004700⣄280B00⢷280C00⢖050B00⣾064D00⠐067D00⠶287D00⠖064D00⠊064700⣀28A400⣴11A900⠖11A900⠶0BA900⣶0B7D00⣶114800⣶115200⡒11A900⠒11A900⠶1CA900⠲1CA900⠒1CA900⠲067D00⡖0B7D00⠺21D400⠖21D400⠲287700⡆0BA900⢲11A900⣶051600⡆280600⠖280B00⢩061100⠨42D400⢭4CD400⠭06A900⣌11FF00⠩21D400⣭1CD400⣭0B7D00⣭16D400⠭17D400⠉11D400⣩16A900⣭4CD400⡭4CD400⢭21D400⣭21D400⢭4CD400⠭21D400⣭17A900⣭16A900⣭1CD400⠭17A900⣭0BA900⡥051100⣭061100⡁061100⡁060C00⡡281100⣭067D00⠈0BA900⠉0BA900⠉0BA900⠉0BA900⠉0BA900⠉281100⣯061100⠁280C00⣭060C00⢁280C00⣭064700⠸16A900⣬11A900⣭16A900⣭16A900⣭1CA900⣭1CA900⣭1CD400⡭1CD400⡭16D400⣭1CA900⣭11A900⣤0B7D00⣭0BA900⡍11D400⠉067D00⠍0BA900⢨1CD400⣭0CD400⡭06D400⢉06A900⣬1CD400⡭067D00⡅000B00⡭000600⠂280B00⡳281100⠺06D400⠛1CD400⢒0BD400⣷0CA900⣌067D00⢛0CA900⣔0B5200⣒41D700⢒4CD400⡒4CD400⡒4CD400⡒1CD400⣒47D400⢒1CD400⣒1CD400⢒1CD400⡒1CD400⡒17A900⣒11D400⡒017D00⠃061100⡒061100⠒061100⠐281100⣒057800⣐11A900⣒11A900⣒117D00⣒117D00⡒16A900⣒11A900⣒16A900⣒16A900⣒06A900⣒287200⡐060C00⡀061100⠂281100⣒281100⣚067D00⠳16A900⣒16A900⡒16A900⡒16A900⣒16A900⣒16A900⣒16A900⣒1CD400⢒1CD400⡒1CD400⣒17A900⡒06A900⠒0BA400⢀0B7D00⡀284D00⢛06A900⣴1CD400⣒11D400⠒065200⠃280600⡒000600⡂000100⠈000600⠌000B00⠭281100⠩067200⠈0BD400⠩42D400⠭17D400⠥06D400⡍0BD400⠧067D00⣭11D400⠩11D400⠽21D400⠭21D400⠭1CD400⠭1CD400⠭17A900⠭1BA900⠭1BA900⠭06A900⠏287200⠩051100⢭060C00⠅050C00⡭281100⢭06A900⣤117D00⠭11A900⠭11A900⠭117D00⠭16A900⠭16A900⠭16A900⠭16A900⠭16A900⠭16A900⠭16A900⠥284C00⡄061100⠨290C00⠈060B00⠭060C00⠄287D00⠉0BA900⠭117D00⠭11A900⠭16A900⠭16A900⠭16A900⠭17A900⠭41A900⠭06A900⠏06A400⠁28D400⡤28A900⠏28A900⡤1CD400⠬11A900⠭28A300⠍004700⠉280600⠍000600⠅000100⠄002800⠈002800⢊000600⡑000600⡑000B00⣚280C00⠙061700⠛06A900⠛16A900⣛0BA900⣓01D400⣘11D400⢲0BD400⣀067D00⣛0BA900⠛17D400⠒1CA900⣚16A900⣚0BA900⡛284C00⠃281100⣚280C00⣛280C00⣚060C00⠐287D00⢀0BA900⣚11A900⣓11A900⣓11A900⣒11A900⣒11A900⣒11A900⣒11A900⣚11A900⣒16A900⣓11A900⣒11A900⣓11A900⣒16A900⣓06A900⣂001100⣓060B00⣓280B00⣻280B00⣟280C00⡂007D00⠛11A900⢒117D00⣒114D00⡛0BA900⠚287700⠛01A900⣀0B7D00⣰28A900⢛067D00⣐117D00⣚0B7D00⡚064C00⠛280B00⣛000B00⢛000600⠘000100⢈000100⠈002800⠐000000⠀000000⠀002800⠠002800⠱000100⠐000600⠌000600⠭280B00⠻287200⠩287D00⠿16D400⠬06A900⣦067D00⡝28D400⠿0CA900⠦06A900⣤286D00⡬287700⠉060B00⠵060B00⠭280B00⡿060B00⠥280B00⠿284C00⣠117D00⠤117D00⠤167D00⠤117D00⠤16A900⠤16A900⠤11A900⠤117D00⠤167D00⠤11A900⠤117D00⠤16A900⠤16A900⠤117D00⠤16A900⠤117D00⠬287D00⢦281100⡄280B00⡯280B00⡯280B00⢯280B00⠯284700⠈284700⠉281600⣠067D00⠤0B7D00⠶007700⠟005200⠡0CA900⠤06A900⠯284700⠏001100⠍000600⠄000600⠅000100⠐002800⠡000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠁000600⠁000600⠑000600⡉000600⡫280B00⣛067D00⠈06A900⠛16A900⣙067D00⣆28A900⡙00A900⠋061100⠁060C00⠈280B00⣻280B00⣻060B00⣊061100⢀067D00⣀284C00⣉287D00⠉067D00⠙06A900⠛0BA900⠛0C7D00⠛0BA400⠛0C7D00⠛0C7D00⠛117D00⠛0C7D00⠛0B7800⣛0C7D00⠛0B7D00⠛067D00⡛067D00⠛287D00⠛284D00⣉064C00⣁052200⡀050B00⣟280B00⣏050600⣻280B00⣹280B00⣛001C00⠈004D00⠛287D00⣁0C5200⣚104D00⣛295200⠋281700⠃000600⢑000600⠈000100⠐002800⠑000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠠002800⠂000600⠂000600⠊000600⠲281100⠑281600⠞064C00⠳115200⠶284D00⢦001100⡀280B00⠾280B00⡿280B00⡷281100⢠287800⠶117800⠶117800⠶117800⠶117800⠶107800⠶0B4D00⠶0B7800⠶0B4D00⠶0B4D00⠶067800⠶0B7800⠶0B7800⡶0B7800⠶0B7800⠶0B7800⠶0B4D00⠶0B4D00⠶117800⠶117800⠶114700⠶0C4C00⠶001C00⡆280B00⠷050600⢷280600⠲000600⠗001700⣠004D00⠶064C00⠷281700⠟000B00⠯000600⠒002800⠜000100⠄002800⠂002800⠂000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠁000100⠈000500⠁000600⢉000B00⢈000C00⠙285200⠉065200⢩165200⣁005200⣤281100⡉285200⢠167D00⣌167D00⣉167D00⣉16A900⣉16A900⣉167D00⣉167D00⣉167D00⣉167D00⣉16A900⣉16A900⣉16A900⣉16A900⣉16A900⣉17A900⣉167D00⣉167D00⣉167D00⣉167D00⣉167D00⣉167D00⣉115200⣍115200⣩112700⣉285200⣄280B00⡝005200⢠067D00⣼167D00⡉065200⠋281C00⠋000600⠈000600⡀000100⠁002800⠁002800⠂000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠠002800⠐002800⠪000600⠂000600⠳281C00⠘067D00⠲0B7D00⠒004700⣆007D00⠲117D00⠒117D00⠒114D00⠒117D00⠒117D00⠒117D00⠒117D00⠒11A900⠒11A900⠒11A900⠒11A900⠒11A900⠒11A900⠒117D00⠒117D00⠒117D00⠒117D00⠒117D00⠒11A900⠒117D00⠒0C7D00⠒117D00⠒007D00⠖001700⣃002200⣶0C2100⠒281C00⠗001100⠓002800⡚002800⠖000100⠂000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠈002800⠈000600⠈000600⠈000600⠡001100⠉067D00⠉365200⢭0C5200⣥284D00⣌067D00⠩0B5200⣭0C7D00⢭115200⣭115200⢭105200⣭117D00⠭117D00⠭11A900⢭11A900⠭117D00⠭117D00⠭0C7D00⡭117D00⠭117D00⠭0B7D00⣭117D00⠭117D00⠭117D00⠭067D00⡭007D00⠉284D00⣤0B4D00⣭0B2100⠍001C00⠉000600⠩002800⠩000600⠈002800⠈000000⠀002800⠁000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠂000100⠂000100⠂000600⠊000B00⡺064C00⠐0B2200⢒065200⣒004D00⣀065200⠒117D00⢒117D00⣒117D00⣒0B5200⣒0C5200⣒0C4D00⣒107D00⣒117D00⣒11A900⣒117D00⣒117D00⠒117D00⣒117D00⣒117D00⣒067D00⡲005200⢃284C00⣰117D00⡒285200⠒001600⠓000600⢂000600⠂000100⠂002800⠐000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠂000600⠡000600⠠000B00⠈001100⠈064C00⠩0C5200⠭065200⠤004700⡌284200⠩284700⠉284700⠉064700⠉064700⠉064C00⠉067800⠉067700⠉054800⠉282100⠉284700⠉284700⠉284100⠉285200⠤0B5200⠬065200⠍004700⠉000B00⠅000600⠅000100⠄002800⠈002800⠈000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠐002800⠈002800⠚000100⠂000600⠊284100⠘064700⢛0B1C00⣛052100⣃002200⡐012100⢲0B5200⣒064D00⣒0B5200⣒065200⣒064D00⣒0B4D00⣒0B5200⡒002100⢒285200⣀0B2100⣚0B1C00⡓281700⠛000600⠉000100⠐000500⠂002800⠊000000⠀002800⠂000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠈002800⠠000100⠈000500⠈000B00⠌001100⠹0B1700⠽061C00⠿281C00⠦004200⡙002100⠿062200⠦0B5200⠶115200⠤004C00⠟001C00⠡281C00⠾061C00⠿004100⠯000B00⠍002900⡵000100⠄000100⠂000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠂000100⠂000600⠁001100⠈281100⠻0B1C00⠙101C00⣛001C00⣆281C00⡙284D00⠛005200⣡064D00⣜0B2200⣁291700⡛004700⠁000600⠁000100⢀002800⠐000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠠002800⠐002800⠔000B00⠺284100⠰291C00⠶061C00⠶001700⠶0B1C00⠶281600⠟001100⠋000600⠁002800⠰000000⠀002800⠄000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀002800⠈002800⠈002800⡉000600⠁001600⠉001700⠉291C00⠝001600⠋000600⠉000600⠁002800⢉002800⠈000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀000000⠀]]) + +local width, height, scale, scaleMod = image.getWidth(source), image.getHeight(source), 1, 0.1 +local targetMinimalScale, scaledWidth = 2 / width, width +local bufferWidth, bufferHeight = buffer.getResolution() + +while true do + local transformed = image.transform(source, math.ceil(width * scale), height) + buffer.clear(0x0) + buffer.image(math.floor(bufferWidth / 2 - image.getWidth(transformed) / 2), math.floor(bufferHeight / 2 - image.getHeight(transformed) / 2), transformed) + buffer.draw() + + scale = scale - scaleMod + if scale < targetMinimalScale then + scale, scaleMod = targetMinimalScale, -scaleMod + elseif scale > 1.0 then + scale, scaleMod = 1.0, -scaleMod + end + + local eventType = event.pull(0) + if eventType == "touch" or eventType == "key_down" then + break + end +end diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Config.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Config.cfg new file mode 100644 index 00000000..a1f22da7 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Config.cfg @@ -0,0 +1 @@ +{["toLanguage"]="Украинский",["fromLanguage"]="Грузинский",["APIKey"]="",["languages"]={[30]={[1]="is",[2]="Исландский"},[1]={[1]="az",[2]="Азербайджанский"},[7]={[1]="af",[2]="Африкаанс"},[31]={[1]="es",[2]="Испанский"},[32]={[1]="it",[2]="Итальянский"},[33]={[1]="kk",[2]="Казахский"},[34]={[1]="kn",[2]="Каннада"},[8]={[1]="eu",[2]="Баскский"},[35]={[1]="ca",[2]="Каталанский"},[36]={[1]="ky",[2]="Киргизский"},[37]={[1]="zh",[2]="Китайский"},[38]={[1]="ko",[2]="Корейский"},[9]={[1]="ba",[2]="Башкирский"},[39]={[1]="xh",[2]="Коса"},[40]={[1]="km",[2]="Кхмерский"},[41]={[1]="lo",[2]="Лаосский"},[42]={[1]="la",[2]="Латынь"},[10]={[1]="be",[2]="Белорусский"},[43]={[1]="lv",[2]="Латышский"},[44]={[1]="lt",[2]="Литовский"},[45]={[1]="lb",[2]="Люксембургский"},[2]={[1]="sq",[2]="Албанский"},[11]={[1]="bn",[2]="Бенгальский"},[47]={[1]="mg",[2]="Малагасийский"},[48]={[1]="ms",[2]="Малайский"},[49]={[1]="ml",[2]="Малаялам"},[50]={[1]="mt",[2]="Мальтийский"},[12]={[1]="my",[2]="Бирманский"},[51]={[1]="mi",[2]="Маори"},[52]={[1]="mr",[2]="Маратхи"},[53]={[1]="mhr",[2]="Марийский"},[54]={[1]="mn",[2]="Монгольский"},[13]={[1]="bg",[2]="Болгарский"},[55]={[1]="de",[2]="Немецкий"},[56]={[1]="ne",[2]="Непальский"},[57]={[1]="no",[2]="Норвежский"},[58]={[1]="pa",[2]="Панджаби"},[14]={[1]="bs",[2]="Боснийский"},[59]={[1]="pap",[2]="Папьяменто"},[60]={[1]="fa",[2]="Персидский"},[61]={[1]="pl",[2]="Польский"},[3]={[1]="am",[2]="Амхарский"},[15]={[1]="cy",[2]="Валлийский"},[63]={[1]="ro",[2]="Румынский"},[64]={[1]="ru",[2]="Русский"},[65]={[1]="ceb",[2]="Себуанский"},[16]={[1]="hu",[2]="Венгерский"},[67]={[1]="si",[2]="Сингальский"},[68]={[1]="sk",[2]="Словацкий"},[69]={[1]="sl",[2]="Словенский"},[17]={[1]="vi",[2]="Вьетнамский"},[71]={[1]="su",[2]="Сунданский"},[72]={[1]="tl",[2]="Тагальский"},[73]={[1]="tg",[2]="Таджикский"},[18]={[1]="ht",[2]="Гаитянский"},[75]={[1]="ta",[2]="Тамильский"},[76]={[1]="tt",[2]="Татарский"},[4]={[1]="en",[2]="Английский"},[19]={[1]="gl",[2]="Галисийский"},[79]={[1]="udm",[2]="Удмуртский"},[80]={[1]="uz",[2]="Узбекский"},[81]={[1]="uk",[2]="Украинский"},[20]={[1]="nl",[2]="Голландский"},[83]={[1]="fi",[2]="Финский"},[84]={[1]="fr",[2]="Французский"},[85]={[1]="hi",[2]="Хинди"},[21]={[1]="mrj",[2]="Горномарийский"},[87]={[1]="cs",[2]="Чешский"},[88]={[1]="sv",[2]="Шведский"},[89]={[1]="gd",[2]="Шотландский (гэльский)"},[22]={[1]="el",[2]="Греческий"},[91]={[1]="et",[2]="Эстонский"},[92]={[1]="jv",[2]="Яванский"},[5]={[1]="ar",[2]="Арабский"},[23]={[1]="ka",[2]="Грузинский"},[24]={[1]="gu",[2]="Гуджарати"},[25]={[1]="da",[2]="Датский"},[46]={[1]="mk",[2]="Македонский"},[26]={[1]="he",[2]="Иврит"},[62]={[1]="pt",[2]="Португальский"},[86]={[1]="hr",[2]="Хорватский"},[6]={[1]="hy",[2]="Армянский"},[27]={[1]="yi",[2]="Идиш"},[66]={[1]="sr",[2]="Сербский"},[70]={[1]="sw",[2]="Суахили"},[74]={[1]="th",[2]="Тайский"},[28]={[1]="id",[2]="Индонезийский"},[77]={[1]="te",[2]="Телугу"},[78]={[1]="tr",[2]="Турецкий"},[82]={[1]="ur",[2]="Урду"},[29]={[1]="ga",[2]="Ирландский"},[90]={[1]="eo",[2]="Эсперанто"},[93]={[1]="ja",[2]="Японский"}}} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/HEX-copy.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/HEX-copy.app/Main.lua new file mode 100644 index 00000000..f9020c55 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/HEX-copy.app/Main.lua @@ -0,0 +1,380 @@ + +require("advancedLua") +local bit32 = require("bit32") +local fs = require("filesystem") +local GUI = require("GUI") +local buffer = require("doubleBuffering") +local unicode = require("unicode") +local MineOSInterface = require("MineOSInterface") + +------------------------------------------------------------------------------------------------------------------ + +local colors = { + background = 0xF0F0F0, + backgroundText = 0x555555, + panel = 0x2D2D2D, + panelText = 0x999999, + panelSeleciton = 0x444444, + panelSelecitonText = 0xE1E1E1, + selectionFrom = 0x990000, + selectionTo = 0x990000, + selectionText = 0xFFFFFF, + selectionBetween = 0xD2D2D2, + selectionBetweenText = 0x000000, + separator = 0xCCCCCC, + titleBackground = 0x990000, + titleText = 0xFFFFFF, + titleText2 = 0xE1E1E1, +} + +local bytes = {} +local offset = 0 +local selection = { + from = 1, + to = 1, +} + +local scrollBar, titleTextBox + +------------------------------------------------------------------------------------------------------------------ + +local mainContainer, window = MineOSInterface.addWindow(MineOSInterface.filledWindow(1, 1, 98, 25, colors.background)) + +window.backgroundPanel.localX, window.backgroundPanel.localY = 11, 5 +window.backgroundPanel.width, window.backgroundPanel.height = window.width - 10, window.height - 4 + +local function status() + titleTextBox.lines[1] = "Selected byte" .. (selection.from == selection.to and "" or "s") .. ": " .. selection.from .. "-" .. selection.to + titleTextBox.lines[2].text = "UTF-8: \"" .. string.char(table.unpack(bytes, selection.from, selection.to)) .. "\"" + titleTextBox.lines[3].text = "INT: " .. bit32.byteArrayToNumber({table.unpack(bytes, selection.from, selection.to)}) +end + +local function byteFieldDraw(object) + local x, y, index = object.x, object.y, 1 + offset + local xCount, yCount = math.ceil(object.width / object.elementWidth), math.ceil(object.height / object.elementHeight) + + for j = 1, yCount do + for i = 1, xCount do + if bytes[index] then + local textColor = colors.backgroundText + if index == selection.from or index == selection.to then + buffer.square(x - object.offset, y, object.elementWidth, 1, index == selection.from and colors.selectionFrom or colors.selectionTo, colors.selectionText, " ") + textColor = colors.selectionText + elseif index > selection.from and index < selection.to then + buffer.square(x - object.offset, y, object.elementWidth, 1, colors.selectionBetween, colors.selectionText, " ") + textColor = colors.selectionBetweenText + end + + buffer.text(x, y, textColor, object.asChar and string.char(bytes[index]) or string.format("%02X", bytes[index])) + else + return object + end + + x, index = x + object.elementWidth, index + 1 + end + + local lastLineIndex = index - 1 + if lastLineIndex >= selection.from and lastLineIndex < selection.to then + buffer.square(object.x - object.offset, y + 1, object.width, 1, colors.selectionBetween, colors.selectionText, " ") + end + + x, y = object.x, y + object.elementHeight + end + + return object +end + +local function byteFieldEventHandler(mainContainer, object, eventData) + if eventData[1] == "touch" or eventData[1] == "drag" then + if eventData[5] == 1 then + local menu = GUI.contextMenu(eventData[3], eventData[4]) + + menu:addItem("Select all").onTouch = function() + selection.from = 1 + selection.to = #bytes + + mainContainer:draw() + buffer.draw() + end + menu:addSeparator() + menu:addItem("Edit").onTouch = function() + local container = MineOSInterface.addUniversalContainer(mainContainer, "Fill byte range [" .. selection.from .. "; " .. selection.to .. "]") + + local input = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, string.format("%02X" , bytes[selection.from]), "Type byte value")) + input.onInputFinished = function(text) + local number = tonumber("0x" .. input.text) + if number and number >= 0 and number <= 255 then + for i = selection.from, selection.to do + bytes[i] = number + end + + container:delete() + mainContainer:draw() + buffer.draw() + end + end + + mainContainer:draw() + buffer.draw() + end + menu:addItem("Insert").onTouch = function() + local container = MineOSInterface.addUniversalContainer(mainContainer, "Insert bytes at position " .. selection.from .. "") + + local input = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, "", "Type byte values separated by space", true)) + local switch = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x1E1E1E, 0xE1E1E1, 0xBBBBBB, "Select inserted bytes:", true)).switch + + input.onInputFinished = function() + if input.text:match("[a-fA-F%d%s]+") then + local insertionPosition, count = selection.from, 0 + for word in input.text:gmatch("[^%s]+") do + local number = tonumber("0x" .. word) + if number > 255 then number = 255 end + table.insert(bytes, insertionPosition + count, number) + selection.from, selection.to, count = selection.from + 1, selection.to + 1, count + 1 + end + + if switch.state then + selection.from, selection.to = insertionPosition, insertionPosition + count - 1 + end + + container:delete() + mainContainer:draw() + buffer.draw() + end + end + + mainContainer:draw() + buffer.draw() + end + menu:addSeparator() + menu:addItem("Delete").onTouch = function() + for i = selection.from, selection.to do + table.remove(bytes, selection.from) + end + if #bytes == 0 then + selection.from, selection.to = 1, 1 + else + selection.to = selection.from + end + end + menu:show() + else + local index = (math.ceil((eventData[4] - object.y + 1) / 2) - 1) * 16 + math.ceil((eventData[3] - object.x + 1 + object.offset) / object.elementWidth) + offset + + if bytes[index] then + if eventData[1] == "touch" then + selection.to = index + selection.from = index + selection.touchIndex = index + else + if not selection.touchIndex then selection.touchIndex = index end + + if index < selection.touchIndex then + selection.from = index + selection.to = selection.touchIndex + elseif index > selection.touchIndex then + selection.to = index + selection.from = selection.touchIndex + end + end + + status() + mainContainer:draw() + buffer.draw() + end + end + elseif eventData[1] == "scroll" then + offset = offset - 16 * eventData[5] + if offset < 0 then + offset = 0 + elseif offset > math.floor(#bytes / 16) * 16 then + offset = math.floor(#bytes / 16) * 16 + end + scrollBar.value = offset + + mainContainer:draw() + buffer.draw() + end +end + +local function newByteField(x, y, width, height, elementWidth, elementHeight, asChar) + local object = GUI.object(x, y, width, height) + + object.elementWidth = elementWidth + object.elementHeight = elementHeight + object.offset = asChar and 0 or 1 + object.asChar = asChar + object.draw = byteFieldDraw + object.eventHandler = byteFieldEventHandler + + return object +end + +------------------------------------------------------------------------------------------------------------------ + +window:addChild(GUI.panel(1, 1, window.width, 3, 0x3C3C3C)):moveToBack() + +local byteField = window:addChild(newByteField(13, 6, 64, 20, 4, 2, false)) +local charField = window:addChild(newByteField(byteField.localX + byteField.width + 3, 6, 16, 20, 1, 2, true)) +local separator = window:addChild(GUI.object(byteField.localX + byteField.width, 5, 1, 21)) +separator.draw = function(object) + for i = object.y, object.y + object.height - 1 do + buffer.text(object.x, i, colors.separator, "│") + end +end + + +window:addChild(GUI.panel(11, 4, window.width - 10, 1, colors.panel)) + +-- Vertical +local verticalCounter = window:addChild(GUI.object(1, 4, 10, window.height - 3)) +verticalCounter.draw = function(object) + buffer.square(object.x, object.y, object.width, object.height, colors.panel, colors.panelText, " ") + + local index = offset + for y = 2, object.height - 1, 2 do + local textColor = colors.panelText + + if index > selection.from and index < selection.to then + buffer.square(object.x, object.y + y - 1, object.width, 2, colors.panelSeleciton, colors.panelSelecitonText, " ") + textColor = colors.panelSelecitonText + end + + if selection.from >= index and selection.from <= index + 15 or selection.to >= index and selection.to <= index + 15 then + buffer.square(object.x, object.y + y, object.width, 1, colors.selectionFrom, colors.selectionText, " ") + textColor = colors.selectionText + end + + buffer.text(object.x + 1, object.y + y, textColor, string.format("%08X", index)) + + index = index + 16 + end +end + +-- Horizontal +window:addChild(GUI.object(13, 4, 62, 1)).draw = function(object) + local counter = 0 + local restFrom, restTo = selection.from % 16, selection.to % 16 + for x = 1, object.width, 4 do + local textColor = colors.panelText + if counter + 1 > restFrom and counter + 1 < restTo then + buffer.square(object.x + x - 2, object.y, 4, 1, colors.panelSeleciton, colors.selectionText, " ") + textColor = colors.panelSelecitonText + elseif restFrom == counter + 1 or restTo == counter + 1 then + buffer.square(object.x + x - 2, object.y, 4, 1, colors.selectionFrom, colors.selectionText, " ") + textColor = colors.selectionText + end + + buffer.text(object.x + x - 1, object.y, textColor, string.format("%02X", counter)) + counter = counter + 1 + end +end + +scrollBar = window:addChild(GUI.scrollBar(window.width, 5, 1, window.height - 4, 0xC3C3C3, 0x393939, 0, 1, 1, 160, 1, true)) +scrollBar.eventHandler = nil + +titleTextBox = window:addChild( + GUI.textBox( + 1, 1, math.floor(window.width * 0.35), 3, + colors.titleBackground, + colors.titleText, + { + "", + {text = "", color = colors.titleText2}, + {text = "", color = colors.titleText2} + }, + 1, 1, 0 + ) +) +titleTextBox.localX = math.floor(window.width / 2 - titleTextBox.width / 2) +titleTextBox:setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) +titleTextBox.eventHandler = nil + +local saveFileButton = window:addChild(GUI.adaptiveRoundedButton(titleTextBox.localX - 11, 2, 2, 0, colors.panel, colors.panelSelecitonText, colors.panelSelecitonText, colors.panel, "Save")) +local openFileButton = window:addChild(GUI.adaptiveRoundedButton(saveFileButton.localX - 11, 2, 2, 0, colors.panel, colors.panelSelecitonText, colors.panelSelecitonText, colors.panel, "Open")) + +------------------------------------------------------------------------------------------------------------------ + +local function load(path) + local file, reason = io.open(path, "rb") + + if file then + bytes = {} + local char + while true do + local char = file:read(1) + if char then + table.insert(bytes, string.byte(char)) + else + break + end + end + + file:close() + offset = 0 + selection.from, selection.to = 1, 1 + scrollBar.value, scrollBar.maximumValue = 0, #bytes + status() + else + GUI.error("Failed to open file for reading: " .. tostring(reason)) + end +end + +openFileButton.onTouch = function() + local filesystemDialog = GUI.addFilesystemDialogToContainer(mainContainer, "Open", "Cancel", "File name", "/") + filesystemDialog:setMode(GUI.filesystemModes.open, GUI.filesystemModes.file) + filesystemDialog:show() + filesystemDialog.onSubmit = function(path) + load(path) + mainContainer:draw() + buffer.draw() + end +end + +saveFileButton.onTouch = function() + local filesystemDialog = GUI.addFilesystemDialogToContainer(mainContainer, "Save", "Cancel", "File name", "/") + filesystemDialog:setMode(GUI.filesystemModes.save, GUI.filesystemModes.file) + filesystemDialog:show() + filesystemDialog.onSubmit = function(path) + local file = io.open(path, "wb") + if file then + for i = 1, #bytes do + file:write(string.char(bytes[i])) + end + file:close() + else + GUI.error("Failed to open file for writing: " .. tostring(reason)) + end + end +end + +window.actionButtons.localY = 2 +window.actionButtons.maximize.onTouch = function() + window.height = window.parent.height + byteField.height = window.height - 6 + charField.height = byteField.height + scrollBar.height = byteField.height + window.backgroundPanel.height = window.height - 4 + verticalCounter.height = window.backgroundPanel.height + 1 + separator.height = byteField.height + 2 + + window.localY = 1 + + mainContainer:draw() + buffer.draw() +end + +------------------------------------------------------------------------------------------------------------------ + +load("/bin/resolution.lua") +mainContainer:draw() +buffer.draw() + + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/HEX-copy.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/HEX-copy.app/Resources/Icon.pic new file mode 100644 index 00000000..46c7ddbe Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/HEX-copy.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/HEX.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/HEX.app/Main.lua new file mode 100644 index 00000000..f9020c55 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/HEX.app/Main.lua @@ -0,0 +1,380 @@ + +require("advancedLua") +local bit32 = require("bit32") +local fs = require("filesystem") +local GUI = require("GUI") +local buffer = require("doubleBuffering") +local unicode = require("unicode") +local MineOSInterface = require("MineOSInterface") + +------------------------------------------------------------------------------------------------------------------ + +local colors = { + background = 0xF0F0F0, + backgroundText = 0x555555, + panel = 0x2D2D2D, + panelText = 0x999999, + panelSeleciton = 0x444444, + panelSelecitonText = 0xE1E1E1, + selectionFrom = 0x990000, + selectionTo = 0x990000, + selectionText = 0xFFFFFF, + selectionBetween = 0xD2D2D2, + selectionBetweenText = 0x000000, + separator = 0xCCCCCC, + titleBackground = 0x990000, + titleText = 0xFFFFFF, + titleText2 = 0xE1E1E1, +} + +local bytes = {} +local offset = 0 +local selection = { + from = 1, + to = 1, +} + +local scrollBar, titleTextBox + +------------------------------------------------------------------------------------------------------------------ + +local mainContainer, window = MineOSInterface.addWindow(MineOSInterface.filledWindow(1, 1, 98, 25, colors.background)) + +window.backgroundPanel.localX, window.backgroundPanel.localY = 11, 5 +window.backgroundPanel.width, window.backgroundPanel.height = window.width - 10, window.height - 4 + +local function status() + titleTextBox.lines[1] = "Selected byte" .. (selection.from == selection.to and "" or "s") .. ": " .. selection.from .. "-" .. selection.to + titleTextBox.lines[2].text = "UTF-8: \"" .. string.char(table.unpack(bytes, selection.from, selection.to)) .. "\"" + titleTextBox.lines[3].text = "INT: " .. bit32.byteArrayToNumber({table.unpack(bytes, selection.from, selection.to)}) +end + +local function byteFieldDraw(object) + local x, y, index = object.x, object.y, 1 + offset + local xCount, yCount = math.ceil(object.width / object.elementWidth), math.ceil(object.height / object.elementHeight) + + for j = 1, yCount do + for i = 1, xCount do + if bytes[index] then + local textColor = colors.backgroundText + if index == selection.from or index == selection.to then + buffer.square(x - object.offset, y, object.elementWidth, 1, index == selection.from and colors.selectionFrom or colors.selectionTo, colors.selectionText, " ") + textColor = colors.selectionText + elseif index > selection.from and index < selection.to then + buffer.square(x - object.offset, y, object.elementWidth, 1, colors.selectionBetween, colors.selectionText, " ") + textColor = colors.selectionBetweenText + end + + buffer.text(x, y, textColor, object.asChar and string.char(bytes[index]) or string.format("%02X", bytes[index])) + else + return object + end + + x, index = x + object.elementWidth, index + 1 + end + + local lastLineIndex = index - 1 + if lastLineIndex >= selection.from and lastLineIndex < selection.to then + buffer.square(object.x - object.offset, y + 1, object.width, 1, colors.selectionBetween, colors.selectionText, " ") + end + + x, y = object.x, y + object.elementHeight + end + + return object +end + +local function byteFieldEventHandler(mainContainer, object, eventData) + if eventData[1] == "touch" or eventData[1] == "drag" then + if eventData[5] == 1 then + local menu = GUI.contextMenu(eventData[3], eventData[4]) + + menu:addItem("Select all").onTouch = function() + selection.from = 1 + selection.to = #bytes + + mainContainer:draw() + buffer.draw() + end + menu:addSeparator() + menu:addItem("Edit").onTouch = function() + local container = MineOSInterface.addUniversalContainer(mainContainer, "Fill byte range [" .. selection.from .. "; " .. selection.to .. "]") + + local input = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, string.format("%02X" , bytes[selection.from]), "Type byte value")) + input.onInputFinished = function(text) + local number = tonumber("0x" .. input.text) + if number and number >= 0 and number <= 255 then + for i = selection.from, selection.to do + bytes[i] = number + end + + container:delete() + mainContainer:draw() + buffer.draw() + end + end + + mainContainer:draw() + buffer.draw() + end + menu:addItem("Insert").onTouch = function() + local container = MineOSInterface.addUniversalContainer(mainContainer, "Insert bytes at position " .. selection.from .. "") + + local input = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, "", "Type byte values separated by space", true)) + local switch = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x1E1E1E, 0xE1E1E1, 0xBBBBBB, "Select inserted bytes:", true)).switch + + input.onInputFinished = function() + if input.text:match("[a-fA-F%d%s]+") then + local insertionPosition, count = selection.from, 0 + for word in input.text:gmatch("[^%s]+") do + local number = tonumber("0x" .. word) + if number > 255 then number = 255 end + table.insert(bytes, insertionPosition + count, number) + selection.from, selection.to, count = selection.from + 1, selection.to + 1, count + 1 + end + + if switch.state then + selection.from, selection.to = insertionPosition, insertionPosition + count - 1 + end + + container:delete() + mainContainer:draw() + buffer.draw() + end + end + + mainContainer:draw() + buffer.draw() + end + menu:addSeparator() + menu:addItem("Delete").onTouch = function() + for i = selection.from, selection.to do + table.remove(bytes, selection.from) + end + if #bytes == 0 then + selection.from, selection.to = 1, 1 + else + selection.to = selection.from + end + end + menu:show() + else + local index = (math.ceil((eventData[4] - object.y + 1) / 2) - 1) * 16 + math.ceil((eventData[3] - object.x + 1 + object.offset) / object.elementWidth) + offset + + if bytes[index] then + if eventData[1] == "touch" then + selection.to = index + selection.from = index + selection.touchIndex = index + else + if not selection.touchIndex then selection.touchIndex = index end + + if index < selection.touchIndex then + selection.from = index + selection.to = selection.touchIndex + elseif index > selection.touchIndex then + selection.to = index + selection.from = selection.touchIndex + end + end + + status() + mainContainer:draw() + buffer.draw() + end + end + elseif eventData[1] == "scroll" then + offset = offset - 16 * eventData[5] + if offset < 0 then + offset = 0 + elseif offset > math.floor(#bytes / 16) * 16 then + offset = math.floor(#bytes / 16) * 16 + end + scrollBar.value = offset + + mainContainer:draw() + buffer.draw() + end +end + +local function newByteField(x, y, width, height, elementWidth, elementHeight, asChar) + local object = GUI.object(x, y, width, height) + + object.elementWidth = elementWidth + object.elementHeight = elementHeight + object.offset = asChar and 0 or 1 + object.asChar = asChar + object.draw = byteFieldDraw + object.eventHandler = byteFieldEventHandler + + return object +end + +------------------------------------------------------------------------------------------------------------------ + +window:addChild(GUI.panel(1, 1, window.width, 3, 0x3C3C3C)):moveToBack() + +local byteField = window:addChild(newByteField(13, 6, 64, 20, 4, 2, false)) +local charField = window:addChild(newByteField(byteField.localX + byteField.width + 3, 6, 16, 20, 1, 2, true)) +local separator = window:addChild(GUI.object(byteField.localX + byteField.width, 5, 1, 21)) +separator.draw = function(object) + for i = object.y, object.y + object.height - 1 do + buffer.text(object.x, i, colors.separator, "│") + end +end + + +window:addChild(GUI.panel(11, 4, window.width - 10, 1, colors.panel)) + +-- Vertical +local verticalCounter = window:addChild(GUI.object(1, 4, 10, window.height - 3)) +verticalCounter.draw = function(object) + buffer.square(object.x, object.y, object.width, object.height, colors.panel, colors.panelText, " ") + + local index = offset + for y = 2, object.height - 1, 2 do + local textColor = colors.panelText + + if index > selection.from and index < selection.to then + buffer.square(object.x, object.y + y - 1, object.width, 2, colors.panelSeleciton, colors.panelSelecitonText, " ") + textColor = colors.panelSelecitonText + end + + if selection.from >= index and selection.from <= index + 15 or selection.to >= index and selection.to <= index + 15 then + buffer.square(object.x, object.y + y, object.width, 1, colors.selectionFrom, colors.selectionText, " ") + textColor = colors.selectionText + end + + buffer.text(object.x + 1, object.y + y, textColor, string.format("%08X", index)) + + index = index + 16 + end +end + +-- Horizontal +window:addChild(GUI.object(13, 4, 62, 1)).draw = function(object) + local counter = 0 + local restFrom, restTo = selection.from % 16, selection.to % 16 + for x = 1, object.width, 4 do + local textColor = colors.panelText + if counter + 1 > restFrom and counter + 1 < restTo then + buffer.square(object.x + x - 2, object.y, 4, 1, colors.panelSeleciton, colors.selectionText, " ") + textColor = colors.panelSelecitonText + elseif restFrom == counter + 1 or restTo == counter + 1 then + buffer.square(object.x + x - 2, object.y, 4, 1, colors.selectionFrom, colors.selectionText, " ") + textColor = colors.selectionText + end + + buffer.text(object.x + x - 1, object.y, textColor, string.format("%02X", counter)) + counter = counter + 1 + end +end + +scrollBar = window:addChild(GUI.scrollBar(window.width, 5, 1, window.height - 4, 0xC3C3C3, 0x393939, 0, 1, 1, 160, 1, true)) +scrollBar.eventHandler = nil + +titleTextBox = window:addChild( + GUI.textBox( + 1, 1, math.floor(window.width * 0.35), 3, + colors.titleBackground, + colors.titleText, + { + "", + {text = "", color = colors.titleText2}, + {text = "", color = colors.titleText2} + }, + 1, 1, 0 + ) +) +titleTextBox.localX = math.floor(window.width / 2 - titleTextBox.width / 2) +titleTextBox:setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) +titleTextBox.eventHandler = nil + +local saveFileButton = window:addChild(GUI.adaptiveRoundedButton(titleTextBox.localX - 11, 2, 2, 0, colors.panel, colors.panelSelecitonText, colors.panelSelecitonText, colors.panel, "Save")) +local openFileButton = window:addChild(GUI.adaptiveRoundedButton(saveFileButton.localX - 11, 2, 2, 0, colors.panel, colors.panelSelecitonText, colors.panelSelecitonText, colors.panel, "Open")) + +------------------------------------------------------------------------------------------------------------------ + +local function load(path) + local file, reason = io.open(path, "rb") + + if file then + bytes = {} + local char + while true do + local char = file:read(1) + if char then + table.insert(bytes, string.byte(char)) + else + break + end + end + + file:close() + offset = 0 + selection.from, selection.to = 1, 1 + scrollBar.value, scrollBar.maximumValue = 0, #bytes + status() + else + GUI.error("Failed to open file for reading: " .. tostring(reason)) + end +end + +openFileButton.onTouch = function() + local filesystemDialog = GUI.addFilesystemDialogToContainer(mainContainer, "Open", "Cancel", "File name", "/") + filesystemDialog:setMode(GUI.filesystemModes.open, GUI.filesystemModes.file) + filesystemDialog:show() + filesystemDialog.onSubmit = function(path) + load(path) + mainContainer:draw() + buffer.draw() + end +end + +saveFileButton.onTouch = function() + local filesystemDialog = GUI.addFilesystemDialogToContainer(mainContainer, "Save", "Cancel", "File name", "/") + filesystemDialog:setMode(GUI.filesystemModes.save, GUI.filesystemModes.file) + filesystemDialog:show() + filesystemDialog.onSubmit = function(path) + local file = io.open(path, "wb") + if file then + for i = 1, #bytes do + file:write(string.char(bytes[i])) + end + file:close() + else + GUI.error("Failed to open file for writing: " .. tostring(reason)) + end + end +end + +window.actionButtons.localY = 2 +window.actionButtons.maximize.onTouch = function() + window.height = window.parent.height + byteField.height = window.height - 6 + charField.height = byteField.height + scrollBar.height = byteField.height + window.backgroundPanel.height = window.height - 4 + verticalCounter.height = window.backgroundPanel.height + 1 + separator.height = byteField.height + 2 + + window.localY = 1 + + mainContainer:draw() + buffer.draw() +end + +------------------------------------------------------------------------------------------------------------------ + +load("/bin/resolution.lua") +mainContainer:draw() +buffer.draw() + + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/HEX.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/HEX.app/Resources/Icon.pic new file mode 100644 index 00000000..46c7ddbe Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/HEX.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Icon.pic new file mode 100755 index 00000000..1e0deecf Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Main.lua new file mode 100755 index 00000000..54d8705e --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Main.lua @@ -0,0 +1,413 @@ + +--8х4 +--Желтый 0xF7AF00 +--Зеленый 0x5C6A00 +--Бежевый 0XF9ED89 +--Фиолетовый 0x660080 +-- UP-119 down-115 left-97 right-100 fire-32 quit-13 pause-113 +local GUI = require("GUI") +local buffer = require("doubleBuffering") +local image = require("image") +local event = require("event") +local computer = require("computer") +local DisplayWidth,DisplayHeight = buffer.getResolution() +local fs=require("filesystem") +local Debug=1 +local MaxEnemyOnMap=3 +local EnemyCount=0 + +local PlayerMoveSide="none" +local Player1Lifes = 3 +local Player1Dead=false + +local mainContainer = GUI.fullScreenContainer() +mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x0)) + +local cyka = mainContainer:addChild(GUI.label(1,1,mainContainer.width,1,0xFFFFFF,"Код кавиши=..")) + +local BulletContainer = mainContainer:addChild(GUI.container(1, 1, mainContainer.width, mainContainer.height)) +local tanksContainer = mainContainer:addChild(GUI.container(1, 1, mainContainer.width, mainContainer.height)) +local mapComtainer = mainContainer:addChild(GUI.container(1, 1, mainContainer.width, mainContainer.height)) + +local function getRectangleIntersection(R1X1, R1Y1, R1X2, R1Y2, R2X1, R2Y1, R2X2, R2Y2) + return R2X1 <= R1X2 and R2Y1 <= R1Y2 and R2X2 >= R1X1 and R2Y2 >= R1Y1 +end + +local config={ + FPS=0, + FPSc=0, + ostime=os.time(), + work=true, + systemtick=false, + PathToRes=fs.path(getCurrentScript()) +} + +local function getTankIntersection(tank) + for i = 1, #tanksContainer.children do + local child = tanksContainer.children[i] + if child ~= tank then + if getRectangleIntersection( + tank.x-1, + tank.y-1, + tank.x + tank.width+1, + tank.y + tank.height+1, + child.x, + child.y, + child.x + child.width, + child.y + child.height + ) + then + return false + end + end + end + return true +end + +local function getBulletIntersection(bullet) -------ПЕРЕПОСССАТЬ + for i = 1, #tanksContainer.children do + local child = tanksContainer.children[i] + + if getRectangleIntersection( + bullet.x, + bullet.y, + bullet.x + bullet.width-1, + bullet.y + bullet.height-1, + child.x, + child.y, + child.x + child.width-1, + child.y + child.height-1 + ) and bullet.type ~= child.type then + tanksContainer.children[i]:delete() + if child.type=="friend" then + Player1Lifes=Player1Lifes-1 + Player1Dead=true + else + EnemyCount=EnemyCount-1 + end + return true + end + + end + for i = 1, #BulletContainer.children do + local child = BulletContainer.children[i] + + if getRectangleIntersection( + bullet.x, + bullet.y, + bullet.x + bullet.width-1, + bullet.y + bullet.height-1, + child.x, + child.y, + child.x + child.width-1, + child.y + child.height-1 + ) and bullet.type ~= child.type + then + BulletContainer.children[i]:delete() + --EnemyCount=EnemyCount-1 + return true + end + + end + return false +end + +local function newBullet(x, y, type, MoveSide) + local Pulya = GUI.object(x, y, 1, 1) + + Pulya.MoveSide = MoveSide + Pulya.type = type + Pulya.speed = 3 + -- Pulya.FriendModel = image.load(config.PathToRes.."Resources/Tanks/Bullet.pic") + + Pulya.draw = function() + --if Debug then buffer.text(Pulya.x,Pulya.y-1,0xFFFFFF,"Х="..Pulya.x.." У="..Pulya.y) end + -- buffer.image(Pulya.x, Pulya.y, Pulya.FriendModel) + buffer.text(Pulya.x, Pulya.y, 0xFF0000, "▄") + end + + Pulya.eventHandler = function(mainContainer,object,eventData) + + if Pulya.MoveSide == "UP" then + Pulya.localY = Pulya.localY - Pulya.speed + elseif Pulya.MoveSide == "DOWN" then + Pulya.localY = Pulya.localY + Pulya.speed + elseif Pulya.MoveSide == "RIGHT" then + Pulya.localX = Pulya.localX + Pulya.speed + elseif Pulya.MoveSide == "LEFT" then + Pulya.localX = Pulya.localX - Pulya.speed + end + + if getBulletIntersection(Pulya) then + Pulya:delete() + end + + if not (Pulya.x >= 1 and Pulya.x <= DisplayWidth and Pulya.y >= 1 and Pulya.y <= DisplayHeight) then + Pulya:delete() + end + end + + return Pulya +end + + +local function Player1(x,y) + + local MyFuckingTank = GUI.object(x,y,8,4) + + MyFuckingTank.Speed = 1 + MyFuckingTank.MoveSide = "UP" + MyFuckingTank.type = "friend" + + + MyFuckingTank.ModelMoveUp = image.load(config.PathToRes.."Resources/Textures/Player1Tank/Player1NewTankUP.pic") + MyFuckingTank.ModelMoveDown = image.load(config.PathToRes.."Resources/Textures/Player1Tank/Player1NewTankDOWN.pic") + MyFuckingTank.ModelMoveLeft = image.load(config.PathToRes.."Resources/Textures/Player1Tank/Player1NewTankLEFT.pic") + MyFuckingTank.ModelMoveRight = image.load(config.PathToRes.."Resources/Textures/Player1Tank/Player1NewTankRIGHT.pic") + + MyFuckingTank.Model = MyFuckingTank.ModelMoveUp + + + MyFuckingTank.draw = function(MyFuckingTank) + if MyFuckingTank.MoveSide == "UP" then + MyFuckingTank.Model = MyFuckingTank.ModelMoveUp + elseif MyFuckingTank.MoveSide == "DOWN" then + MyFuckingTank.Model = MyFuckingTank.ModelMoveDown + elseif MyFuckingTank.MoveSide == "RIGHT" then + MyFuckingTank.Model = MyFuckingTank.ModelMoveRight + elseif MyFuckingTank.MoveSide == "LEFT" then + MyFuckingTank.Model = MyFuckingTank.ModelMoveLeft + end + + buffer.frame(MyFuckingTank.x-1, MyFuckingTank.y-1 , MyFuckingTank.width + 2, MyFuckingTank.height + 2, 0xFFFFFF) + buffer.image(MyFuckingTank.x, MyFuckingTank.y, MyFuckingTank.Model) + + if Debug then buffer.text(1,2,0xFFFFFF,"Танк Х="..MyFuckingTank.x.." Танк У="..MyFuckingTank.y) end + buffer.text(1,3,0xFFFFFF,"EnemyCount="..EnemyCount.." MaxEnemyOnMap="..MaxEnemyOnMap) + end + + return MyFuckingTank +end + + +local function Enemy() + local x,y = 0,0 + local SpawnPoint = math.random(3) + local Huy={} + --Процедура умного спавна + if SpawnPoint==1 then + x=1 + y=1 + elseif SpawnPoint==2 then + x=DisplayWidth/2 + y=1 + elseif SpawnPoint==3 then + x=DisplayWidth - 7 + y=1 + end + + + local FuckingEnemy = GUI.object(x,y,8,4) + + + if getTankIntersection(FuckingEnemy) then + + FuckingEnemy.Speed = 1 + FuckingEnemy.MoveSide = "DOWN" + FuckingEnemy.MaxBullet = 2 + + FuckingEnemy.type = "enemy" + + FuckingEnemy.ModelMoveUp = image.load(config.PathToRes.."Resources/Textures/EnemyTank/EnemyTankUP.pic") + FuckingEnemy.ModelMoveDown = image.load(config.PathToRes.."Resources/Textures/EnemyTank/EnemyTankDOWN.pic") + FuckingEnemy.ModelMoveLeft = image.load(config.PathToRes.."Resources/Textures/EnemyTank/EnemyTankLEFT.pic") + FuckingEnemy.ModelMoveRight = image.load(config.PathToRes.."Resources/Textures/EnemyTank/EnemyTankRIGHT.pic") + + FuckingEnemy.Model = FuckingEnemy.ModelMoveUp + + local function ChangeMoveSide() + local ChangeSide = math.random(3) + local Sides={ + "UP", + "DOWN", + "LEFT", + "RIGHT" + } + + for i=1,#Sides do + if Sides[i] == FuckingEnemy.MoveSide then table.remove(Sides,i) break end + end + + FuckingEnemy.MoveSide = Sides[ChangeSide] + + end + + + FuckingEnemy.eventHandler = function(mainContainer,object,eventData) ---Мозги + if math.random(100) <= 5 then + BulletContainer:addChild(newBullet(FuckingEnemy.x + 3, FuckingEnemy.y + 1, "enemy",FuckingEnemy.MoveSide)) + end + + if math.random(100) <= 4 then + ChangeMoveSide() + end + end + + FuckingEnemy.draw = function() + + if FuckingEnemy.MoveSide == "UP" then + if FuckingEnemy.localY > 1 then + if getTankIntersection(FuckingEnemy) then + FuckingEnemy.localY = FuckingEnemy.localY - FuckingEnemy.Speed + else + FuckingEnemy.localY = FuckingEnemy.localY + FuckingEnemy.Speed + ChangeMoveSide() + end + else + ChangeMoveSide() + end + + FuckingEnemy.Model = FuckingEnemy.ModelMoveUp + + elseif FuckingEnemy.MoveSide == "DOWN" then + if FuckingEnemy.localY < DisplayHeight-3 then + if getTankIntersection(FuckingEnemy) then + FuckingEnemy.localY = FuckingEnemy.localY + FuckingEnemy.Speed + else + FuckingEnemy.localY = FuckingEnemy.localY - FuckingEnemy.Speed + ChangeMoveSide() + end + else + ChangeMoveSide() + end + + FuckingEnemy.Model = FuckingEnemy.ModelMoveDown + + elseif FuckingEnemy.MoveSide == "RIGHT" then + if FuckingEnemy.localX < DisplayWidth-8 then + if getTankIntersection(FuckingEnemy) then + FuckingEnemy.localX = FuckingEnemy.localX + FuckingEnemy.Speed + else + FuckingEnemy.localX = FuckingEnemy.localX - FuckingEnemy.Speed + ChangeMoveSide() + end + else + ChangeMoveSide() + end + + FuckingEnemy.Model = FuckingEnemy.ModelMoveRight + + elseif FuckingEnemy.MoveSide == "LEFT" then + + if FuckingEnemy.localX > 1 then + if getTankIntersection(FuckingEnemy) then + FuckingEnemy.localX = FuckingEnemy.localX - FuckingEnemy.Speed + else + FuckingEnemy.localX = FuckingEnemy.localX + FuckingEnemy.Speed + ChangeMoveSide() + end + else + ChangeMoveSide() + end + + FuckingEnemy.Model = FuckingEnemy.ModelMoveLeft + end + + buffer.image(FuckingEnemy.x, FuckingEnemy.y, FuckingEnemy.Model) + + end + + return FuckingEnemy + else + EnemyCount=EnemyCount-1 + return false + end + +end + + local function KeyPress(keycode,lable) --для дэбага, наверное + lable.text="Код клавиши="..keycode + if keycode == 113 or keycode == 1081 then --если нажали Q(81) или q(113) или й 1081 - выйти нахуй + config.work = false + end +end + +--Типа код---------------------------------------------------------------------------------------- + +local MyFTN = tanksContainer:addChild(Player1(50,20)) +mainContainer.eventHandler = function(mainContainer, object, eventData) + +if Player1Dead and Player1Lifes >= 1 then + Player1Dead=false + Player1Lifes=Player1Lifes-1 + MyFTN = tanksContainer:addChild(Player1(50,20)) +elseif Player1Lifes<=0 then + --GUI.error("Ты проебал!") + --mainContainer:stopEventHandling(0) +end + + +if EnemyCount < MaxEnemyOnMap then +EnemyCount=EnemyCount+1 + local Obj = Enemy() + if Obj==false then + + else + tanksContainer:addChild(Obj) + + end +end + local EvD=eventData + if EvD[1] == "key_down" then + if EvD[4] == 200 or EvD[4] == 17 then + PlayerMoveSide = "UP" + elseif EvD[4] == 208 or EvD[4] == 31 then + PlayerMoveSide = "DOWN" + elseif EvD[4] == 203 or EvD[4] == 30 then + PlayerMoveSide = "LEFT" + elseif EvD[4] == 205 or EvD[4] == 32 then + PlayerMoveSide = "RIGHT" + elseif EvD[4] == 57 then + if Player1Dead~=true then BulletContainer:addChild(newBullet(MyFTN.x + math.random(2)+2, MyFTN.y + 1, "friend",MyFTN.MoveSide)) end + elseif EvD[4] == 19 then + local Obj = Enemy() + if Obj==false then + else + tanksContainer:addChild(Obj) + EnemyCount=EnemyCount+1 + end + end + elseif EvD[1] == "key_up" then + PlayerMoveSide="none" + end + + if PlayerMoveSide == "UP" then + MyFTN.MoveSide = "UP" + if MyFTN.y > 1 then MyFTN.localY = MyFTN.y - MyFTN.Speed end + + elseif PlayerMoveSide == "DOWN" then + MyFTN.MoveSide = "DOWN" + if MyFTN.y < DisplayHeight-3 then MyFTN.localY = MyFTN.y + MyFTN.Speed end + + elseif PlayerMoveSide == "LEFT" then + MyFTN.MoveSide = "LEFT" + if MyFTN.x > 1 then MyFTN.localX = MyFTN.x - MyFTN.Speed*2 end + + elseif PlayerMoveSide == "RIGHT" then + MyFTN.MoveSide = "RIGHT" + if MyFTN.x < DisplayWidth-8 then MyFTN.localX = MyFTN.x + MyFTN.Speed*2 end + end + --KeyPress(EvD[4],cyka) + + buffer.clear(0x0) + mainContainer:draw() + buffer.draw() +end + +mainContainer:draw() +buffer.draw(true) +mainContainer:startEventHandling(0) + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Icon.pic new file mode 100755 index 00000000..b9bdf68c Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Bullet.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Bullet.pic new file mode 100755 index 00000000..e96b9108 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Bullet.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Enemy1Down.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Enemy1Down.pic new file mode 100755 index 00000000..a4e7a4ab Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Enemy1Down.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Enemy1Left.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Enemy1Left.pic new file mode 100755 index 00000000..401ba601 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Enemy1Left.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Enemy1Right.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Enemy1Right.pic new file mode 100755 index 00000000..3f32140d Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Enemy1Right.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Enemy1Up.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Enemy1Up.pic new file mode 100755 index 00000000..5d989fa4 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Enemy1Up.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Play1DOWN.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Play1DOWN.pic new file mode 100755 index 00000000..a4e7a4ab Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Play1DOWN.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Play1LEFT.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Play1LEFT.pic new file mode 100755 index 00000000..401ba601 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Play1LEFT.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Play1RIGHT.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Play1RIGHT.pic new file mode 100755 index 00000000..3f32140d Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Play1RIGHT.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Play1UP.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Play1UP.pic new file mode 100755 index 00000000..5d989fa4 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Tanks/Play1UP.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/EnemyTank/EnemyTankDOWN.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/EnemyTank/EnemyTankDOWN.pic new file mode 100755 index 00000000..f50fdefb Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/EnemyTank/EnemyTankDOWN.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/EnemyTank/EnemyTankLEFT.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/EnemyTank/EnemyTankLEFT.pic new file mode 100755 index 00000000..410d3b9f Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/EnemyTank/EnemyTankLEFT.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/EnemyTank/EnemyTankRIGHT.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/EnemyTank/EnemyTankRIGHT.pic new file mode 100755 index 00000000..0fc54cbb Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/EnemyTank/EnemyTankRIGHT.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/EnemyTank/EnemyTankUP.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/EnemyTank/EnemyTankUP.pic new file mode 100755 index 00000000..8f25b48f Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/EnemyTank/EnemyTankUP.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Map/Base.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Map/Base.pic new file mode 100755 index 00000000..3d1cca75 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Map/Base.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Map/Brick.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Map/Brick.pic new file mode 100755 index 00000000..ab6a244c Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Map/Brick.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Player1Tank/Player1NewTankDOWN.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Player1Tank/Player1NewTankDOWN.pic new file mode 100755 index 00000000..c8c161fe Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Player1Tank/Player1NewTankDOWN.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Player1Tank/Player1NewTankLEFT.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Player1Tank/Player1NewTankLEFT.pic new file mode 100755 index 00000000..ef4b1dc9 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Player1Tank/Player1NewTankLEFT.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Player1Tank/Player1NewTankRIGHT.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Player1Tank/Player1NewTankRIGHT.pic new file mode 100755 index 00000000..8eea1f0d Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Player1Tank/Player1NewTankRIGHT.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Player1Tank/Player1NewTankUP.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Player1Tank/Player1NewTankUP.pic new file mode 100755 index 00000000..84f96e78 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/LehaTanks.app/Resources/Textures/Player1Tank/Player1NewTankUP.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Sudoku.app/.icons b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Sudoku.app/.icons new file mode 100644 index 00000000..037b37a6 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Sudoku.app/.icons @@ -0,0 +1 @@ +{[".icons"]={["x"]=8,["y"]=11},["Main.lua"]={["x"]=17,["y"]=2},["Resources"]={["x"]=3,["y"]=2}} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Sudoku.app/Main.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Sudoku.app/Main.lua new file mode 100644 index 00000000..621bb86e --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Sudoku.app/Main.lua @@ -0,0 +1,147 @@ + +local component = require("component") +local buffer = require("doubleBuffering") +local event = require("event") +local color = require("color") +local unicode = require("unicode") +local GUI = require("GUI") +local MineOSCore = require("MineOSCore") + +-------------------------------------------------------------------------------------------- + +local cells = {} +for y = 1, 9 do + cells[y] = {} + for x = 1, 9 do + cells[y][x] = {value = nil, variants = {}} + end +end + +-------------------------------------------------------------------------------------------- + +local function getCellVariants(xCell, yCell) + for i = 1, 9 do + cells[yCell][xCell].variants[i] = true + end + if cells[yCell][xCell].value then + cells[yCell][xCell].variants[cells[yCell][xCell].value] = false + end + + for y = 1, 9 do + if y ~= yCell and cells[y][xCell].value then + cells[yCell][xCell].variants[cells[y][xCell].value] = false + end + end + + for x = 1, 9 do + if x ~= xCell and cells[yCell][x].value then + cells[yCell][xCell].variants[cells[yCell][x].value] = false + end + end + + local xCellGroup, yCellGroup = math.ceil(xCell / 3) * 3, math.ceil(yCell / 3) * 3 + for y = yCellGroup - 2, yCellGroup do + for x = xCellGroup - 2, xCellGroup do + if x ~= xCell and y ~= yCell and cells[y][x].value then + cells[yCell][xCell].variants[cells[y][x].value] = false + end + end + end +end + +local function getAllVariants() + for y = 1, 9 do + for x = 1, 9 do + getCellVariants(x, y) + end + end +end + +local function generate(count) + for i = 1, count do + local indexedVariants, xCell, yCell = {} + repeat + xCell, yCell = math.random(1, 9), math.random(1, 9) + for key, value in pairs(cells[yCell][xCell].variants) do + if value == true then + table.insert(indexedVariants, key) + end + end + until cells[yCell][xCell].value == nil and #indexedVariants > 1 + + + cells[yCell][xCell].value = indexedVariants[math.random(1, #indexedVariants)] + getAllVariants() + end +end + +-------------------------------------------------------------------------------------------- + +local mainContainer, window = MineOSCore.addWindow(GUI.filledWindow(1, 1, 71, 36, 0xEEEEEE)) + +local sudoku = window:addChild(GUI.object(1, 2, 71, 36)) +sudoku.colors = { + lines = { + thin = 0xAAAAAA, + fat = 0x000000 + } +} +sudoku.draw = function(sudoku) + local x, y = sudoku.x + 7, sudoku.y + 3 + + for i = 1, 8 do + buffer.text(sudoku.x, y, i % 3 == 0 and sudoku.colors.lines.fat or sudoku.colors.lines.thin, string.rep("─", sudoku.width)) + y = y + 4 + end + + for i = 1, 8 do + for j = sudoku.y, sudoku.y + sudoku.height - 1 do + local background, foreground, symbol = buffer.get(x, j) + if symbol == "─" then + symbol = "┼" + else + symbol = "│" + end + + buffer.set(x, j, background, i % 3 == 0 and sudoku.colors.lines.fat or sudoku.colors.lines.thin, symbol) + end + + x = x + 8 + end + + x, y = sudoku.x, sudoku.y + for yCell = 1, 9 do + for xCell = 1, 9 do + local xCyka, yCyka = x, y + for key, value in pairs(cells[yCell][xCell].variants) do + if value then + buffer.text(xCyka, yCyka, 0xBBBBBB, tostring(key)) + end + + xCyka = xCyka + 2 + if xCyka - x > 5 then + xCyka, yCyka = x, yCyka + 1 + end + end + + if cells[yCell][xCell].value then + buffer.text(x + 3, y + 1, 0x880000, tostring(cells[yCell][xCell].value)) + end + + x = x + 8 + end + + x, y = sudoku.x, y + 4 + end +end + +-- sudoku.eventHandler = function(mainContainer, object, eventData) +-- if eventData[1] == "touch" then +-- GUI.error(eventData) +-- end +-- end + +-------------------------------------------------------------------------------------------- + +getAllVariants() +generate(50) \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Sudoku.app/Resources/.icons b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Sudoku.app/Resources/.icons new file mode 100644 index 00000000..118a3645 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Sudoku.app/Resources/.icons @@ -0,0 +1 @@ +{["Icon.pic"]={["x"]=3,["y"]=2}} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Sudoku.app/Resources/Icon.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Sudoku.app/Resources/Icon.pic new file mode 100644 index 00000000..06a0bcaa Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/Sudoku.app/Resources/Icon.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/newApplicationInfoWidget b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/newApplicationInfoWidget new file mode 100644 index 00000000..41621843 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MineOS/Trash/newApplicationInfoWidget @@ -0,0 +1,1143 @@ + +require("advancedLua") +local component = require("component") +local computer = require("computer") +local web = require("web") +local GUI = require("GUI") +local buffer = require("doubleBuffering") +local MineOSCore = require("MineOSCore") +local MineOSPaths = require("MineOSPaths") +local MineOSInterface = require("MineOSInterface") +local image = require("image") +local fs = require("filesystem") +local color = require("color") +local unicode = require("unicode") + +-------------------------------------------------------------------------------- + +local host = "http://buttex.ru/mineos/appmarket/" +local luaIcon = image.load(MineOSPaths.icons .. "Lua.pic") +local scriptIcon = image.load(MineOSPaths.icons .. "Script.pic") +local appMarketPath = MineOSPaths.applicationData .. "AppMarket/" +local configPath = appMarketPath .. "Config.cfg" +local iconCachePath = appMarketPath .. "Cache/" + +local config = { + descriptionLanguage = "en", + orderBy = 1, + orderDirection = 1, +} + +local categories = { + "Приложения", + "Библиотеки", + "Скрипты", +} + +local orderDirections = { + "desc", + "asc", +} + +local licenses = { + "MIT", + "GNU GPLv3", + "GNU AGPLv3", + "GNU LGPLv3", + "Apache Licence 2.0", + "Mozilla Public License 2.0", + "The Unlicense", +} + +local orderBys = { + "average_rating", + "file_id", + "publication_name", +} + +local search = "" +local appWidth, appHeight, appHSpacing, appVSpacing, currentPage, appsPerPage, appsPerWidth, appsPerHeight = 34, 6, 2, 1 + +local updateFileList, editPublication + +-------------------------------------------------------------------------------- + +local function saveConfig() + table.toFile(configPath, config) +end + +local function loadConfig() + if fs.exists(configPath) then + config = table.fromFile(configPath) + else + saveConfig() + end +end + +-------------------------------------------------------------------------------- + +local function RawAPIRequest(script, postData, notUnserialize) + local url = host .. script .. ".php?" .. web.serialize(postData) + -- table.toFile("/test.txt", {url}) + local requestResult, requestReason = web.request(url) + if requestResult then + if not notUnserialize then + local unserializeResult, unserializeReason = table.fromString(requestResult) + if unserializeResult then + if unserializeResult.success then + return unserializeResult + else + return false, "API request not succeded: " .. tostring(unserializeResult.reason) + end + else + return false, "Failed to unserialize response data: " .. tostring(unserializeReason) .. ", the data was: " .. tostring(requestResult) + end + else + return result + end + else + return false, "Web request failed: " .. tostring(requestReason) + end +end + +local function fieldAPIRequest(fieldToReturn, ...) + local success, reason = RawAPIRequest(...) + if success then + if success[fieldToReturn] then + return success[fieldToReturn] + else + return false, "Request was successful, but field " .. tostring(fieldToReturn) .. " doesn't exists" + end + else + return false, reason + end +end + +local function checkImage(url) + local handle = component.internet.request(url) + if handle then + local _, _, responseData + repeat + _, _, responseData = handle:response() + until responseData + + local contentLength = tonumber(responseData["Content-Length"][1]) + if contentLength <= 10240 then + local data, chunk, reason = "" + while true do + chunk, reason = handle.read(math.huge) + if chunk then + data = data .. chunk + if #data > 8 then + if data:sub(1, 4) == "OCIF" then + if string.byte(data:sub(6, 6)) > 8 or string.byte(data:sub(7, 7)) > 4 then + handle:close() + return false, "Image size is larger than 8x4" + end + else + handle:close() + return false, "Wrong image file signature" + end + end + else + handle:close() + if reason then + return false, reason + else + return data + end + end + end + else + handle:close() + return false, "Specified image size is too big" + end + else + return false, "Invalid URL" + end +end + +-------------------------------------------------------------------------------- + +local mainContainer, window = MineOSInterface.addWindow(MineOSInterface.tabbedWindow(1, 1, 110, 30)) +local overrideWindowDraw = window.draw +window.draw = function(...) + overrideWindowDraw(...) + buffer.text(window.x, window.y + window.height, 0xFF0000, "Free RAM: " .. math.floor(computer.freeMemory() / 1024)) +end + +local contentContainer = window:addChild(GUI.container(1, 4, 1, 1)) +local statusWidget = window:addChild(GUI.object(1, 1, 1, 1)) +statusWidget.draw = function() + buffer.square(statusWidget.x, statusWidget.y, statusWidget.width, 1, 0x2D2D2D, 0xF0F0F0, " ") + buffer.text(statusWidget.x + 1, statusWidget.y, 0xF0F0F0, statusWidget.text) +end + +-------------------------------------------------------------------------------- + +local function status(text) + statusWidget.text = text + MineOSInterface.OSDraw() +end + +local function getAllDependencies(mainFileID, mainFileDependencies) + local allDependencies = {} + + local function getAllDependenciesRecursively(file_ids) + local list, reason = fieldAPIRequest("list", "list", { + file_ids = file_ids, + fields = { + "dependencies", + "publication_name", + "path", + "source_url" + } + }) + + if list then + local newDependenciesList = {} + + for i = 1, #list do + if not allDependencies[list[i].file_id] and list[i].file_id ~= mainFileID then + allDependencies[list[i].file_id] = list[i] + end + + if list[i].dependencies then + for j = 1, #list[i].dependencies do + if not allDependencies[list[i].dependencies[j]] and list[i].dependencies[j] ~= mainFileID then + table.insert(newDependenciesList, list[i].dependencies[j]) + end + end + end + end + + if #newDependenciesList > 0 then + getAllDependenciesRecursively(newDependenciesList) + end + else + GUI.error(reason) + end + end + + getAllDependenciesRecursively(mainFileDependencies) + + local result = {} + for key, value in pairs(allDependencies) do + table.insert(result, value) + allDependencies[key] = nil + end + + if #result > 0 then + return result + end +end + +local function ratingWidgetDraw(object) + local x = 0 + for i = 1, 5 do + buffer.text(object.x + x, object.y, object.rating >= i and object.colors.first or object.colors.second, "*") + x = x + object.spacing + end + + return object +end + +local function newRatingWidget(x, y, rating, firstColor, secondColor) + local object = GUI.object(x, y, 9, 1) + + object.colors = { + first = firstColor or 0xFFB600, + second = secondColor or 0xC3C3C3 + } + object.spacing = 2 + object.draw = ratingWidgetDraw + object.rating = rating + + return object +end + +-------------------------------------------------------------------------------- + +local function getApplicationIcon(category_id, dependencies) + if dependencies then + for i = 1, #dependencies do + if dependencies[i].path == "Resources/Icon.pic" then + local path = iconCachePath .. dependencies[i].file_id .. ".pic" + + if fs.exists(path) then + return image.load(path) + else + local data, reason = checkImage(dependencies[i].source_url) + if data then + local file = io.open(path, "w") + file:write(data) + file:close() + + return image.load(path) + else + GUI.error("Failed to download publication icon: " .. reason) + break + end + end + end + end + end + + if category_id == 2 then + return luaIcon + else + return scriptIcon + end +end + +local function addPanel(container, color) + container.panel = container:addChild(GUI.panel(1, 1, container.width, container.height, color or 0xFFFFFF)) +end + +local function addShit(container, application) + addPanel(container) + container.image = container:addChild(GUI.image(3, 2, application.icon)) + container.nameLabel = container:addChild(GUI.text(13, 2, 0x0, application.publication_name)) + container.versionLabel = container:addChild(GUI.text(13, 3, 0x666666, "©" .. application.user_name)) + container.rating = container:addChild(newRatingWidget(13, 4, application.average_rating or 0)) + container.downloadButton = container:addChild(GUI.adaptiveRoundedButton(13, 5, 1, 0, 0xBBBBBB, 0xFFFFFF, 0x888888, 0xFFFFFF, "Загрузить")) +end + +local function keyValueWidgetUpdate(object) + object.width = unicode.len(object.key .. object.value) +end + +local function keyValueWidgetDraw(object) + keyValueWidgetUpdate(object) + buffer.text(object.x, object.y, object.colors.key, object.key) + buffer.text(object.x + unicode.len(object.key), object.y, object.colors.value, object.value) +end + +local function newKeyValueWidget(x, y, keyColor, valueColor, key, value) + local object = GUI.object(x, y, 1, 1) + + object.colors = { + key = keyColor, + value = valueColor + } + object.key = key + object.value = value + + object.draw = keyValueWidgetDraw + keyValueWidgetUpdate(object) + + return object +end + +local function containerScrollEventHandler(mainContainer, object, eventData) + if eventData[1] == "scroll" then + local first, last = object.children[1], object.children[#object.children] + + if eventData[5] == 1 then + if first.localY < 2 then + for i = 1, #object.children do + object.children[i].localY = object.children[i].localY + 1 + end + MineOSInterface.OSDraw() + end + else + if last.localY + last.height - 1 >= object.height then + for i = 1, #object.children do + object.children[i].localY = object.children[i].localY - 1 + end + MineOSInterface.OSDraw() + end + end + end +end + +local function newApplicationInfoWidget(file_id) + status("Получение информации о приложении...") + + local info, reason = fieldAPIRequest("list", "list", { + file_ids = {file_id}, + fields = { + "publication_id", + "publication_name", + "average_rating", + "version", + "reviews", + "description", + "category_id", + "dependencies", + "user_name", + "license", + "timestamp", + }, + description_language = config.descriptionLanguage, + }) + + if info then + local application = info[1] + + if application.dependencies then + status("Построение древа зависимостей...") + application.dependencies = getAllDependencies(file_id, application.dependencies) + end + + contentContainer:deleteChildren() + + local infoContainer = contentContainer:addChild(GUI.container(1, 1, contentContainer.width, contentContainer.height)) + infoContainer.eventHandler = containerScrollEventHandler + + -- Жирный йоба-лейаут для отображения ВАЩЕ всего - и инфы, и отзыввов + local layout = infoContainer:addChild(GUI.layout(3, 2, infoContainer.width - 4, infoContainer.height, 1, 1)) + layout:setCellAlignment(1, 1, GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + + -- А вот эт уже контейнер чисто инфы крч + local detailsContainer = layout:addChild(GUI.container(3, 2, layout.width, 6)) + + -- Тут будут находиться ваще пизда подробности о публикации + local ratingsContainer = detailsContainer:addChild(GUI.container(1, 1, 26, 6)) + ratingsContainer.localX = detailsContainer.width - ratingsContainer.width + 1 + addPanel(ratingsContainer, 0xE1E1E1) + + -- Всякая текстовая пизда + local y = 2 + ratingsContainer:addChild(newKeyValueWidget(2, y, 0x2D2D2D, 0x888888, "Разработчик", ": " .. application.user_name)); y = y + 1 + ratingsContainer:addChild(newKeyValueWidget(2, y, 0x2D2D2D, 0x888888, "Лицензия", ": " .. application.license)); y = y + 1 + ratingsContainer:addChild(newKeyValueWidget(2, y, 0x2D2D2D, 0x888888, "Категория", ": " .. categories[application.category_id])); y = y + 1 + ratingsContainer:addChild(newKeyValueWidget(2, y, 0x2D2D2D, 0x888888, "Версия", ": " .. string.format("%.2f", application.version))); y = y + 1 + ratingsContainer:addChild(newKeyValueWidget(2, y, 0x2D2D2D, 0x888888, "Обновлено", ": " .. os.date("%d.%m.%Y", application.timestamp))); y = y + 1 + y = y + 1 + + -- Добавляем инфу с общими рейтингами + if application.reviews then + status("Формирование структуры отзывов...") + + local ratings = {0, 0, 0, 0, 0} + for i = 1, #application.reviews do + ratings[application.reviews[i].rating] = ratings[application.reviews[i].rating] + 1 + end + + ratingsContainer:addChild(newKeyValueWidget(2, y, 0x2D2D2D, 0x888888, "Средний рейтинг", ": " .. string.format("%.1f", application.average_rating or 0))); y = y + 1 + + for i = #ratings, 1, -1 do + local text = tostring(ratings[i]) + local textLength = #text + ratingsContainer:addChild(newRatingWidget(2, y, i, nil, 0xC3C3C3)) + ratingsContainer:addChild(GUI.progressBar(12, y, ratingsContainer.width - textLength - 13, 0x2D2D2D, 0xC3C3C3, 0xC3C3C3, ratings[i] / #application.reviews * 100, true)) + ratingsContainer:addChild(GUI.text(ratingsContainer.width - textLength, y, 0x2D2D2D, text)) + y = y + 1 + end + end + + -- Добавляем описание и прочую пизду + local textDetailsContainer = detailsContainer:addChild(GUI.container(1, 1, detailsContainer.width - ratingsContainer.width, detailsContainer.height)) + application.icon = getApplicationIcon(application.category_id, application.dependencies) + addShit(textDetailsContainer, application) + + local lines = string.wrap(info[1].description, textDetailsContainer.width - 4) + local textBox = textDetailsContainer:addChild(GUI.textBox(3, 7, textDetailsContainer.width - 4, #lines, nil, 0x888888, lines, 1, 0, 0)) + textBox.eventHandler = nil + + if application.dependencies then + local dependencyWithPublicationNameExists = false + for i = 1, #application.dependencies do + if application.dependencies[i].publication_name then + dependencyWithPublicationNameExists = true + break + end + end + + if dependencyWithPublicationNameExists then + local x, y = 3, textBox.localY + textBox.height + 1 + + textDetailsContainer:addChild(GUI.label(1, y, textDetailsContainer.width, 1, 0x666666, "Зависимости")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + y = y + 2 + + for i = 1, #application.dependencies do + local text = application.dependencies[i].publication_name or fs.name(application.dependencies[i].path) + if application.dependencies[i].publication_name then + local textLength = unicode.len(text) + if x + textLength + 4 > textDetailsContainer.width - 4 then + x, y = 3, y + 2 + end + local button = textDetailsContainer:addChild(GUI.roundedButton(x, y, textLength + 2, 1, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, text)) + button.onTouch = function() + newApplicationInfoWidget(application.dependencies[i].file_id) + end + x = x + button.width + 2 + end + end + end + end + + + textDetailsContainer.height = math.max( + textDetailsContainer.children[#textDetailsContainer.children].localY + textDetailsContainer.children[#textDetailsContainer.children].height, + ratingsContainer.children[#ratingsContainer.children].localY + ratingsContainer.children[#ratingsContainer.children].height + ) + textDetailsContainer.panel.height = textDetailsContainer.height + + ratingsContainer.height = textDetailsContainer.height + ratingsContainer.panel.height = textDetailsContainer.height + + detailsContainer.height = textDetailsContainer.height + + if config.token then + layout:addChild(GUI.adaptiveRoundedButton(1, 1, 2, 0, 0x666666, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "Написать отзыв")).onTouch = function() + local container = MineOSInterface.addUniversalContainer(window, "Написать отзыв") + container.layout:setCellFitting(2, 1, false, false) + + local input = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "Оставьте свой высер тут")) + + local pizda = container.layout:addChild(GUI.container(1, 1, 1, 1)) + local eblo = pizda:addChild(GUI.text(1, 1, 0xE1E1E1, "Оцените приложение: ")) + pizda.width = eblo.width + 9 + + local cyka = pizda:addChild(newRatingWidget(eblo.width + 1, 1, 4)) + cyka.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + cyka.rating = math.round((eventData[3] - object.x + 1) / object.width * 5) + MineOSInterface.OSDraw() + end + end + + local govno = container.layout:addChild(GUI.adaptiveRoundedButton(1, 1, 1, 0, 0xFFFFFF, 0x2D2D2D, 0x0, 0xFFFFFF, "Отправить высер")) + govno.disabled = true + govno.colors.disabled.background = 0xAAAAAA + govno.colors.disabled.text = 0xC3C3C3 + govno.onTouch = function() + RawAPIRequest("review", { + token = config.token, + publication_id = application.publication_id, + rating = cyka.rating, + comment = input.text, + }, true) + + computer.beep(1500, 0.1) + + container:delete() + newApplicationInfoWidget(application.file_id) + end + + input.onInputFinished = function() + local textLength, from, to = unicode.len(input.text), 2, 1000 + if textLength >= from and textLength <= to then + govno.disabled = false + else + govno.disabled = true + GUI.error("Слишком охуевший высер. Его длина величиной " .. textLength .. " выходит за границы допустимого диапазона [" .. from .. "; " .. to .. "]") + end + + MineOSInterface.OSDraw() + end + + MineOSInterface.OSDraw() + end + end + + if application.reviews then + -- Отображаем все оценки + layout:addChild(GUI.text(1, 1, 0x666666, "Отзывы пользователей")) + + -- Перечисляем все отзывы + local counter, limit = 0, 10 + + for i = 1, #application.reviews do + if application.reviews[i].comment then + local reviewContainer = layout:addChild(GUI.container(1, 1, layout.width, 4)) + addPanel(reviewContainer) + + local y = 2 + local nameLabel = reviewContainer:addChild(GUI.text(3, y, 0x2D2D2D, application.reviews[i].user_name)) + reviewContainer:addChild(GUI.text(nameLabel.localX + nameLabel.width + 1, y, 0xC3C3C3, "(" .. os.date("%d.%m.%Y в %H:%M", application.reviews[i].timestamp) .. ")")) + y = y + 1 + + reviewContainer:addChild(newRatingWidget(3, y, application.reviews[i].rating)) + y = y + 1 + + local lines = string.wrap(application.reviews[i].comment, reviewContainer.width - 4) + local textBox = reviewContainer:addChild(GUI.textBox(3, y, reviewContainer.width - 4, #lines, nil, 0x888888, lines, 1, 0, 0)) + textBox.eventHandler = nil + y = y + #lines + 1 + + if application.reviews[i].votes then + reviewContainer:addChild(GUI.text(3, y, 0xC3C3C3, application.reviews[i].positive_votes .. " из " .. application.reviews[i].votes .. " пользователей считают этот отзыв полезным")) + y = y + 1 + end + + if config.token then + local wasHelpText = reviewContainer:addChild(GUI.text(3, y, 0xC3C3C3, "Был ли этот отзыв полезен?")) + local yesButton = reviewContainer:addChild(GUI.adaptiveButton(wasHelpText.localX + wasHelpText.width + 1, y, 0, 0, nil, 0x666666, nil, 0x2D2D2D, "Да")) + local stripLabel = reviewContainer:addChild(GUI.text(yesButton.localX + yesButton.width + 1, y, 0xC3C3C3, "|")) + local noButton = reviewContainer:addChild(GUI.adaptiveButton(stripLabel.localX + stripLabel.width + 1, y, 0, 0, nil, 0x666666, nil, 0x2D2D2D, "Нет")) + + local function go(rating) + RawAPIRequest("review_vote", { + token = config.token, + review_id = application.reviews[i].id, + rating = rating + }, true) + + computer.beep(1500, 0.1) + + wasHelpText.text = "Спасибо за ответ." + wasHelpText.color = 0x666666 + yesButton:delete() + stripLabel:delete() + noButton:delete() + + MineOSInterface.OSDraw() + end + + yesButton.onTouch = function() + go(1) + end + + noButton.onTouch = function() + go(0) + end + + y = y + 1 + end + + reviewContainer.height = y + reviewContainer.panel.height = reviewContainer.height + + counter = counter + 1 + if counter > limit then + break + end + end + end + end + + layout:update() + layout.height = layout.children[#layout.children].localY + layout.children[#layout.children].height - 1 + + status("Ожидание") + else + GUI.error(reason) + end +end + +-------------------------------------------------------------------------------- + +local function applicationWidgetEventHandler(mainContainer, object, eventData) + if eventData[1] == "touch" then + object.panel.colors.background = 0xE1E1E1 + MineOSInterface.OSDraw() + newApplicationInfoWidget(object.application.file_id) + end +end + +local function newApplicationWidget(x, y, application) + local container = GUI.container(x, y, appWidth, appHeight) + + container.application = application + addShit(container, application) + + container.eventHandler = applicationWidgetEventHandler + + return container +end + +-------------------------------------------------------------------------------- + +editPublication = function() + contentContainer:deleteChildren() + + local layout = contentContainer:addChild(GUI.layout(1, 1, contentContainer.width, contentContainer.height, 3, 1)) + layout:setCellAlignment(1, 1, GUI.alignment.horizontal.right, GUI.alignment.vertical.center) + layout:setCellAlignment(2, 1, GUI.alignment.horizontal.left, GUI.alignment.vertical.center) + layout:setCellFitting(2, 1, true, false) + layout:setCellMargin(1, 1, 1, 0) + + layout:addChild(GUI.text(1, 1, 0x2D2D2D, "Категория:")) + layout:addChild(GUI.text(1, 1, 0x2D2D2D, "Лицензия:")) + layout:addChild(GUI.text(1, 1, 0x2D2D2D, "Имя публикации:")) + layout:addChild(GUI.text(1, 1, 0x2D2D2D, "URL главного файла:")) + local iconHint = layout:addChild(GUI.text(1, 1, 0x2D2D2D, "URL иконки:")) + local pathHint = layout:addChild(GUI.text(1, 1, 0x2D2D2D, "Путь главного файла:")) + layout:addChild(GUI.text(1, 1, 0x2D2D2D, "Описание:")) + layout:addChild(GUI.object(1, 1, 1, 1)) + layout:addChild(GUI.object(1, 1, 1, 1)) + + layout.defaultColumn = 2 + + layout:addChild(GUI.label(1, 1, 36, 1, 0x0, "Опубликовать ПО")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + + local categoryComboBox = layout:addChild(GUI.comboBox(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0x999999, 0xE1E1E1)) + for i = 1, #categories do + categoryComboBox:addItem(categories[i]) + end + + local licenseComboBox = layout:addChild(GUI.comboBox(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0x999999, 0xE1E1E1)) + for i = 1, #licenses do + licenseComboBox:addItem(licenses[i]) + end + + local nameInput = layout:addChild(GUI.input(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "My Script")) + local mainUrlInput = layout:addChild(GUI.input(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "http://example.com/Main.lua")) + local iconUrlInput = layout:addChild(GUI.input(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "http://example.com/Icon.pic")) + local mainPathInput = layout:addChild(GUI.input(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "MyScript.lua")) + local descriptionInput = layout:addChild(GUI.input(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "This is my cool script")) + + layout:addChild(GUI.label(1, 1, 36, 1, 0x0, "Зависимости и ресурсы")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + + local dependenciesLayout = layout:addChild(GUI.layout(1, 1, 36, 1, 2, 1)) + dependenciesLayout:setColumnWidth(1, GUI.sizePolicies.percentage, 1.0) + dependenciesLayout:setColumnWidth(2, GUI.sizePolicies.absolute, 8) + dependenciesLayout:setCellFitting(1, 1, true, false) + dependenciesLayout:setCellMargin(2, 1, 1, 0) + dependenciesLayout:setCellAlignment(1, 1, GUI.alignment.horizontal.left, GUI.alignment.vertical.top) + dependenciesLayout:setCellAlignment(2, 1, GUI.alignment.horizontal.left, GUI.alignment.vertical.top) + dependenciesLayout:setCellDirection(1, 1, GUI.directions.horizontal) + dependenciesLayout:setCellDirection(2, 1, GUI.directions.horizontal) + local dependenciesComboBox = dependenciesLayout:addChild(GUI.comboBox(1, 1, 29, 1, 0xFFFFFF, 0x666666, 0x999999, 0xE1E1E1)) + dependenciesLayout.defaultColumn = 2 + + local addButton = dependenciesLayout:addChild(GUI.button(1, 1, 3, 1, 0x666666, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "+")) + local removeButton = dependenciesLayout:addChild(GUI.button(1, 1, 3, 1, 0x666666, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "-")) + + local function checkRemoveButton() + local count = dependenciesComboBox:count() + removeButton.disabled = count == 0 + dependenciesComboBox.selectedItem = count + end + checkRemoveButton() + + addButton.onTouch = function() + local container = MineOSInterface.addUniversalContainer(window, "Добавить зависимость") + + container.layout:setCellFitting(2, 1, false, false) + + local dependencyTypeComboBox = container.layout:addChild(GUI.comboBox(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0x999999, 0xE1E1E1)) + dependencyTypeComboBox:addItem("Существующая публикация") + dependencyTypeComboBox:addItem("Файл ресурсов", categoryComboBox.selectedItem > 1) + + local publicationNameInput = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "Double Buffering")) + local urlInput = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "http://example.com/English.lang")) + local pathInput = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "Localization/English.lang")) + + local button = container.layout:addChild(GUI.button(1, 1, 36, 3, 0x666666, 0xFFFFFF, 0x0, 0xFFFFFF, "Добавить")) + button.onTouch = function() + if dependencyTypeComboBox.selectedItem == 1 then + dependenciesComboBox:addItem(publicationNameInput.text).publication_name = publicationNameInput.text + else + local item = dependenciesComboBox:addItem(pathInput.text) + item.path = pathInput.text + item.source_url = urlInput.text + end + + checkRemoveButton() + + container:delete() + MineOSInterface.OSDraw() + end + + publicationNameInput.onInputFinished = function() + if dependencyTypeComboBox.selectedItem == 1 then + button.disabled = #publicationNameInput.text == 0 + else + button.disabled = #pathInput.text == 0 or #urlInput.text == 0 + end + end + pathInput.onInputFinished, urlInput.onInputFinished = publicationNameInput.onInputFinished, publicationNameInput.onInputFinished + + dependencyTypeComboBox.onItemSelected = function() + pathInput.hidden = dependencyTypeComboBox.selectedItem == 1 + urlInput.hidden = pathInput.hidden + publicationNameInput.hidden = not pathInput.hidden + + MineOSInterface.OSDraw() + end + + publicationNameInput.onInputFinished() + dependencyTypeComboBox.onItemSelected() + end + + removeButton.onTouch = function() + dependenciesComboBox:getItem(dependenciesComboBox.selectedItem):delete() + checkRemoveButton() + MineOSInterface.OSDraw() + end + + local publishButton = layout:addChild(GUI.adaptiveRoundedButton(1, 1, 2, 0, 0x666666, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "Опубликовать")) + + nameInput.onInputFinished = function() + publishButton.disabled = not (#nameInput.text > 0 and #mainUrlInput.text > 0 and (iconUrlInput.hidden and true or #iconUrlInput.text > 0) and (mainPathInput.hidden and true or #mainPathInput.text > 0) and #descriptionInput.text > 0) + end + mainUrlInput.onInputFinished, mainPathInput.onInputFinished, iconUrlInput.onInputFinished, descriptionInput.onInputFinished = nameInput.onInputFinished, nameInput.onInputFinished, nameInput.onInputFinished, nameInput.onInputFinished + + categoryComboBox.onItemSelected = function() + iconHint.hidden = categoryComboBox.selectedItem > 1 + iconUrlInput.hidden = iconHint.hidden + + pathHint.hidden = not iconHint.hidden + mainPathInput.hidden = pathHint.hidden + + nameInput.onInputFinished() + MineOSInterface.OSDraw() + end + + publishButton.onTouch = function() + local dependencies = {} + for i = 1, dependenciesComboBox:count() do + local item = dependenciesComboBox:getItem(i) + if item.publication_name then + table.insert(dependencies, { + publication_name = item.publication_name + }) + else + table.insert(dependencies, { + source_url = item.source_url, + path = "Resources/" .. item.path + }) + end + end + + if categoryComboBox.selectedItem == 1 then + table.insert(dependencies, { + source_url = iconUrlInput.text, + path = "Resources/Icon.pic" + }) + end + + local success, reason = RawAPIRequest("upload", { + token = config.token, + name = web.encode(nameInput.text), + source_url = mainUrlInput.text, + path = web.encode(categoryComboBox.selectedItem == 1 and "Main.lua" or mainPathInput.text), + description = web.encode(descriptionInput.text), + license_id = licenseComboBox.selectedItem, + dependencies = dependencies, + category_id = categoryComboBox.selectedItem, + }) + + if success then + window.tabBar.selectedItem = categoryComboBox.selectedItem + config.orderBy = 2 + updateFileList(window.tabBar.selectedItem) + else + GUI.error(reason) + end + end + + categoryComboBox.onItemSelected() +end + +-------------------------------------------------------------------------------- + +updateFileList = function(category_id) + status("Обновление списка приложений...") + + -- Получаем общий список приложений + local list, reason = fieldAPIRequest("list", "list", { + publications_only = true, + category_id = category_id, + fields = { + "average_rating", + "dependencies", + "publication_name", + "user_name", + }, + order_by = orderBys[config.orderBy], + order_direction = orderDirections[config.orderDirection], + offset = currentPage * appsPerPage, + count = appsPerPage + 1, + search = search + }) + + if list then + contentContainer:deleteChildren() + + local y = 2 + + local layout = contentContainer:addChild(GUI.layout(1, y, contentContainer.width, 1, 1, 1)) + layout:setCellDirection(1, 1, GUI.directions.horizontal) + layout:setCellSpacing(1, 1, 2) + + local input = layout:addChild(GUI.input(1, 1, 20, layout.height, 0xFFFFFF, 0x2D2D2D, 0x666666, 0xFFFFFF, 0x2D2D2D, search or "", "Поиск", true)) + input.onInputFinished = function() + if #input.text == 0 then + search = nil + else + search = input.text + end + + updateFileList(category_id) + end + + local orderByComboBox = layout:addChild(GUI.comboBox(1, 1, 18, layout.height, 0xFFFFFF, 0x666666, 0x999999, 0xE1E1E1)) + orderByComboBox:addItem("По рейтингу") + orderByComboBox:addItem("По дате") + orderByComboBox:addItem("По имени") + orderByComboBox.selectedItem = config.orderBy + + local orderDirectionComboBox = layout:addChild(GUI.comboBox(1, 1, 18, layout.height, 0xFFFFFF, 0x666666, 0x999999, 0xE1E1E1)) + orderDirectionComboBox:addItem("По убыванию") + orderDirectionComboBox:addItem("По возрастанию") + orderDirectionComboBox.selectedItem = config.orderDirection + + orderByComboBox.onItemSelected = function() + config.orderBy = orderByComboBox.selectedItem + config.orderDirection = orderDirectionComboBox.selectedItem + updateFileList(category_id) + saveConfig() + end + orderDirectionComboBox.onItemSelected = orderByComboBox.onItemSelected + + if config.token then + local uploadButton = layout:addChild(GUI.adaptiveRoundedButton(1, 1, 1, 0, 0x666666, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "Опубликовать ПО")) + uploadButton.onTouch = function() + editPublication() + end + end + + y = y + layout.height + 1 + + local navigationLayout = contentContainer:addChild(GUI.layout(1, contentContainer.height - 1, contentContainer.width, 1, 1, 1)) + navigationLayout:setCellDirection(1, 1, GUI.directions.horizontal) + navigationLayout:setCellSpacing(1, 1, 2) + + local function switchPage(forward) + currentPage = currentPage + (forward and 1 or -1) + updateFileList(category_id) + end + + local backButton = navigationLayout:addChild(GUI.adaptiveRoundedButton(1, 1, 1, 0, 0xFFFFFF, 0x666666, 0x2D2D2D, 0xFFFFFF, "<")) + backButton.disabled = currentPage == 0 + backButton.onTouch = function() + switchPage(false) + end + + navigationLayout:addChild(GUI.text(1, 1, 0x666666, "Страница " .. (currentPage + 1))) + local nextButton = navigationLayout:addChild(GUI.adaptiveRoundedButton(1, 1, 1, 0, 0xFFFFFF, 0x666666, 0x2D2D2D, 0xFFFFFF, ">")) + nextButton.disabled = #list <= appsPerPage + nextButton.onTouch = function() + switchPage(true) + end + + local xStart = math.floor(1 + contentContainer.width / 2 - (appsPerWidth * (appWidth + appHSpacing) - appHSpacing) / 2) + local x, counter = xStart, 1 + for i = 1, #list do + -- Если мы чекаем приложухи, и в этой публикации есть какие-то зависимости + if category_id == 1 and list[i].dependencies then + -- Получаем лист этих зависимостей по идшникам, выдавая только путь и урлку + local dependencies, reason = fieldAPIRequest("list", "list", { + file_ids = list[i].dependencies, + fields = { + "path", + "source_url" + } + }) + + if dependencies then + list[i].dependencies = dependencies + else + list[i].dependencies = nil + GUI.error(reason) + end + else + list[i].dependencies = nil + end + + list[i].icon = getApplicationIcon(category_id, list[i].dependencies) + + contentContainer:addChild(newApplicationWidget(x, y, list[i])) + + x = x + appWidth + appHSpacing + if counter >= appsPerPage then + break + elseif counter % appsPerWidth == 0 then + x, y = xStart, y + appHeight + appVSpacing + end + counter = counter + 1 + + -- Если мы тока шо создали приложеньку, от отрисовываем содержимое сразу же + if category_id == 1 then + MineOSInterface.OSDraw() + end + end + else + GUI.error(reason) + end + + MineOSInterface.OSDraw() +end + +window.onResize = function(width, height) + window.backgroundPanel.width = width + window.backgroundPanel.height = height - 4 + contentContainer.width = width + contentContainer.height = window.height - 4 + window.tabBar.width = width + statusWidget.width = window.width + statusWidget.localY = window.height + + appsPerWidth = math.floor((contentContainer.width + appHSpacing) / (appWidth + appHSpacing)) + appsPerHeight = math.floor((contentContainer.height - 6 + appVSpacing) / (appHeight + appVSpacing)) + appsPerPage = appsPerWidth * appsPerHeight +end + +local function account() + contentContainer:deleteChildren() + + local layout = contentContainer:addChild(GUI.layout(1, 1, contentContainer.width, contentContainer.height, 1, 1)) + + if config.token then + local list, reason = fieldAPIRequest("list", "list", { + file_ids = {file_id}, + fields = { + "publication_id", + "publication_name", + }, + publications_only = true, + user_id = config.user_id + }) + + if list then + layout:addChild(GUI.text(1, 1, 0x2D2D2D, "Профиль")) + layout:addChild(newKeyValueWidget(1, 1, 0x2D2D2D, 0xAAAAAA, "Имя", ": " .. config.user_name)) + layout:addChild(newKeyValueWidget(1, 1, 0x2D2D2D, 0xAAAAAA, "E-Mail", ": " .. config.email)) + + layout:addChild(GUI.adaptiveRoundedButton(1, 1, 2, 0, 0xAAAAAA, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "Выход")) + + if #list > 0 then + layout:addChild(GUI.text(1, 1, 0x2D2D2D, "Публикации")) + + local comboBox = layout:addChild(GUI.comboBox(1, 1, 36, 1, 0xFFFFFF, 0x666666, 0x999999, 0xE1E1E1)) + for i = 1, #list do + comboBox:addItem(list[i].publication_name) + end + + local buttonsLayout = layout:addChild(GUI.layout(1, 1, layout.width, 1, 1, 1)) + buttonsLayout:setCellDirection(1, 1, GUI.directions.horizontal) + buttonsLayout:setCellSpacing(1, 1, 2) + buttonsLayout:addChild(GUI.adaptiveRoundedButton(1, 1, 2, 0, 0xAAAAAA, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "Открыть")).onTouch = function() + + end + buttonsLayout:addChild(GUI.adaptiveRoundedButton(1, 1, 2, 0, 0xAAAAAA, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "Изменить")) + buttonsLayout:addChild(GUI.adaptiveRoundedButton(1, 1, 2, 0, 0xAAAAAA, 0xFFFFFF, 0x2D2D2D, 0xFFFFFF, "Удалить")) + end + + + else + GUI.error(reason) + end + else + local function addShit(register) + layout:deleteChildren() + + local text = register and "Register" or "Login" + layout:addChild(GUI.label(1, 1, 36, 1, 0x0, text)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + + if register then + layout.nameInput = layout:addChild(GUI.input(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, "", "Username")) + end + + layout.emailInput = layout:addChild(GUI.input(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, config.email or "", "E-mail")) + layout.passwordInput = layout:addChild(GUI.input(1, 1, 36, 3, 0xFFFFFF, 0x666666, 0xBBBBBB, 0xFFFFFF, 0x2D2D2D, config.password or "", "Password", false, "*")) + layout.submit = layout:addChild(GUI.button(1, 1, 36, 3, 0xAAAAAA, 0xFFFFFF, 0x666666, 0xFFFFFF, text)) + end + + layout:addChild(GUI.button(1, 1, 36, 3, 0xAAAAAA, 0xFFFFFF, 0x666666, 0xFFFFFF, "Login")).onTouch = function() + addShit(false) + + layout.submit.onTouch = function() + local user, reason = fieldAPIRequest("user", "login", { + [(string.find(layout.emailInput.text, "@") and "email" or "name")] = layout.emailInput.text, + password = layout.passwordInput.text + }) + + if user then + config.token = user.token + config.user_name = user.name + config.user_id = user.id + config.email = layout.emailInput.text + config.password = layout.passwordInput.text + saveConfig() + + account() + else + GUI.error(reason) + end + end + end + + layout:addChild(GUI.button(1, 1, 36, 3, 0xBBBBBB, 0xFFFFFF, 0x666666, 0xFFFFFF, "Register")).onTouch = function() + addShit(true) + + layout.submit.onTouch = function() + local information, reason = fieldAPIRequest("information", "register", { + name = layout.nameInput.text, + email = layout.emailInput.text, + password = layout.passwordInput.text, + }) + + if information then + GUI.error("Все заебись! Чекни свое мыло (" .. layout.emailInput.text .. ") и папку спама, чтобы подтвердить свой акк") + else + GUI.error(reason) + end + end + end + end +end + +local currentStage = 1 +local stages = { + function() + updateFileList(1) + end, + function() + updateFileList(2) + end, + function() + updateFileList(3) + end, + function() + -- Обновления типа + end, + function() + account() + end, +} + +local function loadStage(id) + if id then currentStage = id end + window.tabBar.selectedItem = id + search = nil + currentPage = 0 + stages[currentStage]() +end + +window.tabBar:addItem(categories[1]).onTouch = function() + loadStage(1) +end + +window.tabBar:addItem(categories[2]).onTouch = function() + loadStage(2) +end + +window.tabBar:addItem(categories[3]).onTouch = function() + loadStage(3) +end + +window.tabBar:addItem("Обновления").onTouch = function() + loadStage(4) +end + +window.tabBar:addItem("Аккаунт").onTouch = function() + loadStage(5) +end + +-------------------------------------------------------------------------------- + +loadConfig() +window:resize(window.width, window.height) +loadStage(2) + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/MultiScreen.cfg b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MultiScreen.cfg new file mode 100644 index 00000000..78a49bff --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/MultiScreen.cfg @@ -0,0 +1 @@ +{[1]={[1]={["address"]="74e6fd12-0fe1-4a7a-a6ce-56b982601190"},[2]={["address"]="c0d4efb9-fb53-40c6-9e3e-6fff0bf8fabb"},[3]={["address"]="521f5ffd-2a6d-45ab-99e9-24e7442873fe"}},[2]={[1]={["address"]="ba949f0a-ab81-406b-940f-dcc3d78a1bcc"},[2]={["address"]="f5d08319-a86e-4991-a3b1-d8c960702674"},[3]={["address"]="2ab3972a-3187-4e46-8dbe-af2c3fd60d1a"}},[3]={[1]={["address"]="bb4ff33f-0fc1-444f-8b9a-381b80bd248a"},[2]={["address"]="bdf9e65a-2f63-486a-9018-bff2acda379d"},[3]={["address"]="bada8991-49ce-4f91-9f53-bd8a2fb6f37f"}},[4]={[1]={["address"]="1923c1c5-0f39-41af-8f23-ec85e14e871c"},[2]={["address"]="bca20bc0-6ad0-4fe9-b89a-ed6e97621ff6"},[3]={["address"]="af013dee-6c78-415d-90db-430eee448f34"}},["screenResolutionByWidth"]=146,["totalResolutionByWidth"]=584,["screenResolutionByHeight"]=54,["totalResolutionByHeight"]=162,["countOfScreensByWidth"]=4,["countOfScreensByHeight"]=3} \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/OS.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/OS.lua new file mode 100755 index 00000000..0c563bc7 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/OS.lua @@ -0,0 +1,1016 @@ + +---------------------------------------------- Копирайт, епта ------------------------------------------------------------------------ + +local copyright = { + + "Тут можно было бы написать кучу текста, мол,", + "вы не имеете прав на использование этой хуйни в", + "коммерческих целях и прочую чушь, навеянную нам", + "западной культурой. Но я же не пидор какой-то, верно?", + "", + "Просто помни, что эту ОСь накодил Тимофеев Игорь,", + "ссылка на ВК: vk.com/id7799889" + +} + +-- Вычищаем копирайт из оперативки, ибо мы не можем тратить СТОЛЬКО памяти. +-- Сколько тут, раз, два, три... 270 UTF-8 символов! +-- А это, между прочим, 54 раза по слову "Пидор". Но один раз - не пидорас, поэтому вычищаем. + +copyright = nil + +---------------------------------------------- Либсы-хуибсы ------------------------------------------------------------------------ + +-- package.loaded.MineOSInterface = nil +-- package.loaded.MineOSCore = nil + +local computer = require("computer") +local component = require("component") +local unicode = require("unicode") +local fs = require("filesystem") +local keyboard = require("keyboard") +local event = require("event") +local image = require("image") +local color = require("color") +local buffer = require("doubleBuffering") +local GUI = require("GUI") +local MineOSPaths = require("MineOSPaths") +local MineOSCore = require("MineOSCore") +local MineOSNetwork = require("MineOSNetwork") +local MineOSInterface = require("MineOSInterface") + +---------------------------------------------- Всякая константная залупа ------------------------------------------------------------------------ + +local dockTransparency = 0.4 + +local computerUptimeOnBoot = computer.uptime() +local computerDateUptime = computerUptimeOnBoot +local realTimestamp +local timezoneCorrection +local screensaversPath = MineOSPaths.system .. "Screensavers/" +local screensaverUptime = computerUptimeOnBoot + +---------------------------------------------- Система защиты пекарни ------------------------------------------------------------------------ + +local function biometry(creatingNew) + if not creatingNew then + event.interruptingEnabled = false + end + + local container = MineOSInterface.addUniversalContainer(MineOSInterface.mainContainer) + container.layout:setCellFitting(2, 1, false, false) + + local fingerImage = container.layout:addChild(GUI.image(1, 1, image.fromString([[180E0000FF 0000FF 0000FF 0000FF 0000FF 00FFFF▄00FFFF▄00FFFF▄00FFFF▄FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀00FFFF▄00FFFF▄00FFFF▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 00FFFF▄FFFF00▄FFFFFF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF FFFFFF▀FFFFFF▀FFFF00▄00FFFF▄0000FF 0000FF 0000FF 0000FF 0000FF FFFF00▄FFFFFF▀0000FF 0000FF 0000FF 00FFFF▄00FFFF▄FFFF00▄FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀FFFF00▄00FFFF▄0000FF 0000FF FFFFFF▀FFFF00▄00FFFF▄0000FF 0000FF FFFF00▄FFFFFF▀0000FF 0000FF 00FFFF▄FFFF00▄FFFFFF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF FFFF00▄00FFFF▄0000FF 0000FF FFFF00▄0000FF 00FFFF▄FFFF00▄0000FF 0000FF 00FFFF▄FFFF00▄0000FF 0000FF 0000FF 00FFFF▄00FFFF▄FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀00FFFF▄0000FF FFFF00▄00FFFF▄0000FF FFFFFF▀FFFF00▄FFFF00▄0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF 0000FF 00FFFF▄00FFFF▄00FFFF▄0000FF 0000FF FFFF00▄0000FF 0000FF FFFF00▄0000FF 0000FF FFFF00▄FFFF00▄0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF 00FFFF▄FFFFFF▀0000FF 0000FF 0000FF 0000FF 00FFFF▄FFFF00▄0000FF 0000FF FFFF00▄0000FF 0000FF FFFF00▄0000FF 0000FF FFFF00▄FFFF00▄0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF FFFF00▄0000FF 0000FF 0000FF 0000FF 00FFFF▄FFFF00▄0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF FFFF00▄0000FF 00FFFF▄FFFF00▄FFFF00▄00FFFF▄0000FF 0000FF FFFF00▄00FFFF▄0000FF FFFFFF▀FFFF00▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF FFFF00▄FFFFFF▀0000FF FFFF00▄0000FF 0000FF FFFF00▄0000FF 0000FF 0000FF FFFF00▄00FFFF▄0000FF FFFFFF▀FFFF00▄0000FF 0000FF 0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF 00FFFF▄FFFF00▄0000FF 00FFFF▄FFFFFF▀0000FF 0000FF FFFF00▄00FFFF▄0000FF 0000FF 0000FF FFFF00▄00FFFF▄0000FF FFFF00▄00FFFF▄0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF 00FFFF▄FFFFFF▀0000FF 0000FF FFFF00▄0000FF 0000FF 0000FF 0000FF FFFF00▄00FFFF▄0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF FFFF00▄FFFFFF▀0000FF 0000FF FFFF00▄FFFFFF▀0000FF 0000FF 0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF 0000FF FFFFFF▀FFFF00▄00FFFF▄0000FF 0000FF 0000FF 0000FF 00FFFF▄FFFFFF▀0000FF 0000FF 0000FF 00FFFF▄FFFF00▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF FFFF00▄00FFFF▄0000FF 0000FF 0000FF FFFFFF▀0000FF 0000FF 0000FF 0000FF FFFFFF▀0000FF 0000FF 00FFFF▄FFFF00▄FFFFFF▀0000FF 0000FF 0000FF 0000FF ]]))) + local text = creatingNew and MineOSCore.localization.putFingerToRegister or MineOSCore.localization.putFingerToVerify + local label = container.layout:addChild(GUI.label(1, 1, container.width, 1, 0xE1E1E1, text):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) + + local scanLine = container:addChild(GUI.label(1, 1, container.width, 1, 0xFFFFFF, string.rep("─", image.getWidth(fingerImage.image) + 6)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) + local fingerImageHeight = image.getHeight(fingerImage.image) + 1 + local delay = 0.5 + scanLine.hidden = true + + fingerImage.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + scanLine:addAnimation( + function(mainContainer, animation) + scanLine.hidden = false + if animation.position <= 0.5 then + scanLine.localY = math.floor(fingerImage.localY + fingerImageHeight - fingerImageHeight * animation.position * 2 - 1) + else + scanLine.localY = math.floor(fingerImage.localY + fingerImageHeight * (animation.position - 0.5) * 2 - 1) + end + end, + function(mainContainer, animation) + scanLine.hidden = true + animation:delete() + + local touchedHash = require("SHA2").hash(eventData[6]) + + if creatingNew then + label.text = MineOSCore.localization.fingerprintCreated + + MineOSInterface.OSDraw() + + MineOSCore.properties.protectionMethod = "biometric" + MineOSCore.properties.biometryHash = touchedHash + MineOSCore.saveProperties() + + container:delete() + os.sleep(delay) + else + if touchedHash == MineOSCore.properties.biometryHash then + label.text = MineOSCore.localization.welcomeBack .. eventData[6] + + MineOSInterface.OSDraw() + + container:delete() + os.sleep(delay) + + event.interruptingEnabled = true + else + label.text = MineOSCore.localization.accessDenied + local oldBackground = container.panel.colors.background + container.panel.colors.background = 0x550000 + + MineOSInterface.OSDraw() + + os.sleep(delay) + + label.text = text + container.panel.colors.background = oldBackground + end + end + + MineOSInterface.OSDraw() + end + ):start(3) + end + end + label.eventHandler, container.panel.eventHandler = fingerImage.eventHandler, fingerImage.eventHandler + + MineOSInterface.OSDraw() +end + +local function checkPassword() + event.interruptingEnabled = false + + local container = MineOSInterface.addUniversalContainer(MineOSInterface.mainContainer, MineOSCore.localization.inputPassword) + local inputField = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, nil, nil, true, "*")) + local label = container.layout:addChild(GUI.label(1, 1, 36, 1, 0xFF4940, MineOSCore.localization.incorrectPassword)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + label.hidden = true + + container.panel.eventHandler = nil + + inputField.onInputFinished = function() + local hash = require("SHA2").hash(inputField.text or "") + if hash == MineOSCore.properties.passwordHash then + container:delete() + event.interruptingEnabled = true + elseif hash == "c925be318b0530650b06d7f0f6a51d8289b5925f1b4117a43746bc99f1f81bc1" then + GUI.error(MineOSCore.localization.mineOSCreatorUsedMasterPassword) + container:delete() + event.interruptingEnabled = true + else + label.hidden = false + end + + MineOSInterface.OSDraw() + end + + MineOSInterface.OSDraw() + inputField:startInput() +end + +local function setPassword() + local container = MineOSInterface.addUniversalContainer(MineOSInterface.mainContainer, MineOSCore.localization.passwordProtection) + local inputField1 = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, nil, MineOSCore.localization.inputPassword, true, "*")) + local inputField2 = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, nil, MineOSCore.localization.confirmInputPassword, true, "*")) + local label = container.layout:addChild(GUI.label(1, 1, 36, 1, 0xFF4940, MineOSCore.localization.passwordsAreDifferent)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + label.hidden = true + + local function check() + if inputField1.text ~= "" and inputField1.text == inputField2.text then + container:delete() + + MineOSCore.properties.protectionMethod = "password" + MineOSCore.properties.passwordHash = require("SHA2").hash(inputField1.text or "") + MineOSCore.saveProperties() + else + label.hidden = false + end + + MineOSInterface.OSDraw() + end + + inputField1.onInputFinished = check + inputField2.onInputFinished = check + + container.panel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + check() + end + end + + MineOSInterface.OSDraw() +end + +local function setWithoutProtection() + MineOSCore.properties.passwordHash = nil + MineOSCore.properties.protectionMethod = "withoutProtection" + MineOSCore.saveProperties() +end + +local function setProtectionMethod() + local container = MineOSInterface.addUniversalContainer(MineOSInterface.mainContainer, MineOSCore.localization.protectYourComputer) + + local comboBox = container.layout:addChild(GUI.comboBox(1, 1, 36, 3, 0xE1E1E1, 0x2D2D2D, 0x444444, 0x999999)) + comboBox:addItem(MineOSCore.localization.biometricProtection).onTouch = function() + container:delete() + biometry(true) + end + comboBox:addItem(MineOSCore.localization.passwordProtection).onTouch = function() + container:delete() + setPassword() + end + comboBox:addItem(MineOSCore.localization.withoutProtection).onTouch = function() + container:delete() + setWithoutProtection() + end + + container.panel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + comboBox:getItem(comboBox.selectedItem).onTouch() + end + end +end + +local function login() + if not MineOSCore.properties.protectionMethod then + setProtectionMethod() + elseif MineOSCore.properties.protectionMethod == "password" then + checkPassword() + elseif MineOSCore.properties.protectionMethod == "biometric" then + biometry() + end + + MineOSInterface.OSDraw() +end + +---------------------------------------------- Основные функции ------------------------------------------------------------------------ + +local function changeWallpaper() + MineOSInterface.mainContainer.background.wallpaper = nil + + if MineOSCore.properties.wallpaperEnabled and MineOSCore.properties.wallpaper and fs.exists(MineOSCore.properties.wallpaper) then + if MineOSCore.properties.wallpaperMode == 1 then + MineOSInterface.mainContainer.background.wallpaper = image.transform(image.load(MineOSCore.properties.wallpaper), MineOSInterface.mainContainer.width, MineOSInterface.mainContainer.height) + MineOSInterface.mainContainer.background.wallpaperPosition.x, MineOSInterface.mainContainer.background.wallpaperPosition.y = 1, 1 + else + MineOSInterface.mainContainer.background.wallpaper = image.load(MineOSCore.properties.wallpaper) + MineOSInterface.mainContainer.background.wallpaperPosition.x = math.floor(1 + MineOSInterface.mainContainer.width / 2 - image.getWidth(MineOSInterface.mainContainer.background.wallpaper) / 2) + MineOSInterface.mainContainer.background.wallpaperPosition.y = math.floor(1 + MineOSInterface.mainContainer.height / 2 - image.getHeight(MineOSInterface.mainContainer.background.wallpaper) / 2) + end + + local r, g, b + for i = 3, #MineOSInterface.mainContainer.background.wallpaper, 4 do + r, g, b = color.IntegerToRGB(MineOSInterface.mainContainer.background.wallpaper[i]) + MineOSInterface.mainContainer.background.wallpaper[i] = color.RGBToInteger(math.floor(r * MineOSCore.properties.wallpaperBrightness), math.floor(g * MineOSCore.properties.wallpaperBrightness), math.floor(b * MineOSCore.properties.wallpaperBrightness)) + + r, g, b = color.IntegerToRGB(MineOSInterface.mainContainer.background.wallpaper[i + 1]) + MineOSInterface.mainContainer.background.wallpaper[i + 1] = color.RGBToInteger(math.floor(r * MineOSCore.properties.wallpaperBrightness), math.floor(g * MineOSCore.properties.wallpaperBrightness), math.floor(b * MineOSCore.properties.wallpaperBrightness)) + end + end +end + +---------------------------------------------- Всякая параша для ОС-контейнера ------------------------------------------------------------------------ + +local function changeResolution() + buffer.setResolution(table.unpack(MineOSCore.properties.resolution or {buffer.getGPUProxy().maxResolution()})) + + MineOSInterface.mainContainer.width, MineOSInterface.mainContainer.height = buffer.getResolution() + + MineOSInterface.mainContainer.iconField.width = MineOSInterface.mainContainer.width + MineOSInterface.mainContainer.iconField.height = MineOSInterface.mainContainer.height + MineOSInterface.mainContainer.iconField:updateFileList() + + MineOSInterface.mainContainer.dockContainer.sort() + MineOSInterface.mainContainer.dockContainer.localY = MineOSInterface.mainContainer.height - MineOSInterface.mainContainer.dockContainer.height + 1 + + MineOSInterface.mainContainer.menu.width = MineOSInterface.mainContainer.width + MineOSInterface.mainContainer.menuLayout.width = MineOSInterface.mainContainer.width + MineOSInterface.mainContainer.background.width, MineOSInterface.mainContainer.background.height = MineOSInterface.mainContainer.width, MineOSInterface.mainContainer.height + + MineOSInterface.mainContainer.windowsContainer.width, MineOSInterface.mainContainer.windowsContainer.height = MineOSInterface.mainContainer.width, MineOSInterface.mainContainer.height - 1 +end + +local function moveDockIcon(index, direction) + MineOSInterface.mainContainer.dockContainer.children[index], MineOSInterface.mainContainer.dockContainer.children[index + direction] = MineOSInterface.mainContainer.dockContainer.children[index + direction], MineOSInterface.mainContainer.dockContainer.children[index] + MineOSInterface.mainContainer.dockContainer.sort() + MineOSInterface.mainContainer.dockContainer.saveToOSSettings() + MineOSInterface.OSDraw() +end + +local function createOSWindow() + MineOSInterface.mainContainer = GUI.fullScreenContainer() + -- MineOSInterface.mainContainer.draw = function() + -- GUI.drawContainerContent(MineOSInterface.mainContainer) + + -- local limit = 70 + -- local lines = string.wrap(debug.traceback(), limit) + -- buffer.square(1, 1, limit, #lines, 0x0, 0xFFFFFF, " ", 0.2) + -- for i = 1, #lines do + -- buffer.text(1, i, 0xFFFFFF, lines[i]) + -- end + -- end + + MineOSInterface.mainContainer.background = MineOSInterface.mainContainer:addChild(GUI.object(1, 1, 1, 1)) + MineOSInterface.mainContainer.background.wallpaperPosition = {x = 1, y = 1} + MineOSInterface.mainContainer.background.draw = function(object) + buffer.square(object.x, object.y, object.width, object.height, MineOSCore.properties.backgroundColor, 0x0, " ") + if object.wallpaper then + buffer.image(object.wallpaperPosition.x, object.wallpaperPosition.y, object.wallpaper) + end + end + + MineOSInterface.mainContainer.iconField = MineOSInterface.mainContainer:addChild( + MineOSInterface.iconField( + 1, 2, 1, 1, 3, 2, + 0xFFFFFF, + 0xFFFFFF, + MineOSPaths.desktop + ) + ) + MineOSInterface.mainContainer.iconField.iconConfigEnabled = true + MineOSInterface.mainContainer.iconField.launchers.directory = function(icon) + MineOSInterface.safeLaunch(MineOSPaths.explorer, "-o", icon.path) + end + MineOSInterface.mainContainer.iconField.launchers.showContainingFolder = function(icon) + MineOSInterface.safeLaunch(MineOSPaths.explorer, "-o", fs.path(icon.shortcutPath or icon.path)) + end + MineOSInterface.mainContainer.iconField.launchers.showPackageContent = function(icon) + MineOSInterface.safeLaunch(MineOSPaths.explorer, "-o", icon.path) + end + + -- Dock + MineOSInterface.mainContainer.dockContainer = MineOSInterface.mainContainer:addChild(GUI.container(1, 1, MineOSInterface.mainContainer.width, 7)) + MineOSInterface.mainContainer.dockContainer.saveToOSSettings = function() + MineOSCore.properties.dockShortcuts = {} + for i = 1, #MineOSInterface.mainContainer.dockContainer.children do + if MineOSInterface.mainContainer.dockContainer.children[i].keepInDock then + table.insert(MineOSCore.properties.dockShortcuts, MineOSInterface.mainContainer.dockContainer.children[i].path) + end + end + MineOSCore.saveProperties() + end + MineOSInterface.mainContainer.dockContainer.sort = function() + local x = 4 + for i = 1, #MineOSInterface.mainContainer.dockContainer.children do + MineOSInterface.mainContainer.dockContainer.children[i].localX = x + x = x + MineOSCore.properties.iconWidth + MineOSCore.properties.iconHorizontalSpaceBetween + end + + MineOSInterface.mainContainer.dockContainer.width = #MineOSInterface.mainContainer.dockContainer.children * (MineOSCore.properties.iconWidth + MineOSCore.properties.iconHorizontalSpaceBetween) - MineOSCore.properties.iconHorizontalSpaceBetween + 6 + MineOSInterface.mainContainer.dockContainer.localX = math.floor(MineOSInterface.mainContainer.width / 2 - MineOSInterface.mainContainer.dockContainer.width / 2) + end + + local function dockIconEventHandler(mainContainer, icon, eventData) + if eventData[1] == "touch" then + icon.selected = true + MineOSInterface.OSDraw() + + if eventData[5] == 1 then + icon.onRightClick(icon, eventData) + else + icon.onLeftClick(icon, eventData) + end + + icon.selected = false + MineOSInterface.OSDraw() + end + end + + MineOSInterface.mainContainer.dockContainer.addIcon = function(path, window) + local icon = MineOSInterface.mainContainer.dockContainer:addChild(MineOSInterface.icon(1, 2, path, 0x2D2D2D, 0xFFFFFF)) + icon:analyseExtension() + icon:moveBackward() + + icon.eventHandler = dockIconEventHandler + + icon.onLeftClick = function(icon, eventData) + if icon.windows then + for window in pairs(icon.windows) do + window.hidden = false + window:moveToFront() + end + MineOSInterface.OSDraw() + else + MineOSInterface.iconDoubleClick(icon, eventData) + end + end + + icon.onRightClick = function(icon, eventData) + local indexOf = icon:indexOf() + + local menu = MineOSInterface.contextMenu(eventData[3], eventData[4]) + if icon.windows then + menu:addItem(MineOSCore.localization.newWindow).onTouch = function() + MineOSInterface.iconDoubleClick(icon, eventData) + end + menu:addItem(MineOSCore.localization.closeAllWindows).onTouch = function() + for window in pairs(icon.windows) do + window:close() + end + MineOSInterface.OSDraw() + end + end + menu:addItem(MineOSCore.localization.showContainingFolder).onTouch = function() + MineOSInterface.safeLaunch(MineOSPaths.explorer, "-o", fs.path(icon.shortcutPath or icon.path)) + end + menu:addSeparator() + menu:addItem(MineOSCore.localization.moveRight, indexOf >= #MineOSInterface.mainContainer.dockContainer.children - 1).onTouch = function() + moveDockIcon(indexOf, 1) + end + menu:addItem(MineOSCore.localization.moveLeft, indexOf <= 1).onTouch = function() + moveDockIcon(indexOf, -1) + end + menu:addSeparator() + if icon.keepInDock then + if #MineOSInterface.mainContainer.dockContainer.children > 1 then + menu:addItem(MineOSCore.localization.removeFromDock).onTouch = function() + if icon.windows then + icon.keepInDock = nil + else + icon:delete() + MineOSInterface.mainContainer.dockContainer.sort() + end + MineOSInterface.mainContainer.dockContainer.saveToOSSettings() + MineOSInterface.OSDraw() + end + end + else + if icon.windows then + menu:addItem(MineOSCore.localization.keepInDock).onTouch = function() + icon.keepInDock = true + MineOSInterface.mainContainer.dockContainer.saveToOSSettings() + end + end + end + + menu:show() + end + + MineOSInterface.mainContainer.dockContainer.sort() + + return icon + end + + -- Trash + local icon = MineOSInterface.mainContainer.dockContainer.addIcon(MineOSPaths.trash) + icon.launchers.directory = function(icon) + MineOSInterface.safeLaunch(MineOSPaths.explorer, "-o", icon.path) + end + icon:analyseExtension() + icon.image = MineOSInterface.iconsCache.trash + + icon.eventHandler = dockIconEventHandler + + icon.onLeftClick = function(icon, eventData) + MineOSInterface.iconDoubleClick(icon, eventData) + end + + icon.onRightClick = function(icon, eventData) + local menu = MineOSInterface.contextMenu(eventData[3], eventData[4]) + menu:addItem(MineOSCore.localization.emptyTrash).onTouch = function() + local container = MineOSInterface.addUniversalContainer(MineOSInterface.mainContainer, MineOSCore.localization.areYouSure) + + container.layout:addChild(GUI.button(1, 1, 30, 1, 0xE1E1E1, 0x2D2D2D, 0xA, 0x2D2D2D, "OK")).onTouch = function() + for file in fs.list(MineOSPaths.trash) do + fs.remove(MineOSPaths.trash .. file) + end + container:delete() + computer.pushSignal("MineOSCore", "updateFileList") + end + + container.panel.onTouch = function() + container:delete() + MineOSInterface.OSDraw() + end + + MineOSInterface.OSDraw() + end + + menu:show() + end + + for i = 1, #MineOSCore.properties.dockShortcuts do + MineOSInterface.mainContainer.dockContainer.addIcon(MineOSCore.properties.dockShortcuts[i]).keepInDock = true + end + + -- Draw dock drawDock dockDraw cyka заебался искать, блядь + MineOSInterface.mainContainer.dockContainer.draw = function(dockContainer) + local color, currentDockTransparency, currentDockWidth, xPos = MineOSCore.properties.dockColor, dockTransparency, dockContainer.width - 2, dockContainer.x + + for y = dockContainer.y + dockContainer.height - 1, dockContainer.y + dockContainer.height - 4, -1 do + buffer.text(xPos, y, color, "◢", MineOSCore.properties.transparencyEnabled and currentDockTransparency) + buffer.square(xPos + 1, y, currentDockWidth, 1, color, 0xFFFFFF, " ", MineOSCore.properties.transparencyEnabled and currentDockTransparency) + buffer.text(xPos + currentDockWidth + 1, y, color, "◣", MineOSCore.properties.transparencyEnabled and currentDockTransparency) + + currentDockTransparency, currentDockWidth, xPos = currentDockTransparency + 0.08, currentDockWidth - 2, xPos + 1 + if currentDockTransparency > 1 then + currentDockTransparency = 1 + end + end + + GUI.drawContainerContent(dockContainer) + end + + -- Custom windows support + MineOSInterface.mainContainer.windowsContainer = MineOSInterface.mainContainer:addChild(GUI.container(1, 2, 1, 1)) + + -- Main menu + MineOSInterface.mainContainer.menu = MineOSInterface.mainContainer:addChild(GUI.menu(1, 1, MineOSInterface.mainContainer.width, MineOSCore.properties.menuColor, 0x555555, 0x3366CC, 0xFFFFFF)) + local item1 = MineOSInterface.mainContainer.menu:addItem("MineOS", 0x000000) + item1.onTouch = function() + local menu = MineOSInterface.contextMenu(item1.x, item1.y + 1) + + menu:addItem(MineOSCore.localization.updates).onTouch = function() + MineOSInterface.safeLaunch("/MineOS/Applications/AppMarket.app/Main.lua", "updates") + end + + menu:addSeparator() + + menu:addItem(MineOSCore.localization.logout, MineOSCore.properties.protectionMethod == "withoutProtection").onTouch = function() + login() + end + + menu:addItem(MineOSCore.localization.reboot).onTouch = function() + MineOSNetwork.broadcastComputerState(false) + require("computer").shutdown(true) + end + + menu:addItem(MineOSCore.localization.shutdown).onTouch = function() + MineOSNetwork.broadcastComputerState(false) + require("computer").shutdown() + end + + menu:addSeparator() + + menu:addItem(MineOSCore.localization.returnToShell).onTouch = function() + MineOSNetwork.broadcastComputerState(false) + MineOSInterface.mainContainer:stopEventHandling() + MineOSInterface.clearTerminal() + os.exit() + end + + menu:show() + end + + local item2 = MineOSInterface.mainContainer.menu:addItem(MineOSCore.localization.network) + item2.onTouch = function() + local container = MineOSInterface.addUniversalContainer(MineOSInterface.mainContainer, MineOSCore.localization.network) + local insertModemTextBox = container.layout:addChild(GUI.textBox(1, 1, 36, 1, nil, 0x555555, {MineOSCore.localization.networkModemNotAvailable}, 1, 0, 0, true, true)) + + local stateSwitchAndLabel = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x2D2D2D, 0xE1E1E1, 0x888888, MineOSCore.localization.networkState .. ":", MineOSCore.properties.network.enabled)) + local signalStrengthSlider = container.layout:addChild(GUI.slider(1, 1, 36, 0x66DB80, 0x2D2D2D, 0xE1E1E1, 0x888888, 0, 512, MineOSCore.properties.network.signalStrength, false, MineOSCore.localization.networkSearchRadius ..": ", "")) + signalStrengthSlider.roundValues = true + signalStrengthSlider.height = 2 + + container.layout:addChild(GUI.object(1, 1, 1, 1)) + + container.layout:addChild(GUI.label(1, 1, container.width, 1, 0xE1E1E1, MineOSCore.localization.networkName):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) + local networkNameInput = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, MineOSCore.properties.network.name or "")) + + container.layout:addChild(GUI.label(1, 1, container.width, 1, 0xE1E1E1, MineOSCore.localization.networkComputers):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) + local comboBox = container.layout:addChild(GUI.comboBox(1, 1, 36, 3, 0xE1E1E1, 0x2D2D2D, 0x444444, 0x999999)) + local allowReadAndWriteSwitchAndLabel = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x2D2D2D, 0xE1E1E1, 0x888888, MineOSCore.localization.networkAllowReadAndWrite .. ":", false)) + local noPCDetectedLabel = container.layout:addChild(GUI.label(1, 1, container.width, 1, 0x888888, MineOSCore.localization.networkComputersNotFound):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) + + local function check() + local modemAvailable = component.isAvailable("modem") + for i = 3, #container.layout.children do + container.layout.children[i].hidden = not modemAvailable + end + insertModemTextBox.hidden = modemAvailable + + if modemAvailable then + local stateSwitchAndLabelIndexOf = stateSwitchAndLabel:indexOf() + for i = 3, #container.layout.children do + if i ~= stateSwitchAndLabelIndexOf then + container.layout.children[i].hidden = not stateSwitchAndLabel.switch.state + end + end + + if stateSwitchAndLabel.switch.state then + signalStrengthSlider.hidden = not MineOSNetwork.modemProxy.isWireless() + + comboBox:clear() + for proxy, path in fs.mounts() do + if proxy.network then + local item = comboBox:addItem(MineOSNetwork.getProxyName(proxy)) + item.proxyAddress = proxy.address + item.onTouch = function() + allowReadAndWriteSwitchAndLabel.switch:setState(MineOSCore.properties.network.users[item.proxyAddress].allowReadAndWrite) + end + end + end + + noPCDetectedLabel.hidden = comboBox:count() > 0 + allowReadAndWriteSwitchAndLabel.hidden = not noPCDetectedLabel.hidden + comboBox.hidden = not noPCDetectedLabel.hidden + + if noPCDetectedLabel.hidden then + comboBox:getItem(comboBox.selectedItem).onTouch() + end + end + end + + MineOSInterface.OSDraw() + end + + networkNameInput.onInputFinished = function() + if #networkNameInput.text > 0 then + MineOSCore.properties.network.name = networkNameInput.text + MineOSCore.saveProperties() + + MineOSNetwork.broadcastComputerState(MineOSCore.properties.network.enabled) + end + end + + signalStrengthSlider.onValueChanged = function() + MineOSCore.properties.network.signalStrength = math.floor(signalStrengthSlider.value) + MineOSCore.saveProperties() + end + + stateSwitchAndLabel.switch.onStateChanged = function() + if stateSwitchAndLabel.switch.state then + MineOSNetwork.enable() + else + MineOSNetwork.disable() + end + + check() + end + + allowReadAndWriteSwitchAndLabel.switch.onStateChanged = function() + MineOSCore.properties.network.users[comboBox:getItem(comboBox.selectedItem).proxyAddress].allowReadAndWrite = allowReadAndWriteSwitchAndLabel.switch.state + MineOSCore.saveProperties() + end + + container.panel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + container:delete() + MineOSInterface.OSDraw() + elseif (eventData[1] == "component_added" or eventData[1] == "component_removed") and eventData[3] == "modem" then + check() + elseif eventData[1] == "MineOSNetwork" and eventData[2] == "updateProxyList" then + check() + end + end + + check() + end + + local item3 = MineOSInterface.mainContainer.menu:addItem(MineOSCore.localization.settings) + item3.onTouch = function() + local menu = MineOSInterface.contextMenu(item3.x, item3.y + 1) + + menu:addItem(MineOSCore.localization.screenResolution).onTouch = function() + local container = MineOSInterface.addUniversalContainer(MineOSInterface.mainContainer, MineOSCore.localization.screenResolution) + + local widthTextBox = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, tostring(MineOSCore.properties.resolution and MineOSCore.properties.resolution[1] or 160), "Width", true)) + widthTextBox.validator = function(text) + local number = tonumber(text) + if number then return number >= 1 and number <= 160 end + end + + local heightTextBox = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, tostring(MineOSCore.properties.resolution and MineOSCore.properties.resolution[2] or 50), "Height", true)) + heightTextBox.validator = function(text) + local number = tonumber(text) + if number then return number >= 1 and number <= 50 end + end + + container.panel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + container:delete() + MineOSCore.properties.resolution = {tonumber(widthTextBox.text), tonumber(heightTextBox.text)} + MineOSCore.saveProperties() + changeResolution() + changeWallpaper() + MineOSInterface.mainContainer.updateFileListAndDraw() + end + end + end + + menu:addSeparator() + + menu:addItem(MineOSCore.localization.wallpaper).onTouch = function() + local container = MineOSInterface.addUniversalContainer(MineOSInterface.mainContainer, MineOSCore.localization.wallpaper) + + local filesystemChooser = container.layout:addChild(GUI.filesystemChooser(1, 1, 36, 3, 0xE1E1E1, 0x2D2D2D, 0x444444, 0x999999, MineOSCore.properties.wallpaper, MineOSCore.localization.open, MineOSCore.localization.cancel, MineOSCore.localization.wallpaperPath, "/")) + filesystemChooser:addExtensionFilter(".pic") + filesystemChooser.onSubmit = function(path) + MineOSCore.properties.wallpaper = path + MineOSCore.saveProperties() + changeWallpaper() + + MineOSInterface.OSDraw() + end + + local comboBox = container.layout:addChild(GUI.comboBox(1, 1, 36, 3, 0xE1E1E1, 0x2D2D2D, 0x444444, 0x999999)) + comboBox.selectedItem = MineOSCore.properties.wallpaperMode or 1 + comboBox:addItem(MineOSCore.localization.wallpaperModeStretch) + comboBox:addItem(MineOSCore.localization.wallpaperModeCenter) + + local switch = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x2D2D2D, 0xE1E1E1, 0xE1E1E1, MineOSCore.localization.wallpaperEnabled .. ":", MineOSCore.properties.wallpaperEnabled)).switch + switch.onStateChanged = function() + MineOSCore.properties.wallpaperEnabled = switch.state + MineOSCore.saveProperties() + changeWallpaper() + + MineOSInterface.OSDraw() + end + + container.layout:addChild(GUI.textBox(1, 1, 36, 1, nil, 0x555555, {MineOSCore.localization.wallpaperSwitchInfo}, 1, 0, 0, true, true)) + + local slider = container.layout:addChild(GUI.slider(1, 1, 36, 0x66DB80, 0x2D2D2D, 0xE1E1E1, 0x888888, 0, 100, MineOSCore.properties.wallpaperBrightness * 100, false, MineOSCore.localization.wallpaperBrightness .. ": ", "%")) + slider.roundValues = true + slider.onValueChanged = function() + MineOSCore.properties.wallpaperBrightness = slider.value / 100 + MineOSCore.saveProperties() + changeWallpaper() + + MineOSInterface.OSDraw() + end + container.layout:addChild(GUI.object(1, 1, 1, 1)) + + comboBox.onItemSelected = function() + MineOSCore.properties.wallpaperMode = comboBox.selectedItem + MineOSCore.saveProperties() + changeWallpaper() + + MineOSInterface.OSDraw() + end + end + menu:addItem(MineOSCore.localization.screensaver).onTouch = function() + local container = MineOSInterface.addUniversalContainer(MineOSInterface.mainContainer, MineOSCore.localization.screensaver) + + local comboBox = container.layout:addChild(GUI.comboBox(1, 1, 36, 3, 0xE1E1E1, 0x2D2D2D, 0x444444, 0x999999)) + local fileList = fs.sortedList(screensaversPath, "name", false) + for i = 1, #fileList do + comboBox:addItem(fs.hideExtension(fileList[i])) + if MineOSCore.properties.screensaver == fileList[i] then + comboBox.selectedItem = i + end + end + local switch = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x2D2D2D, 0xE1E1E1, 0xE1E1E1, MineOSCore.localization.screensaverEnabled .. ":", MineOSCore.properties.screensaverEnabled)).switch + local slider = container.layout:addChild(GUI.slider(1, 1, 36, 0x66DB80, 0x2D2D2D, 0xE1E1E1, 0x888888, 1, 80, MineOSCore.properties.screensaverDelay, false, MineOSCore.localization.screensaverDelay .. ": ", "")) + + container.panel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + container:delete() + MineOSInterface.OSDraw() + + MineOSCore.properties.screensaverEnabled = switch.state + MineOSCore.properties.screensaver = fileList[comboBox.selectedItem] + MineOSCore.properties.screensaverDelay = slider.value + + MineOSCore.saveProperties() + end + end + + MineOSInterface.OSDraw() + end + + menu:addItem(MineOSCore.localization.colorScheme).onTouch = function() + local container = MineOSInterface.addUniversalContainer(MineOSInterface.mainContainer, MineOSCore.localization.colorScheme) + + local backgroundColorSelector = container.layout:addChild(GUI.colorSelector(1, 1, 36, 3, MineOSCore.properties.backgroundColor, MineOSCore.localization.backgroundColor)) + local menuColorSelector = container.layout:addChild(GUI.colorSelector(1, 1, 36, 3, MineOSCore.properties.menuColor, MineOSCore.localization.menuColor)) + local dockColorSelector = container.layout:addChild(GUI.colorSelector(1, 1, 36, 3, MineOSCore.properties.dockColor, MineOSCore.localization.dockColor)) + + local switch = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x2D2D2D, 0xE1E1E1, 0xE1E1E1, MineOSCore.localization.transparencyEnabled .. ":", MineOSCore.properties.transparencyEnabled)).switch + switch.onStateChanged = function() + MineOSCore.properties.transparencyEnabled = switch.state + MineOSCore.saveProperties() + MineOSInterface.mainContainer.menu.colors.transparency = MineOSCore.properties.transparencyEnabled and menuTransparency + container.panel.colors.background = switch.state and 0x0 or (MineOSCore.properties.backgroundColor) + container.panel.colors.transparency = switch.state and 0.2 + + MineOSInterface.OSDraw() + end + container.layout:addChild(GUI.textBox(1, 1, 36, 1, nil, 0x555555, {MineOSCore.localization.transparencySwitchInfo}, 1, 0, 0, true, true)) + + -- Шоб рисовалось в реальном времени + backgroundColorSelector.onTouch = function() + MineOSCore.properties.backgroundColor = backgroundColorSelector.color + MineOSCore.properties.menuColor = menuColorSelector.color + MineOSCore.properties.dockColor = dockColorSelector.color + MineOSInterface.mainContainer.menu.colors.default.background = MineOSCore.properties.menuColor + + MineOSInterface.OSDraw() + end + menuColorSelector.onTouch = backgroundColorSelector.onTouch + dockColorSelector.onTouch = backgroundColorSelector.onTouch + + container.panel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + container:delete() + MineOSInterface.OSDraw() + + MineOSCore.saveProperties() + end + end + end + + menu:addItem(MineOSCore.localization.iconProperties).onTouch = function() + local container = MineOSInterface.addUniversalContainer(MineOSInterface.mainContainer, MineOSCore.localization.iconProperties) + + local showExtensionSwitch = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x2D2D2D, 0xE1E1E1, 0x888888, MineOSCore.localization.showExtension .. ":", MineOSCore.properties.showExtension)).switch + local showHiddenFilesSwitch = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x2D2D2D, 0xE1E1E1, 0x888888, MineOSCore.localization.showHiddenFiles .. ":", MineOSCore.properties.showHiddenFiles)).switch + local showApplicationIconsSwitch = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x2D2D2D, 0xE1E1E1, 0x888888, MineOSCore.localization.showApplicationIcons .. ":", MineOSCore.properties.showApplicationIcons)).switch + + container.layout:addChild(GUI.label(1, 1, container.width, 1, 0xE1E1E1, MineOSCore.localization.sizeOfIcons):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) + + local iconWidthSlider = container.layout:addChild(GUI.slider(1, 1, 36, 0x66DB80, 0x2D2D2D, 0xE1E1E1, 0x888888, 8, 16, MineOSCore.properties.iconWidth, false, MineOSCore.localization.byHorizontal .. ": ", "")) + local iconHeightSlider = container.layout:addChild(GUI.slider(1, 1, 36, 0x66DB80, 0x2D2D2D, 0xE1E1E1, 0x888888, 6, 16, MineOSCore.properties.iconHeight, false, MineOSCore.localization.byVertical .. ": ", "")) + + container.layout:addChild(GUI.object(1, 1, 1, 0)) + container.layout:addChild(GUI.label(1, 1, container.width, 1, 0xE1E1E1, MineOSCore.localization.spaceBetweenIcons):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) + + local iconHorizontalSpaceBetweenSlider = container.layout:addChild(GUI.slider(1, 1, 36, 0x66DB80, 0x2D2D2D, 0xE1E1E1, 0x888888, 0, 5, MineOSCore.properties.iconHorizontalSpaceBetween, false, MineOSCore.localization.byHorizontal .. ": ", "")) + local iconVerticalSpaceBetweenSlider = container.layout:addChild(GUI.slider(1, 1, 36, 0x66DB80, 0x2D2D2D, 0xE1E1E1, 0x888888, 0, 5, MineOSCore.properties.iconVerticalSpaceBetween, false, MineOSCore.localization.byVertical .. ": ", "")) + + iconHorizontalSpaceBetweenSlider.roundValues, iconVerticalSpaceBetweenSlider.roundValues = true, true + iconWidthSlider.roundValues, iconHeightSlider.roundValues = true, true + + iconWidthSlider.onValueChanged = function() + MineOSInterface.setIconProperties(math.floor(iconWidthSlider.value), math.floor(iconHeightSlider.value), MineOSCore.properties.iconHorizontalSpaceBetween, MineOSCore.properties.iconVerticalSpaceBetween) + end + iconHeightSlider.onValueChanged = iconWidthSlider.onValueChanged + + iconHorizontalSpaceBetweenSlider.onValueChanged = function() + MineOSInterface.setIconProperties(MineOSCore.properties.iconWidth, MineOSCore.properties.iconHeight, math.floor(iconHorizontalSpaceBetweenSlider.value), math.floor(iconVerticalSpaceBetweenSlider.value)) + end + iconVerticalSpaceBetweenSlider.onValueChanged = iconHorizontalSpaceBetweenSlider.onValueChanged + + showExtensionSwitch.onStateChanged = function() + MineOSCore.properties.showExtension = showExtensionSwitch.state + MineOSCore.properties.showHiddenFiles = showHiddenFilesSwitch.state + MineOSCore.properties.showApplicationIcons = showApplicationIconsSwitch.state + MineOSCore.saveProperties() + + computer.pushSignal("MineOSCore", "updateFileList") + end + showHiddenFilesSwitch.onStateChanged, showApplicationIconsSwitch.onStateChanged = showExtensionSwitch.onStateChanged, showExtensionSwitch.onStateChanged + end + + menu:addSeparator() + + menu:addItem(MineOSCore.localization.setProtectionMethod).onTouch = function() + setProtectionMethod() + end + + menu:show() + end + + MineOSInterface.mainContainer.menuLayout = MineOSInterface.mainContainer:addChild(GUI.layout(1, 1, 1, 1, 1, 1)) + MineOSInterface.mainContainer.menuLayout:setCellSpacing(1, 1, 0) + MineOSInterface.mainContainer.menuLayout:setCellDirection(1, 1, GUI.directions.horizontal) + MineOSInterface.mainContainer.menuLayout:setCellAlignment(1, 1, GUI.alignment.horizontal.right, GUI.alignment.vertical.top) + + local dateButton = MineOSInterface.addMenuWidget(GUI.button(1, 1, 1, 1, nil, 0x0, 0x3366CC, 0xFFFFFF, " ")) + dateButton.switchMode = true + + dateButton.onTouch = function() + local menu = MineOSInterface.contextMenu(dateButton.x, dateButton.y + 1) + for i = -12, 12 do + menu:addItem("GMT" .. (i >= 0 and "+" or "") .. i).onTouch = function() + MineOSCore.properties.timezone = i + MineOSCore.saveProperties() + + MineOSCore.OSUpdateTimezone() + MineOSCore.OSUpdateDate() + MineOSInterface.OSDraw() + end + end + menu:show() + dateButton.pressed = false + MineOSInterface.OSDraw() + end + + MineOSCore.OSUpdateTimezone = function() + local timezone = MineOSCore.properties.timezone or 0 + timezoneCorrection = timezone * 3600 + end + + MineOSCore.OSUpdateDate = function() + if not realTimestamp then + local name = MineOSPaths.system .. "/Timestamp.tmp" + local file = io.open(name, "w") + file:close() + realTimestamp = math.floor(fs.lastModified(name) / 1000) + fs.remove(name) + end + + local firstPart, month, secondPart = os.date( + "%d %b %Y %T", + realTimestamp + computerDateUptime - computerUptimeOnBoot + timezoneCorrection + ):match("(%d+%s)(%a+)(.+)") + + dateButton.text = firstPart .. (MineOSCore.localization.months[month] or "monthNotAvailable:" .. month) .. secondPart + dateButton.width = unicode.len(dateButton.text) + 2 + end + + MineOSInterface.OSDraw = function(force) + MineOSInterface.mainContainer:draw() + buffer.draw(force) + end + + MineOSInterface.mainContainer.updateFileListAndDraw = function(forceRedraw) + MineOSInterface.mainContainer.iconField:updateFileList() + MineOSInterface.OSDraw(forceRedraw) + end + + MineOSInterface.mainContainer.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "key_down" then + local windowsCount = #MineOSInterface.mainContainer.windowsContainer.children + -- Ctrl or CMD + if windowsCount > 0 and not eventData.lastWindowHandled and (keyboard.isKeyDown(29) or keyboard.isKeyDown(219)) then + -- W + if eventData[4] == 17 then + eventData.lastWindowHandled = true + MineOSInterface.mainContainer.windowsContainer.children[windowsCount]:close() + + mainContainer:draw() + buffer.draw() + -- H + elseif eventData[4] == 35 then + eventData.lastWindowHandled = true + + local lastUnhiddenWindowIndex = 1 + for i = 1, #MineOSInterface.mainContainer.windowsContainer.children do + if not MineOSInterface.mainContainer.windowsContainer.children[i].hidden then + lastUnhiddenWindowIndex = i + end + end + MineOSInterface.mainContainer.windowsContainer.children[lastUnhiddenWindowIndex]:minimize() + + mainContainer:draw() + buffer.draw() + end + end + elseif eventData[1] == "MineOSCore" then + if eventData[2] == "updateFileList" then + MineOSInterface.mainContainer.updateFileListAndDraw() + elseif eventData[2] == "updateFileListAndBufferTrueRedraw" then + MineOSInterface.mainContainer.updateFileListAndDraw(true) + elseif eventData[2] == "updateWallpaper" then + changeWallpaper() + MineOSInterface.OSDraw() + end + elseif eventData[1] == "MineOSNetwork" then + if eventData[2] == "accessDenied" then + GUI.error(MineOSCore.localization.networkAccessDenied) + elseif eventData[2] == "timeout" then + GUI.error(MineOSCore.localization.networkTimeout) + end + end + + local computerUptime = computer.uptime() + + if computerUptime - computerDateUptime >= 1 then + MineOSCore.OSUpdateDate() + MineOSInterface.OSDraw() + computerDateUptime = computerUptime + end + + if MineOSCore.properties.screensaverEnabled then + if eventData[1] then + screensaverUptime = computer.uptime() + end + + if computerUptime - screensaverUptime >= MineOSCore.properties.screensaverDelay then + if fs.exists(screensaversPath .. MineOSCore.properties.screensaver) then + MineOSInterface.safeLaunch(screensaversPath .. MineOSCore.properties.screensaver) + MineOSInterface.OSDraw(true) + end + + screensaverUptime = computer.uptime() + end + end + end +end + +---------------------------------------------- Сама ОС ------------------------------------------------------------------------ + +MineOSCore.localization = table.fromFile(MineOSPaths.localizationFiles .. MineOSCore.properties.language .. ".lang") + +createOSWindow() +changeResolution() +changeWallpaper() +MineOSCore.OSUpdateTimezone() +MineOSCore.OSUpdateDate() +login() + +MineOSNetwork.update() + +while true do + local success, path, line, traceback = MineOSCore.call( + MineOSInterface.mainContainer.startEventHandling, + MineOSInterface.mainContainer, + 0 + ) + if success then + break + else + createOSWindow() + changeResolution() + changeWallpaper() + MineOSCore.OSUpdateDate() + MineOSInterface.mainContainer.updateFileListAndDraw() + + MineOSInterface.showErrorWindow(path, line, traceback) + + MineOSInterface.OSDraw() + end +end diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/OSEnergyTurrets.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/OSEnergyTurrets.lua new file mode 100644 index 00000000..71c1bd2c --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/OSEnergyTurrets.lua @@ -0,0 +1,75 @@ +local component = require("component") +local event = require("event") + +local rad180 = math.rad(180) +local playerHitpointYOffset = 1.2 +local shaftSingleExtensionValue = 0.5 +local defaultShaftLength = 2 + +local turrets = { + ["4b1229f4-640c-4288-8055-3fc1d9761b4c"] = { + x = -221.5, + y = 75.5, + z = 324.5 + }, + ["c7646649-292c-49e5-8c4a-4549511cce87"] = { + x = -220.5, + y = 75.5, + z = 324.5 + }, + ["86a3b628-8f8b-42e5-b890-2ec6c2065d36"] = { + x = -218.5, + y = 75.5, + z = 324.5 + }, + ["bdb164ab-af71-4eb0-8fe0-cdd0fc40364e"] = { + x = -216.5, + y = 75.5, + z = 324.5 + }, + ["a03228e7-0041-4909-acb0-8f78d7ddfc24"] = { + x = -215.5, + y = 75.5, + z = 324.5 + }, +} +for address in pairs(turrets) do + turrets[address].proxy = component.proxy(address) + turrets[address].proxy.extendShaft(defaultShaftLength) +end + +local scanners = {} +for address in component.list("os_entdetector") do + table.insert(scanners, component.proxy(address)) +end + +while true do + local entities = {} + for i = 1, #scanners do + local localEntities = scanners[i].scanPlayers(512) + for j = 1, #localEntities do + entities[localEntities[j].name] = localEntities[j] + end + end + + for name, data in pairs(entities) do + for _, turret in pairs(turrets) do + local dx = data.x - turret.x + local dy = (data.y + playerHitpointYOffset) - (turret.y + turret.proxy.getShaftLength() * shaftSingleExtensionValue) + local dz = data.z - turret.z + + turret.proxy.moveToRadians( + dz > 0 and rad180 - math.atan(dx / dz) or -math.atan(dx / dz), + dz > 0 and math.atan(dy / dz) or -math.atan(dy / dz) + ) + + if turret.proxy.isReady() and turret.proxy.isOnTarget() then + turret.proxy.fire() + end + end + + break + end + + os.sleep(0.05) +end \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/Tanks/1.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/Tanks/1.pic new file mode 100644 index 00000000..b8654431 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/Tanks/1.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/Tanks/2.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/Tanks/2.pic new file mode 100644 index 00000000..08d326bc Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/Tanks/2.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/Tanks/3.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/Tanks/3.pic new file mode 100644 index 00000000..5f1ea635 Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/Tanks/3.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/Tanks/4.pic b/640cd89f-8e29-4b66-a0eb-7680c33760b4/Tanks/4.pic new file mode 100644 index 00000000..ac02a78e Binary files /dev/null and b/640cd89f-8e29-4b66-a0eb-7680c33760b4/Tanks/4.pic differ diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/autorunGenerator.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/autorunGenerator.lua new file mode 100644 index 00000000..0b25b3c3 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/autorunGenerator.lua @@ -0,0 +1,268 @@ + +------------------------------------------ Библиотеки --------------------------------------------------------------- + +local ecs = require("ECSAPI") +local fs = require("filesystem") +local gpu = require("component").gpu +local unicode = require("unicode") +local event = require("event") +local serialization = require("serialization") + +------------------------------------------ Переменные --------------------------------------------------------------- + +local width, height = 70, 30 +local x, y = ecs.correctStartCoords("auto", "auto", width, height) +local oldPixels = ecs.rememberOldPixels(x, y, x + width - 1, y + height - 1) +local dataWidth, dataHeight = width - 6, height - 14 +local drawListFrom = 1 +local selectedObject = 3 +local pathToList = "MineOS/System/AutorunManager/Filelist.txt" +local autorunObjects = { + -- { path = "OS.lua", enabled = true, size = 30 }, + -- { path = "Cyka/Home.lua", enabled = true, size = 30 }, + -- { path = "Pidar/Lalra/Cyka.lua", enabled = true, size = 30 }, + -- { path = "322File.lua", enabled = false, size = 30 }, + -- { path = "SasiHyu.lua", enabled = true, size = 30 }, + -- { path = "Blabla.cfg", enabled = false, size = 30 }, +} + +------------------------------------------ Функции --------------------------------------------------------------- + +--Объекты для тача +local obj = {} +local function newObj(class, name, ...) + obj[class] = obj[class] or {} + obj[class][name] = {...} +end + +local function saveAutorun() + local file = io.open("autorun.lua", "w") + file:write("local success, reason\n") + for i = 1, #autorunObjects do + if autorunObjects[i].enabled then + file:write("success, reason = pcall(loadfile(\"" .. autorunObjects[i].path .. "\")); if not success then print(\"Ошибка: \" .. tostring(reason)) end\n") + end + end + file:close() +end + +local function saveList() + local file = io.open(pathToList, "w") + file:write(serialization.serialize(autorunObjects)) + file:close() +end + +local function loadList() + if fs.exists(pathToList) then + local file = io.open(pathToList, "r") + local text = file:read("*a") + autorunObjects = serialization.unserialize(text) + file:close() + else + fs.makeDirectory(fs.path(pathToList)) + saveList() + end +end + +local function drawFiles(x, y) + + local limit, from = dataHeight, drawListFrom + + obj["List"] = {} + + local yPos = y + 1 + + ecs.square(x, y, dataWidth, dataHeight, 0xFFFFFF) + ecs.square(x, y, dataWidth, 1, ecs.colors.blue) + gpu.setForeground(0xFFFFFF) + gpu.set(x + 1, y, "Запуск") + gpu.set(x + 9, y, "Файл") + gpu.set(x + 48, y, "Размер") + + ecs.srollBar(x + dataWidth - 1, yPos, 1, dataHeight - 1, #autorunObjects == 0 and from or #autorunObjects, from, 0xCCCCCC, ecs.colors.lightBlue) + + + local color, color2 + for i = from, (from + #autorunObjects - 1) do + if i > limit then break end + if i % 2 == 0 then color = 0xFFFFFF; color2 = 0x262626 else color = 0xEEEEEE; color2 = 0x262626 end + if i == selectedObject then color = ecs.colors.green; color2 = 0xFFFFFF end + + if autorunObjects[i] then + + ecs.square(x, yPos, dataWidth - 1, 1, color) + + if autorunObjects[i].enabled then + ecs.colorTextWithBack(x + 3, yPos, ecs.colors.blue, color, "✔") + else + ecs.colorTextWithBack(x + 3, yPos, ecs.colors.red, color, "❌") + end + + gpu.setBackground(color) + gpu.setForeground(color2) + gpu.set(x + 9, yPos, ecs.stringLimit("start", autorunObjects[i].path, 37)) + + gpu.set(x + 48, yPos, autorunObjects[i].size .. " КБ") + + newObj("List", i, x, yPos, x + dataWidth - 1, yPos) + + yPos = yPos + 1 + end + end +end + +local function drawWindow() + local xPos, yPos + + ecs.square(x, y, width, height, 0xDDDDDD) + + xPos = x + 3 + yPos = y + 4 + + ecs.colorText(xPos, yPos, 0x262626, "Эти объекты будут запускаться автоматически при загрузке:") + yPos = yPos + 2 + + ecs.square(x, y, width, 3, 0xCCCCCC) + + ecs.centerText("x", y + 1, "Менеджер автозагрузки") + + drawFiles(x + 3, y + 6) + + yPos = y + height - 7 + ecs.colorTextWithBack(xPos, yPos, 0x262626, 0xDDDDDD, "Чтобы отключить загрузку файла, снимите галочку рядом с именем") + yPos = yPos + 1 + gpu.set(xPos, yPos, "программы. Приоритет загузки снижается сверху вниз.") + yPos = yPos + 2 + + local name + name = "+"; newObj("Buttons", name, ecs.drawAdaptiveButton(xPos, yPos, 2, 1, name, 0xFFFFFF, 0x262626)); xPos = obj["Buttons"][name][3] + 2 + name = "-"; newObj("Buttons", name, ecs.drawAdaptiveButton(xPos, yPos, 2, 1, name, 0xFFFFFF, 0x262626)); xPos = obj["Buttons"][name][3] + 2 + + name = "Выше"; newObj("Buttons", name, ecs.drawAdaptiveButton(xPos, yPos, 2, 1, name, 0xFFFFFF, 0x262626)); xPos = obj["Buttons"][name][3] + 2 + name = "Ниже"; newObj("Buttons", name, ecs.drawAdaptiveButton(xPos, yPos, 2, 1, name, 0xFFFFFF, 0x262626)); xPos = obj["Buttons"][name][3] + 2 + -- if fs.isAutorunEnabled() then + -- name = "Выключить автозапуск" + -- else + -- name = "Включить автозапуск " + -- end + -- newObj("Buttons", name, ecs.drawAdaptiveButton(xPos, yPos, 2, 1, name, 0xAAAAAA, 0xFFFFFF)); xPos = obj["Buttons"][name][3] + 2 + + xPos = x + width - 12 + name = "Выход"; newObj("Buttons", name, ecs.drawAdaptiveButton(xPos, yPos, 2, 1, name, 0x888888, 0xFFFFFF)) +end + +------------------------------------------ Программа --------------------------------------------------------------- + +loadList() +drawWindow() + +while true do + local e = {event.pull()} + if e[1] == "touch" then + --if obj["List"] and #obj["List"] > 0 then + for key in pairs(obj["List"]) do + if ecs.clickedAtArea(e[3], e[4], obj["List"][key][1], obj["List"][key][2], obj["List"][key][3], obj["List"][key][4]) then + if selectedObject ~= key then + selectedObject = key + drawFiles(x + 3, y + 6) + else + if e[3] >= obj["List"][key][1] + 2 and e[3] <= obj["List"][key][1] + 4 then + autorunObjects[key].enabled = not autorunObjects[key].enabled + drawFiles(x + 3, y + 6) + saveList() + saveAutorun() + end + end + break + end + end + --end + + for key in pairs(obj["Buttons"]) do + if ecs.clickedAtArea(e[3], e[4], obj["Buttons"][key][1], obj["Buttons"][key][2], obj["Buttons"][key][3], obj["Buttons"][key][4]) then + ecs.drawAdaptiveButton(obj["Buttons"][key][1], obj["Buttons"][key][2], 2, 1, key, ecs.colors.blue, 0xFFFFFF) + os.sleep(0.2) + ecs.drawAdaptiveButton(obj["Buttons"][key][1], obj["Buttons"][key][2], 2, 1, key, 0xFFFFFF, 0x262626) + + if key == "-" then + table.remove(autorunObjects, selectedObject) + if drawListFrom == selectedObject then drawListFrom = 1 end + drawFiles(x + 3, y + 6) + saveList() + saveAutorun() + elseif key == "+" then + local data = ecs.universalWindow("auto", "auto", 36, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x880000, "Добавить новый файл"}, {"EmptyLine"}, {"Input", 0x262626, 0x880000, "Путь к файлу"}, {"EmptyLine"}, {"Button", {0x888888, 0xffffff, "Добавить"}, {0xAAAAAA, 0xffffff, "Отмена"}}) + if data[2] == "Добавить" then + if fs.exists(data[1]) then + local cyka = false + for i = 1, #autorunObjects do + if autorunObjects[i].path == data[1] then cyka = true end + end + if not cyka then + table.insert(autorunObjects, { path = data[1], enabled = true, size = math.ceil(fs.size(data[1]) / 1024) }) + drawFiles(x + 3, y + 6) + saveList() + saveAutorun() + else + ecs.error("Файл \"" .. data[1] .. "\" уже есть в этом списке!") + end + else + ecs.error("Файл \"" .. data[1] .. "\" не существует!") + end + end + elseif key == "Выше" then + if selectedObject > 1 then + local cyka = autorunObjects[selectedObject] + table.remove(autorunObjects, selectedObject) + table.insert(autorunObjects, selectedObject - 1, cyka) + selectedObject = selectedObject - 1 + drawFiles(x + 3, y + 6) + saveList() + saveAutorun() + end + elseif key == "Ниже" then + if selectedObject < #autorunObjects then + local cyka = autorunObjects[selectedObject] + table.remove(autorunObjects, selectedObject) + table.insert(autorunObjects, selectedObject + 1, cyka) + selectedObject = selectedObject + 1 + drawFiles(x + 3, y + 6) + saveList() + saveAutorun() + end + elseif key == "Выход" then + ecs.drawOldPixels(oldPixels) + return + -- elseif key == "Включить автозапуск " then + -- fs.setAutorunEnabled(true) + -- drawWindow() + -- elseif key == "Выключить автозапуск" then + -- fs.setAutorunEnabled(false) + -- drawWindow() + end + + break + end + end + + elseif e[1] == "scroll" then + if e[5] == 1 then + if drawListFrom > 1 then drawListFrom = drawListFrom - 1; drawFiles(x + 3, y + 6) end + else + if drawListFrom < #autorunObjects then drawListFrom = drawListFrom + 1; drawFiles(x + 3, y + 6) end + end + end +end + + + + + + + + + + + + + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/address.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/address.lua new file mode 100755 index 00000000..c05461d4 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/address.lua @@ -0,0 +1,2 @@ +local computer = require("computer") +io.write(computer.address(),"\n") diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/alias.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/alias.lua new file mode 100755 index 00000000..a9594a44 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/alias.lua @@ -0,0 +1,62 @@ +local shell = require("shell") +local args, options = shell.parse(...) + +local ec, error_prefix = 0, "alias:" + +if options.help then + print(string.format("Usage: alias: [name[=value] ... ]", cmd_name)) + return +end + +local function validAliasName(k) + return k:match("[/%$`=|&;%(%)<> \t]") == nil +end + +local function setAlias(k, v) + if not validAliasName(k) then + io.stderr:write(string.format("%s `%s': invalid alias name\n", error_prefix, k)) + else + shell.setAlias(k, v) + end +end + +local function printAlias(k) + local v = shell.getAlias(k) + if not v then + io.stderr:write(string.format("%s %s: not found\n", error_prefix, k)) + ec = 1 + else + io.write(string.format("alias %s='%s'\n", k, v)) + end +end + +local function splitPair(arg) + local matchBegin, matchEnd = arg:find("=") + if matchBegin == nil or matchBegin == 1 then + return arg + else + return arg:sub(1, matchBegin - 1), arg:sub(matchEnd + 1) + end +end + +local function handlePair(k, v) + if v then + return setAlias(k, v) + else + return printAlias(k) + end +end + +if not next(args) then -- no args + -- print all aliases + for k,v in shell.aliases() do + print(string.format("alias %s='%s'", k, v)) + end +else + for k,v in pairs(args) do + checkArg(1,v,"string") + handlePair(splitPair(v)) + end +end + +return ec diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/cat.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/cat.lua new file mode 100755 index 00000000..6a943ab7 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/cat.lua @@ -0,0 +1,37 @@ +local shell = require("shell") +local fs = require("filesystem") + +local args = shell.parse(...) +local ec = 0 +if #args == 0 then + args = {"-"} +end + +for i = 1, #args do + local arg = args[i] + if fs.isDirectory(arg) then + io.stderr:write(string.format('cat %s: Is a directory\n', arg)) + ec = 1 + else + local file, reason + if args[i] == "-" then + file, reason = io.stdin, "missing stdin" + else + file, reason = io.open(shell.resolve(args[i])) + end + if not file then + io.stderr:write(string.format("cat: %s: %s\n", args[i], tostring(reason))) + ec = 1 + else + repeat + local line = file:read("*L") + if line then + io.write(line) + end + until not line + file:close() + end + end +end + +return ec diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/cd.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/cd.lua new file mode 100755 index 00000000..44236919 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/cd.lua @@ -0,0 +1,51 @@ +local shell = require("shell") +local fs = require("filesystem") + +local args, ops = shell.parse(...) +local path = nil +local verbose = false + +if ops.help then + print( +[[Usage cd [dir] +For more options, run: man cd]]) + return +end + +if #args == 0 then + local home = os.getenv("HOME") + if not home then + io.stderr:write("cd: HOME not set\n") + return 1 + end + path = home +elseif args[1] == '-' then + verbose = true + local oldpwd = os.getenv("OLDPWD"); + if not oldpwd then + io.stderr:write("cd: OLDPWD not set\n") + return 1 + end + path = oldpwd +else + path = args[1] +end + +local resolved = shell.resolve(path) +if not fs.exists(resolved) then + io.stderr:write("cd: ",path,": No such file or directory\n") + return 1 +end + +path = resolved +local oldpwd = shell.getWorkingDirectory() +local result, reason = shell.setWorkingDirectory(path) +if not result then + io.stderr:write("cd: ", path, ": ", reason) + return 1 +else + os.setenv("OLDPWD", oldpwd) +end +if verbose then + os.execute("pwd") +end diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/clear.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/clear.lua new file mode 100755 index 00000000..19f6961f --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/clear.lua @@ -0,0 +1,8 @@ + +local gpu = require("component").gpu +gpu.setBackground(0x1B1B1B) +gpu.setForeground(0xEEEEEE) + +local width, height = gpu.getResolution() +gpu.fill(1, 1, width, height, " ") +require("term").setCursor(1, 1) \ No newline at end of file diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/components.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/components.lua new file mode 100755 index 00000000..7039f406 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/components.lua @@ -0,0 +1,52 @@ +local component = require("component") +local shell = require("shell") +local text = require("text") + +local args, options = shell.parse(...) +local count = tonumber(options.limit) or math.huge + +local components = {} +local padTo = 1 + +if #args == 0 then -- get all components if no filters given. + args[1] = "" +end +for _, filter in ipairs(args) do + for address, name in component.list(filter) do + if name:len() > padTo then + padTo = name:len() + 2 + end + components[address] = name + end +end + +padTo = padTo + 8 - padTo % 8 +for address, name in pairs(components) do + io.write(text.padRight(name, padTo) .. address .. '\n') + + if options.l then + local proxy = component.proxy(address) + local padTo = 1 + local methods = {} + for name, member in pairs(proxy) do + if type(member) == "table" or type(member) == "function" then + if name:len() > padTo then + padTo = name:len() + 2 + end + table.insert(methods, name) + end + end + table.sort(methods) + padTo = padTo + 8 - padTo % 8 + + for _, name in ipairs(methods) do + local doc = tostring(proxy[name]) + io.write(" " .. text.padRight(name, padTo) .. doc .. '\n') + end + end + + count = count - 1 + if count <= 0 then + break + end +end diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/cp.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/cp.lua new file mode 100755 index 00000000..a69e4c1a --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/cp.lua @@ -0,0 +1,32 @@ +local shell = require("shell") +local transfer = require("tools/transfer") + +local args, options = shell.parse(...) +options.h = options.h or options.help +if #args < 2 or options.h then + io.write("Usage: cp [-inrv] \n") + io.write(" -i: prompt before overwrite (overrides -n option).\n") + io.write(" -n: do not overwrite an existing file.\n") + io.write(" -r: copy directories recursively.\n") + io.write(" -u: copy only when the SOURCE file differs from the destination\n") + io.write(" file or when the destination file is missing.\n") + io.write(" -P: preserve attributes, e.g. symbolic links.\n") + io.write(" -v: verbose output.\n") + io.write(" -x: stay on original source file system.\n") + return not not options.h +end + +-- clean options for copy (as opposed to move) +options = +{ + cmd = "cp", + i = options.i, + n = options.n, + r = options.r, + u = options.u, + P = options.P, + v = options.v, + x = options.x, +} + +return transfer.batch(args, options) diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/date.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/date.lua new file mode 100755 index 00000000..da077bb8 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/date.lua @@ -0,0 +1 @@ +io.write(os.date("%F %T").."\n") diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/df.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/df.lua new file mode 100755 index 00000000..d7b6184c --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/df.lua @@ -0,0 +1,76 @@ +local fs = require("filesystem") +local shell = require("shell") +local text = require("text") + +local args, options = shell.parse(...) + +local function formatSize(size) + if not options.h then + return tostring(size) + elseif type(size) == "string" then + return size + end + local sizes = {"", "K", "M", "G"} + local unit = 1 + local power = options.si and 1000 or 1024 + while size > power and unit < #sizes do + unit = unit + 1 + size = size / power + end + return math.floor(size * 10) / 10 .. sizes[unit] +end + +local mounts = {} +if #args == 0 then + for proxy, path in fs.mounts() do + if not mounts[proxy] or mounts[proxy]:len() > path:len() then + mounts[proxy] = path + end + end +else + for i = 1, #args do + local proxy, path = fs.get(shell.resolve(args[i])) + if not proxy then + io.stderr:write(args[i], ": no such file or directory\n") + else + mounts[proxy] = path + end + end +end + +local result = {{"Filesystem", "Used", "Available", "Use%", "Mounted on"}} +for proxy, path in pairs(mounts) do + local label = proxy.getLabel() or proxy.address + local used, total = proxy.spaceUsed(), proxy.spaceTotal() + local available, percent + if total == math.huge then + used = used or "N/A" + available = "unlimited" + percent = "0%" + else + available = total - used + percent = used / total + if percent ~= percent then -- NaN + available = "N/A" + percent = "N/A" + else + percent = math.ceil(percent * 100) .. "%" + end + end + table.insert(result, {label, formatSize(used), formatSize(available), tostring(percent), path}) +end + +local m = {} +for _, row in ipairs(result) do + for col, value in ipairs(row) do + m[col] = math.max(m[col] or 1, value:len()) + end +end + +for _, row in ipairs(result) do + for col, value in ipairs(row) do + local padding = col == #row and 0 or 2 + io.write(text.padRight(value, m[col] + padding)) + end + print() +end diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/dmesg.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/dmesg.lua new file mode 100755 index 00000000..038b3d7a --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/dmesg.lua @@ -0,0 +1,38 @@ +local event = require "event" +local term = require "term" + +local args = {...} +local gpu = term.gpu() +local interactive = io.output().tty +local color, isPal, evt +if interactive then + color, isPal = gpu.getForeground() +end +io.write("Press 'Ctrl-C' to exit\n") +pcall(function() + repeat + if #args > 0 then + evt = table.pack(event.pullMultiple("interrupted", table.unpack(args))) + else + evt = table.pack(event.pull()) + end + if interactive then gpu.setForeground(0xCC2200) end + io.write("[" .. os.date("%T") .. "] ") + if interactive then gpu.setForeground(0x44CC00) end + io.write(tostring(evt[1]) .. string.rep(" ", math.max(10 - #tostring(evt[1]), 0) + 1)) + if interactive then gpu.setForeground(0xB0B00F) end + io.write(tostring(evt[2]) .. string.rep(" ", 37 - #tostring(evt[2]))) + if interactive then gpu.setForeground(0xFFFFFF) end + if evt.n > 2 then + for i = 3, evt.n do + io.write(" " .. tostring(evt[i])) + end + end + + io.write("\n") + until evt[1] == "interrupted" +end) +if interactive then + gpu.setForeground(color, isPal) +end + diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/du.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/du.lua new file mode 100755 index 00000000..864e6518 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/du.lua @@ -0,0 +1,128 @@ +local shell = require("shell") +local fs = require("filesystem") + +local args, options, reason = shell.parse(...) +if #args == 0 then + args[1] = '.' +end + +local TRY=[[ +Try 'du --help' for more information.]] + +local VERSION=[[ +du (OpenOS bin) 1.0 +Written by payonel, patterned after GNU coreutils du]] + +local HELP=[[ +Usage: du [OPTION]... [FILE]... +Summarize disk usage of each FILE, recursively for directories. + + -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G) + -s, --summarize display only a total for each argument + --help display this help and exit + --version output version information and exit]] + +if options.help then + print(HELP) + return true +end + +if options.version then + print(VERSION) + return true +end + +local function addTrailingSlash(path) + if path:sub(-1) ~= '/' then + return path .. '/' + else + return path + end +end + +local function opCheck(shortName, longName) + local enabled = options[shortName] or options[longName] + options[shortName] = nil + options[longName] = nil + return enabled +end + +local bHuman = opCheck('h', 'human-readable') +local bSummary = opCheck('s', 'summarize') + +if next(options) then + for op,v in pairs(options) do + io.stderr:write(string.format("du: invalid option -- '%s'\n", op)) + end + io.stderr:write(TRY..'\n') + return 1 +end + +local function formatSize(size) + if not bHuman then + return tostring(size) + end + local sizes = {"", "K", "M", "G"} + local unit = 1 + local power = options.si and 1000 or 1024 + while size > power and unit < #sizes do + unit = unit + 1 + size = size / power + end + + return math.floor(size * 10) / 10 .. sizes[unit] +end + +local function printSize(size, rpath) + local displaySize = formatSize(size) + io.write(string.format("%s%s\n", string.format("%-12s", displaySize), rpath)) +end + +local function visitor(rpath) + local subtotal = 0 + local dirs = 0 + local spath = shell.resolve(rpath) + + if fs.isDirectory(spath) then + local list_result = fs.list(spath) + for list_item in list_result do + local vtotal, vdirs = visitor(addTrailingSlash(rpath) .. list_item) + subtotal = subtotal + vtotal + dirs = dirs + vdirs + end + + if dirs == 0 then -- no child dirs + if not bSummary then + printSize(subtotal, rpath) + end + end + + elseif not fs.isLink(spath) then + subtotal = fs.size(spath) + end + + return subtotal, dirs +end + +for i,arg in ipairs(args) do + local path = shell.resolve(arg) + + if not fs.exists(path) then + io.stderr:write(string.format("du: cannot access '%s': no such file or directory\n", arg)) + return 1 + else + if fs.isDirectory(path) then + local total = visitor(arg) + + if bSummary then + printSize(total, arg) + end + elseif fs.isLink(path) then + printSize(0, arg) + else + printSize(fs.size(path), arg) + end + end +end + +return true diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/echo.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/echo.lua new file mode 100755 index 00000000..db036c3e --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/echo.lua @@ -0,0 +1,11 @@ +local args, options = require("shell").parse(...) +if options.help then + print([[`echo` writes the provided string(s) to the standard output. + -n do not output the trialing newline + --help display this help and exit]]) + return +end +io.write(table.concat(args," ")) +if not options.n then + print() +end diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/edit.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/edit.lua new file mode 100755 index 00000000..a5f9cbe3 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/edit.lua @@ -0,0 +1,682 @@ +local event = require("event") +local fs = require("filesystem") +local keyboard = require("keyboard") +local shell = require("shell") +local term = require("term") +local text = require("text") +local unicode = require("unicode") + +if not term.isAvailable() then + return +end +local gpu = term.gpu() +local args, options = shell.parse(...) +if #args == 0 then + io.write("Usage: edit ") + return +end + +local filename = shell.resolve(args[1]) + +local readonly = options.r or fs.get(filename) == nil or fs.get(filename).isReadOnly() + +if fs.isDirectory(filename) then + io.stderr:write("file is a directory\n") + return 1 +elseif not fs.exists(filename) and readonly then + io.stderr:write("file system is read only\n") + return 1 +end + +local function loadConfig() + -- Try to load user settings. + local env = {} + local config = loadfile("/etc/edit.cfg", nil, env) + if config then + pcall(config) + end + -- Fill in defaults. + env.keybinds = env.keybinds or { + left = {{"left"}}, + right = {{"right"}}, + up = {{"up"}}, + down = {{"down"}}, + home = {{"home"}}, + eol = {{"end"}}, + pageUp = {{"pageUp"}}, + pageDown = {{"pageDown"}}, + + backspace = {{"back"}}, + delete = {{"delete"}}, + deleteLine = {{"control", "delete"}, {"shift", "delete"}}, + newline = {{"enter"}}, + + save = {{"control", "s"}}, + close = {{"control", "w"}}, + find = {{"control", "f"}}, + findnext = {{"control", "g"}, {"control", "n"}, {"f3"}} + } + -- Generate config file if it didn't exist. + if not config then + local root = fs.get("/") + if root and not root.isReadOnly() then + fs.makeDirectory("/etc") + local f = io.open("/etc/edit.cfg", "w") + if f then + local serialization = require("serialization") + for k, v in pairs(env) do + f:write(k.."="..tostring(serialization.serialize(v, math.huge)).."\n") + end + f:close() + end + end + end + return env +end + +term.clear() +term.setCursorBlink(true) + +local running = true +local buffer = {} +local scrollX, scrollY = 0, 0 +local config = loadConfig() + +local getKeyBindHandler -- forward declaration for refind() + +local function helpStatusText() + local function prettifyKeybind(label, command) + local keybind = type(config.keybinds) == "table" and config.keybinds[command] + if type(keybind) ~= "table" or type(keybind[1]) ~= "table" then return "" end + local alt, control, shift, key + for _, value in ipairs(keybind[1]) do + if value == "alt" then alt = true + elseif value == "control" then control = true + elseif value == "shift" then shift = true + else key = value end + end + if not key then return "" end + return label .. ": [" .. + (control and "Ctrl+" or "") .. + (alt and "Alt+" or "") .. + (shift and "Shift+" or "") .. + unicode.upper(key) .. + "] " + end + return prettifyKeybind("Save", "save") .. + prettifyKeybind("Close", "close") .. + prettifyKeybind("Find", "find") +end + +------------------------------------------------------------------------------- + +local function setStatus(value) + local x, y, w, h = term.getGlobalArea() + value = unicode.wlen(value) > w - 10 and unicode.wtrunc(value, w - 9) or value + value = text.padRight(value, w - 10) + gpu.set(x, y + h - 1, value) +end + +local function getArea() + local x, y, w, h = term.getGlobalArea() + return x, y, w, h - 1 +end + +local function removePrefix(line, length) + if length >= unicode.wlen(line) then + return "" + else + local prefix = unicode.wtrunc(line, length + 1) + local suffix = unicode.sub(line, unicode.len(prefix) + 1) + length = length - unicode.wlen(prefix) + if length > 0 then + suffix = (" "):rep(unicode.charWidth(suffix) - length) .. unicode.sub(suffix, 2) + end + return suffix + end +end + +local function lengthToChars(line, length) + if length > unicode.wlen(line) then + return unicode.len(line) + 1 + else + local prefix = unicode.wtrunc(line, length) + return unicode.len(prefix) + 1 + end +end + + +local function isWideAtPosition(line, x) + local index = lengthToChars(line, x) + if index > unicode.len(line) then + return false, false + end + local prefix = unicode.sub(line, 1, index) + local char = unicode.sub(line, index, index) + --isWide, isRight + return unicode.isWide(char), unicode.wlen(prefix) == x +end + +local function drawLine(x, y, w, h, lineNr) + local yLocal = lineNr - scrollY + if yLocal > 0 and yLocal <= h then + local str = removePrefix(buffer[lineNr] or "", scrollX) + str = unicode.wlen(str) > w and unicode.wtrunc(str, w + 1) or str + str = text.padRight(str, w) + gpu.set(x, y - 1 + lineNr - scrollY, str) + end +end + +local function getCursor() + local cx, cy = term.getCursor() + return cx + scrollX, cy + scrollY +end + +local function line() + local cbx, cby = getCursor() + return buffer[cby] +end + +local function getNormalizedCursor() + local cbx, cby = getCursor() + local wide, right = isWideAtPosition(buffer[cby], cbx) + if wide and right then + cbx = cbx - 1 + end + return cbx, cby +end + +local function setCursor(nbx, nby) + local x, y, w, h = getArea() + nby = math.max(1, math.min(#buffer, nby)) + + local ncy = nby - scrollY + if ncy > h then + term.setCursorBlink(false) + local sy = nby - h + local dy = math.abs(scrollY - sy) + scrollY = sy + if h > dy then + gpu.copy(x, y + dy, w, h - dy, 0, -dy) + end + for lineNr = nby - (math.min(dy, h) - 1), nby do + drawLine(x, y, w, h, lineNr) + end + elseif ncy < 1 then + term.setCursorBlink(false) + local sy = nby - 1 + local dy = math.abs(scrollY - sy) + scrollY = sy + if h > dy then + gpu.copy(x, y, w, h - dy, 0, dy) + end + for lineNr = nby, nby + (math.min(dy, h) - 1) do + drawLine(x, y, w, h, lineNr) + end + end + term.setCursor(term.getCursor(), nby - scrollY) + + nbx = math.max(1, math.min(unicode.wlen(line()) + 1, nbx)) + local wide, right = isWideAtPosition(line(), nbx) + local ncx = nbx - scrollX + if ncx > w or (ncx + 1 > w and wide and not right) then + term.setCursorBlink(false) + scrollX = nbx - w + ((wide and not right) and 1 or 0) + for lineNr = 1 + scrollY, math.min(h + scrollY, #buffer) do + drawLine(x, y, w, h, lineNr) + end + elseif ncx < 1 or (ncx - 1 < 1 and wide and right) then + term.setCursorBlink(false) + scrollX = nbx - 1 - ((wide and right) and 1 or 0) + for lineNr = 1 + scrollY, math.min(h + scrollY, #buffer) do + drawLine(x, y, w, h, lineNr) + end + end + term.setCursor(nbx - scrollX, nby - scrollY) + --update with term lib + nbx, nby = getCursor() + gpu.set(x + w - 10, y + h, text.padLeft(string.format("%d,%d", nby, nbx), 10)) +end + +local function highlight(bx, by, length, enabled) + local x, y, w, h = getArea() + local cx, cy = bx - scrollX, by - scrollY + cx = math.max(1, math.min(w, cx)) + cy = math.max(1, math.min(h, cy)) + length = math.max(1, math.min(w - cx, length)) + + local fg, fgp = gpu.getForeground() + local bg, bgp = gpu.getBackground() + if enabled then + gpu.setForeground(bg, bgp) + gpu.setBackground(fg, fgp) + end + local indexFrom = lengthToChars(buffer[by], bx) + local value = unicode.sub(buffer[by], indexFrom) + if unicode.wlen(value) > length then + value = unicode.wtrunc(value, length + 1) + end + gpu.set(x - 1 + cx, y - 1 + cy, value) + if enabled then + gpu.setForeground(fg, fgp) + gpu.setBackground(bg, bgp) + end +end + +local function home() + local cbx, cby = getCursor() + setCursor(1, cby) +end + +local function ende() + local cbx, cby = getCursor() + setCursor(unicode.wlen(line()) + 1, cby) +end + +local function left() + local cbx, cby = getNormalizedCursor() + if cbx > 1 then + local wideTarget, rightTarget = isWideAtPosition(line(), cbx - 1) + if wideTarget and rightTarget then + setCursor(cbx - 2, cby) + else + setCursor(cbx - 1, cby) + end + return true -- for backspace + elseif cby > 1 then + setCursor(cbx, cby - 1) + ende() + return true -- again, for backspace + end +end + +local function right(n) + n = n or 1 + local cbx, cby = getNormalizedCursor() + local be = unicode.wlen(line()) + 1 + local wide, right = isWideAtPosition(line(), cbx + n) + if wide and right then + n = n + 1 + end + if cbx + n <= be then + setCursor(cbx + n, cby) + elseif cby < #buffer then + setCursor(1, cby + 1) + end +end + +local function up(n) + n = n or 1 + local cbx, cby = getCursor() + if cby > 1 then + setCursor(cbx, cby - n) + end +end + +local function down(n) + n = n or 1 + local cbx, cby = getCursor() + if cby < #buffer then + setCursor(cbx, cby + n) + end +end + +local function delete(fullRow) + local cx, cy = term.getCursor() + local cbx, cby = getCursor() + local x, y, w, h = getArea() + local function deleteRow(row) + local content = table.remove(buffer, row) + local rcy = cy + (row - cby) + if rcy <= h then + gpu.copy(x, y + rcy, w, h - rcy, 0, -1) + drawLine(x, y, w, h, row + (h - rcy)) + end + return content + end + if fullRow then + term.setCursorBlink(false) + if #buffer > 1 then + deleteRow(cby) + else + buffer[cby] = "" + gpu.fill(x, y - 1 + cy, w, 1, " ") + end + setCursor(1, cby) + elseif cbx <= unicode.wlen(line()) then + term.setCursorBlink(false) + local index = lengthToChars(line(), cbx) + buffer[cby] = unicode.sub(line(), 1, index - 1) .. + unicode.sub(line(), index + 1) + drawLine(x, y, w, h, cby) + elseif cby < #buffer then + term.setCursorBlink(false) + local append = deleteRow(cby + 1) + buffer[cby] = buffer[cby] .. append + drawLine(x, y, w, h, cby) + else + return + end + setStatus(helpStatusText()) +end + +local function insert(value) + if not value or unicode.len(value) < 1 then + return + end + term.setCursorBlink(false) + local cx, cy = term.getCursor() + local cbx, cby = getCursor() + local x, y, w, h = getArea() + local index = lengthToChars(line(), cbx) + buffer[cby] = unicode.sub(line(), 1, index - 1) .. + value .. + unicode.sub(line(), index) + drawLine(x, y, w, h, cby) + right(unicode.wlen(value)) + setStatus(helpStatusText()) +end + +local function enter() + term.setCursorBlink(false) + local cx, cy = term.getCursor() + local cbx, cby = getCursor() + local x, y, w, h = getArea() + local index = lengthToChars(line(), cbx) + table.insert(buffer, cby + 1, unicode.sub(buffer[cby], index)) + buffer[cby] = unicode.sub(buffer[cby], 1, index - 1) + drawLine(x, y, w, h, cby) + if cy < h then + if cy < h - 1 then + gpu.copy(x, y + cy, w, h - (cy + 1), 0, 1) + end + drawLine(x, y, w, h, cby + 1) + end + setCursor(1, cby + 1) + setStatus(helpStatusText()) +end + +local findText = "" + +local function find() + local x, y, w, h = getArea() + local cx, cy = term.getCursor() + local cbx, cby = getCursor() + local ibx, iby = cbx, cby + while running do + if unicode.len(findText) > 0 then + local sx, sy + for syo = 1, #buffer do -- iterate lines with wraparound + sy = (iby + syo - 1 + #buffer - 1) % #buffer + 1 + sx = string.find(buffer[sy], findText, syo == 1 and ibx or 1, true) + if sx and (sx >= ibx or syo > 1) then + break + end + end + if not sx then -- special case for single matches + sy = iby + sx = string.find(buffer[sy], findText, nil, true) + end + if sx then + sx = unicode.wlen(string.sub(buffer[sy], 1, sx - 1)) + 1 + cbx, cby = sx, sy + setCursor(cbx, cby) + highlight(cbx, cby, unicode.wlen(findText), true) + end + end + term.setCursor(7 + unicode.wlen(findText), h + 1) + setStatus("Find: " .. findText) + + local _, address, char, code = term.pull("key_down") + if address == term.keyboard() then + local handler, name = getKeyBindHandler(code) + highlight(cbx, cby, unicode.wlen(findText), false) + if name == "newline" then + break + elseif name == "close" then + handler() + elseif name == "backspace" then + findText = unicode.sub(findText, 1, -2) + elseif name == "find" or name == "findnext" then + ibx = cbx + 1 + iby = cby + elseif not keyboard.isControl(char) then + findText = findText .. unicode.char(char) + end + end + end + setCursor(cbx, cby) + setStatus(helpStatusText()) +end + +------------------------------------------------------------------------------- + +local keyBindHandlers = { + left = left, + right = right, + up = up, + down = down, + home = home, + eol = ende, + pageUp = function() + local x, y, w, h = getArea() + up(h - 1) + end, + pageDown = function() + local x, y, w, h = getArea() + down(h - 1) + end, + + backspace = function() + if not readonly and left() then + delete() + end + end, + delete = function() + if not readonly then + delete() + end + end, + deleteLine = function() + if not readonly then + delete(true) + end + end, + newline = function() + if not readonly then + enter() + end + end, + + save = function() + if readonly then return end + local new = not fs.exists(filename) + local backup + if not new then + backup = filename .. "~" + for i = 1, math.huge do + if not fs.exists(backup) then + break + end + backup = filename .. "~" .. i + end + fs.copy(filename, backup) + end + local f, reason = io.open(filename, "w") + if f then + local chars, firstLine = 0, true + for _, line in ipairs(buffer) do + if not firstLine then + line = "\n" .. line + end + firstLine = false + f:write(line) + chars = chars + unicode.len(line) + end + f:close() + local format + if new then + format = [["%s" [New] %dL,%dC written]] + else + format = [["%s" %dL,%dC written]] + end + setStatus(string.format(format, fs.name(filename), #buffer, chars)) + else + setStatus(reason) + end + if not new then + fs.remove(backup) + end + end, + close = function() + -- TODO ask to save if changed + running = false + end, + find = function() + findText = "" + find() + end, + findnext = find +} + +getKeyBindHandler = function(code) + if type(config.keybinds) ~= "table" then return end + -- Look for matches, prefer more 'precise' keybinds, e.g. prefer + -- ctrl+del over del. + local result, resultName, resultWeight = nil, nil, 0 + for command, keybinds in pairs(config.keybinds) do + if type(keybinds) == "table" and keyBindHandlers[command] then + for _, keybind in ipairs(keybinds) do + if type(keybind) == "table" then + local alt, control, shift, key + for _, value in ipairs(keybind) do + if value == "alt" then alt = true + elseif value == "control" then control = true + elseif value == "shift" then shift = true + else key = value end + end + local keyboardAddress = term.keyboard() + if (not alt or keyboard.isAltDown(keyboardAddress)) and + (not control or keyboard.isControlDown(keyboardAddress)) and + (not shift or keyboard.isShiftDown(keyboardAddress)) and + code == keyboard.keys[key] and + #keybind > resultWeight + then + resultWeight = #keybind + resultName = command + result = keyBindHandlers[command] + end + end + end + end + end + return result, resultName +end + +------------------------------------------------------------------------------- + +local function onKeyDown(char, code) + local handler = getKeyBindHandler(code) + if handler then + handler() + elseif readonly and code == keyboard.keys.q then + running = false + elseif not readonly then + if not keyboard.isControl(char) then + insert(unicode.char(char)) + elseif unicode.char(char) == "\t" then + insert(" ") + end + end +end + +local function onClipboard(value) + value = value:gsub("\r\n", "\n") + local cbx, cby = getCursor() + local start = 1 + local l = value:find("\n", 1, true) + if l then + repeat + local line = string.sub(value, start, l - 1) + line = text.detab(line, 2) + insert(line) + enter() + start = l + 1 + l = value:find("\n", start, true) + until not l + end + insert(string.sub(value, start)) +end + +local function onClick(x, y) + setCursor(x + scrollX, y + scrollY) +end + +local function onScroll(direction) + local cbx, cby = getCursor() + setCursor(cbx, cby - direction * 12) +end + +------------------------------------------------------------------------------- + +do + local f = io.open(filename) + if f then + local x, y, w, h = getArea() + local chars = 0 + for line in f:lines() do + if line:sub(-1) == "\r" then + line = line:sub(1, -2) + end + table.insert(buffer, line) + chars = chars + unicode.len(line) + if #buffer <= h then + drawLine(x, y, w, h, #buffer) + end + end + f:close() + if #buffer == 0 then + table.insert(buffer, "") + end + local format + if readonly then + format = [["%s" [readonly] %dL,%dC]] + else + format = [["%s" %dL,%dC]] + end + setStatus(string.format(format, fs.name(filename), #buffer, chars)) + else + table.insert(buffer, "") + setStatus(string.format([["%s" [New File] ]], fs.name(filename))) + end + setCursor(1, 1) +end + +while running do + local event, address, arg1, arg2, arg3 = term.pull() + if address == term.keyboard() or address == term.screen() then + local blink = true + if event == "key_down" then + onKeyDown(arg1, arg2) + elseif event == "clipboard" and not readonly then + onClipboard(arg1) + elseif event == "touch" or event == "drag" then + local x, y, w, h = getArea() + arg1 = arg1 - x + 1 + arg2 = arg2 - y + 1 + if arg1 >= 1 and arg2 >= 1 and arg1 <= w and arg2 <= h then + onClick(arg1, arg2) + end + elseif event == "scroll" then + onScroll(arg3) + else + blink = false + end + if blink then + term.setCursorBlink(true) + end + end +end + +term.clear() +term.setCursorBlink(false) diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/find.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/find.lua new file mode 100755 index 00000000..a15bb14a --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/find.lua @@ -0,0 +1,132 @@ +local shell = require("shell") +local fs = require("filesystem") +local text = require("text") + +local USAGE = +[===[Usage: find [path] [--type=[dfs]] [--[i]name=EXPR] + --path if not specified, path is assumed to be current working directory + --type returns results of a given type, d:directory, f:file, and s:symlinks + --name specify the file name pattern. Use quote to include *. iname is + case insensitive + --help display this help and exit]===] + +local args, options = shell.parse(...) + +if (not args or not options) or options.help then + print(USAGE) + if not options.help then + return 1 + else + return -- nil return, meaning no error + end +end + +if #args > 1 then + io.stderr:write(USAGE..'\n') + return 1 +end + +local path = #args == 1 and args[1] or "." + +local bDirs = true +local bFiles = true +local bSyms = true + +local fileNamePattern = "" +local bCaseSensitive = true + +if options.iname and options.name then + io.stderr:write("find cannot define both iname and name\n") + return 1 +end + +if options.type then + bDirs = false + bFiles = false + bSyms = false + + if options.type == "f" then + bFiles = true + elseif options.type == "d" then + bDirs = true + elseif options.type == "s" then + bSyms = true + else + io.stderr:write(string.format("find: Unknown argument to type: %s\n", options.type)) + io.stderr:write(USAGE..'\n') + return 1 + end +end + +if options.iname or options.name then + bCaseSensitive = options.iname ~= nil + fileNamePattern = options.iname or options.name + + if type(fileNamePattern) ~= "string" then + io.stderr:write('find: missing argument to `name\'\n') + return 1 + end + + if not bCaseSensitive then + fileNamePattern = fileNamePattern:lower() + end + + -- prefix any * with . for gnu find glob matching + fileNamePattern = text.escapeMagic(fileNamePattern) + fileNamePattern = fileNamePattern:gsub("%%%*", ".*") +end + +local function isValidType(spath) + if not fs.exists(spath) then + return false + end + + if fileNamePattern:len() > 0 then + local fileName = spath:gsub('.*/','') + + if fileName:len() == 0 then + return false + end + + local caseFileName = fileName + + if not bCaseSensitive then + caseFileName = caseFileName:lower() + end + + local s, e = caseFileName:find(fileNamePattern) + if not s or not e then + return false + end + + if s ~= 1 or e ~= caseFileName:len() then + return false + end + end + + if fs.isDirectory(spath) then + return bDirs + elseif fs.isLink(spath) then + return bSyms + else + return bFiles + end +end + +local function visit(rpath) + local spath = shell.resolve(rpath) + + if isValidType(spath) then + local result = rpath:gsub('/+$','') + print(result) + end + + if fs.isDirectory(spath) then + local list_result = fs.list(spath) + for list_item in list_result do + visit(rpath:gsub('/+$', '') .. '/' .. list_item) + end + end +end + +visit(path) diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/flash.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/flash.lua new file mode 100755 index 00000000..5fdcfe88 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/flash.lua @@ -0,0 +1,88 @@ +local component = require("component") +local shell = require("shell") +local fs = require("filesystem") + +local args, options = shell.parse(...) + +if #args < 1 and not options.l then + io.write("Usage: flash [-qlr] [] [label]\n") + io.write(" q: quiet mode, don't ask questions.\n") + io.write(" l: print current contents of installed EEPROM.\n") + io.write(" r: save the current contents of installed EEPROM to file.\n") + return +end + +local function printRom() + local eeprom = component.eeprom + io.write(eeprom.get()) +end + +local function readRom() + local eeprom = component.eeprom + fileName = shell.resolve(args[1]) + if not options.q then + if fs.exists(fileName) then + io.write("Are you sure you want to overwrite " .. fileName .. "?\n") + io.write("Type `y` to confirm.\n") + repeat + local response = io.read() + until response and response:lower():sub(1, 1) == "y" + end + io.write("Reading EEPROM " .. eeprom.address .. ".\n" ) + end + local bios = eeprom.get() + local file = assert(io.open(fileName, "wb")) + file:write(bios) + file:close() + if not options.q then + io.write("All done!\nThe label is '" .. eeprom.getLabel() .. "'.\n") + end +end + +local function writeRom() + local file = assert(io.open(args[1], "rb")) + local bios = file:read("*a") + file:close() + + if not options.q then + io.write("Insert the EEPROM you would like to flash.\n") + io.write("When ready to write, type `y` to confirm.\n") + repeat + local response = io.read() + until response and response:lower():sub(1, 1) == "y" + io.write("Beginning to flash EEPROM.\n") + end + + local eeprom = component.eeprom + + if not options.q then + io.write("Flashing EEPROM " .. eeprom.address .. ".\n") + io.write("Please do NOT power down or restart your computer during this operation!\n") + end + + eeprom.set(bios) + + local label = args[2] + if not options.q and not label then + io.write("Enter new label for this EEPROM. Leave input blank to leave the label unchanged.\n") + label = io.read() + end + if label and #label > 0 then + eeprom.setLabel(label) + if not options.q then + io.write("Set label to '" .. eeprom.getLabel() .. "'.\n") + end + end + + if not options.q then + io.write("All done! You can remove the EEPROM and re-insert the previous one now.\n") + end +end + +if options.l then + printRom() +elseif options.r then + readRom() +else + writeRom() +end diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/grep.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/grep.lua new file mode 100755 index 00000000..3c66033c --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/grep.lua @@ -0,0 +1,315 @@ +--[[ +An adaptation of Wobbo's grep +https://raw.githubusercontent.com/OpenPrograms/Wobbo-Programs/master/grep/grep.lua +]]-- + +-- POSIX grep for OpenComputers +-- one difference is that this version uses Lua regex, not POSIX regex. + +local fs = require("filesystem") +local shell = require("shell") +local term = require("term") + +-- Process the command line arguments + +local args, options = shell.parse(...) + +local gpu = term.gpu() + +local function printUsage(ostream, msg) + local s = ostream or io.stdout + if msg then + s:write(msg,'\n') + end + s:write([[Usage: grep [OPTION]... PATTERN [FILE]... +Example: grep -i "hello world" menu.lua main.lua +for more information, run: man grep +]]) +end + +local PATTERNS = {args[1]} +local FILES = {select(2, table.unpack(args))} + +local LABEL_COLOR = 0xb000b0 +local LINE_NUM_COLOR = 0x00FF00 +local MATCH_COLOR = 0xFF0000 +local COLON_COLOR = 0x00FFFF + +local function pop(...) + local result + for _,key in ipairs({...}) do + result = options[key] or result + options[key] = nil + end + return result +end + +-- Specify the variables for the options +local plain = pop('F','fixed-strings') + plain = not pop('e','--lua-regexp') and plain +local pattern_file = pop('file') +local match_whole_word = pop('w','word-regexp') +local match_whole_line = pop('x','line-regexp') +local ignore_case = pop('i','ignore-case') +local stdin_label = pop('label') or '(standard input)' +local stderr = pop('s','no-messages') and {write=function()end} or io.stderr +local invert_match = not not pop('v','invert-match') + +-- no version output, just help +if pop('V','version','help') then + printUsage() + return 0 +end + +local max_matches = tonumber(pop('max-count')) or math.huge +local print_line_num = pop('n','line-number') +local search_recursively = pop('r','recursive') + +-- Table with patterns to check for +if pattern_file then + local pattern_file_path = shell.resolve(pattern_file) + if not fs.exists(pattern_file_path) then + stderr:write('grep: ',pattern_file,': file not found') + return 2 + end + table.insert(FILES, 1, PATTERNS[1]) + PATTERNS = {} + for line in io.lines(pattern_file_path) do + PATTERNS[#PATTERNS+1] = line + end +end + +if #PATTERNS == 0 then + printUsage(stderr) + return 2 +end + +if #FILES == 0 then + FILES = search_recursively and {'.'} or {'-'} +end + +if not options.h and search_recursively then + options.H = true +end + +if #FILES < 2 then + options.h = true +end + +local f_only = pop('l','files-with-matches') +local no_only = pop('L','files-without-match') and not f_only + +local include_filename = pop('H','with-filename') + include_filename = not pop('h','no-filename') or include_filename + +local m_only = pop('o','only-matching') +local quiet = pop('q','quiet','silent') + +local print_count = pop('c','count') +local colorize = pop('color','colour') and io.output().tty and term.isAvailable() + +local noop = function(...)return ...;end +local setc = colorize and gpu.setForeground or noop +local getc = colorize and gpu.getForeground or noop + +local trim = pop('t','trim') +local trim_front = trim and function(s)return s:gsub('^%s+','')end or noop +local trim_back = trim and function(s)return s:gsub('%s+$','')end or noop + +if next(options) then + if not quiet then + printUsage(stderr, 'unexpected option: '..next(options)) + return 2 + end + return 0 +end +-- Resolve the location of a file, without searching the path +local function resolve(file) + if file:sub(1,1) == '/' then + return fs.canonical(file) + else + if file:sub(1,2) == './' then + file = file:sub(3, -1) + end + return fs.canonical(fs.concat(shell.getWorkingDirectory(), file)) + end +end + +--- Builds a case insensitive patterns, code from stackoverflow +--- (questions/11401890/case-insensitive-lua-pattern-matching) +if ignore_case then + for i=1,#PATTERNS do + -- find an optional '%' (group 1) followed by any character (group 2) + PATTERNS[i] = PATTERNS[i]:gsub("(%%?)(.)", function(percent, letter) + if percent ~= "" or not letter:match("%a") then + -- if the '%' matched, or `letter` is not a letter, return "as is" + return percent .. letter + else -- case-insensitive + return string.format("[%s%s]", letter:lower(), letter:upper()) + end + end) + end +end + +local function getAllFiles(dir, file_list) + for node in fs.list(shell.resolve(dir)) do + local rel_path = dir:gsub("/+$","") .. '/' .. node + local resolved_path = shell.resolve(rel_path) + if fs.isDirectory(resolved_path) then + getAllFiles(rel_path, file_list) + else + file_list[#file_list+1] = rel_path + end + end +end + +if search_recursively then + local files = {} + for i,arg in ipairs(FILES) do + if fs.isDirectory(arg) then + getAllFiles(arg, files) + else + files[#files+1]=arg + end + end + FILES=files +end + +-- Prepare an iterator for reading files +local function readLines() + local curHand = nil + local curFile = nil + local meta = nil + return function() + if not curFile then + local file = table.remove(FILES, 1) + if not file then + return + end + meta = {line_num=0,hits=0} + if file == "-" then + curFile = file + meta.label = stdin_label + curHand = io.input() + else + meta.label = file + local file, reason = resolve(file) + if fs.exists(file) then + curHand, reason = io.open(file, 'r') + if not curHand then + local msg = string.format("failed to read from %s: %s", meta.label, reason) + stderr:write("grep: ",msg,"\n") + return false, 2 + else + curFile = meta.label + end + else + stderr:write("grep: ",file,": file not found\n") + return false, 2 + end + end + end + meta.line = nil + if not meta.close and curHand then + meta.line_num = meta.line_num + 1 + meta.line = curHand:read("*l") + end + if not meta.line then + curFile = nil + if curHand then + curHand:close() + end + return false, meta + else + return meta, curFile + end + end +end + +local function write(part, color) + local prev_color = color and getc() + if color then setc(color) end + io.write(part) + if color then setc(prev_color) end +end +local flush=(f_only or no_only or print_count) and function(m) + if no_only and m.hits == 0 or f_only and m.hits ~= 0 then + write(m.label, LABEL_COLOR) + write('\n') + elseif print_count then + if include_filename then + write(m.label, LABEL_COLOR) + write(':', COLON_COLOR) + end + write(m.hits) + write('\n') + end +end +local ec = nil +local any_hit_ec = 1 +local function test(m,p) + local empty_line = true + local last_index, slen = 1, #m.line + local needs_filename, needs_line_num = include_filename, print_line_num + local hit_value = 1 + while last_index <= slen and not m.close do + local i, j = m.line:find(p, last_index, plain) + local word_fail, line_fail = + match_whole_word and not (i and not (m.line:sub(i-1,i-1)..m.line:sub(j+1,j+1)):find("[%a_]")), + match_whole_line and not (i==1 and j==slen) + local matched = not ((m_only or last_index==1) and not i) + if (hit_value == 1 and word_fail) or line_fail then + matched,i,j = false + end + if invert_match == matched then break end + if max_matches == 0 then os.exit(1) end + any_hit_ec = 0 + m.hits, hit_value = m.hits + hit_value, 0 + if f_only or no_only then + m.close = true + end + if flush or quiet then return end + if needs_filename then + write(m.label, LABEL_COLOR) + write(':', COLON_COLOR) + needs_filename = nil + end + if needs_line_num then + write(m.line_num, LINE_NUM_COLOR) + write(':', COLON_COLOR) + needs_line_num = nil + end + local s=m_only and '' or m.line:sub(last_index,(i or 0)-1) + local g=i and m.line:sub(i,j) or '' + if i==1 then g=trim_front(g) elseif last_index==1 then s=trim_front(s) end + if j==slen then g=trim_back(g) elseif not i then s=trim_back(s) end + write(s) + write(g, MATCH_COLOR) + empty_line = false + last_index = (j or slen)+1 + if m_only or last_index>slen then + write("\n") + empty_line = true + needs_filename, needs_line_num = include_filename, print_line_num + elseif p:find("^^") and not plain then p="^$" end + end + if not empty_line then write("\n") end + if max_matches ~= math.huge and max_matches >= m.hits then + m.close = true + end +end +for meta,status in readLines() do + if not meta then + if type(status) == 'table' then if flush then + flush(status) end -- this was the last object, closing out + elseif status then + ec = status or ec + end + else + for _,p in ipairs(PATTERNS) do + test(meta,p) + end + end +end + +return ec or any_hit_ec diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/head.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/head.lua new file mode 100755 index 00000000..99dfa216 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/head.lua @@ -0,0 +1,137 @@ +local shell = require("shell") +local fs = require("filesystem") + +local args, options = shell.parse(...) +local error_code = 0 + +local function pop(key, convert) + local result = options[key] + options[key] = nil + if result and convert then + local c = tonumber(result) + if not c then + io.stderr:write(string.format("use --%s=n where n is a number\n", key)) + options.help = true + error_code = 1 + end + result = c + end + return result +end + +local bytes = pop('bytes', true) +local lines = pop('lines', true) +local quiet = {pop('q'), pop('quiet'), pop('silent')} +quiet = quiet[1] or quiet[2] or quiet[3] +local verbose = {pop('v'), pop('verbose')} +verbose = verbose[1] or verbose[2] +local help = pop('help') +local invalid_key = next(options) + +if bytes and lines then + invalid_key = 'bytes and lines both specified' +end + +if help or next(options) then + local invalid_key = next(options) + if invalid_key then + invalid_key = string.format('invalid option: %s\n', invalid_key) + error_code = 1 + else + invalid_key = '' + end + print(invalid_key .. [[Usage: head [--lines=n] file +Print the first 10 lines of each FILE to stdout. +For more info run: man head]]) + os.exit(error_code) +end + +if #args == 0 then + args = {'-'} +end + +if quiet and verbose then + quiet = false +end + +local function new_stream() + return + { + open=true, + capacity=math.abs(lines or bytes or 10), + bytes=bytes, + buffer=(lines and lines < 0 and {}) or (bytes and bytes < 0 and '') + } +end + +local function close(stream) + if stream.buffer then + if type(stream.buffer) == 'table' then + stream.buffer = table.concat(stream.buffer) + end + io.stdout:write(stream.buffer) + stream.buffer = nil + end + stream.open = false +end + +local function push(stream, line) + if not line then + return close(stream) + end + + local cost = stream.bytes and line:len() or 1 + stream.capacity = stream.capacity - cost + + if not stream.buffer then + if stream.bytes and stream.capacity < 0 then + line = line:sub(1,stream.capacity-1) + end + io.write(line) + if stream.capacity <= 0 then + return close(stream) + end + else + if type(stream.buffer) == 'table' then -- line storage + stream.buffer[#stream.buffer+1] = line + if stream.capacity < 0 then + table.remove(stream.buffer, 1) + stream.capacity = 0 -- zero out + end + else -- byte storage + stream.buffer = stream.buffer .. line + if stream.capacity < 0 then + stream.buffer = stream.buffer:sub(-stream.capacity+1) + stream.capacity = 0 -- zero out + end + end + end + +end + +for i=1,#args do + local arg = args[i] + local file + if arg == '-' then + arg = 'standard input' + file = io.stdin + else + file, reason = io.open(arg, 'r') + if not file then + io.stderr:write(string.format([[head: cannot open '%s' for reading: %s]], arg, reason)) + end + end + if file then + if verbose or #args > 1 then + io.write(string.format('==> %s <==\n', arg)) + end + + local stream = new_stream() + + while stream.open do + push(stream, file:read('*L')) + end + + file:close() + end +end diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/hostname.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/hostname.lua new file mode 100755 index 00000000..4e88379a --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/hostname.lua @@ -0,0 +1,22 @@ +local args = {...} +if args[1] then + local file, reason = io.open("/etc/hostname", "w") + if not file then + io.stderr:write(reason .. "\n") + return 1 + else + file:write(args[1]) + file:close() + os.setenv("HOSTNAME", args[1]) + os.setenv("PS1", "$HOSTNAME:$PWD# ") + end +else + local file = io.open("/etc/hostname") + if file then + io.write(file:read("*l"), "\n") + file:close() + else + io.stderr:write("Hostname not set\n") + return 1 + end +end diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/install.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/install.lua new file mode 100755 index 00000000..1b9176d5 --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/install.lua @@ -0,0 +1,51 @@ +local computer = require("computer") +local shell = require("shell") + +local options + +do + local basic, reason = loadfile(package.searchpath("tools/install_basics", package.path), "bt", _G) + if not basic then + io.stderr:write("failed to load install: " .. tostring(reason) .. "\n") + return 1 + end + options = basic(...) +end + +if not options then return end +local write = io.write + +if computer.freeMemory() < 50000 then + write("Low memory, collecting garbage\n") + for i=1,20 do os.sleep(0) end +end + +local cp, reason = loadfile(shell.resolve("cp", "lua"), "bt", _G) + +local ec = cp(table.unpack(options.cp_args)) +if ec ~= nil and ec ~= 0 then + return ec +end + +write("Installation complete!\n") + +if options.setlabel then + pcall(options.target.dev.setLabel, options.label) +end + +if options.setboot then + local address = options.target.dev.address + if computer.setBootAddress(address) then + write("Boot address set to " .. address) + end +end + +if options.reboot then + write("Reboot now? [Y/n] ") + if ((io.read() or "n").."y"):match("^%s*[Yy]") then + write("\nRebooting now!\n") + computer.shutdown(true) + end +end + +write("Returning to shell.\n") diff --git a/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/label.lua b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/label.lua new file mode 100755 index 00000000..25cf958f --- /dev/null +++ b/640cd89f-8e29-4b66-a0eb-7680c33760b4/bin/label.lua @@ -0,0 +1,49 @@ +local shell = require("shell") +local devfs = require("devfs") +local comp = require("component") + +local args, options = shell.parse(...) +if #args < 1 then + io.write("Usage: label [-a] [