ECS
Гуру-
Публикации
533 -
Зарегистрирован
-
Посещение
-
Победитель дней
203
Тип публикации
Блоги
Профили
Форум
Багтрекер
Магазин
Все публикации пользователя ECS
-
Нет, что ты. Это банально более функциональный враппер к интернет-компоненту для упрощенной работы с HTTP-хендлом
-
До поры до времени я преспокойно себе использовал OpenOS'овскую библиотеку для запросов и горя не знал. Однако вскоре все больше и больше убеждался в необходимости написания более функционального аналога, устав чистить вилочкой множество однотипных "велосипедов". Основные преимущества библиотеки: Рекурсивная сериализация Lua-таблиц в формат URL-кодированной строки Обработка серверных ошибок по принципу "success, reason" без необходимости использовать pcall в каждой программе Возможность прямой загрузки файлов с сервера в указанную директорию Возможность исполнения файла по URL как Lua-программы Поддержка ручной почанковой обработки загружаемых данных Команда для загрузки: wget https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/web.lua /lib/web.lua -f web.serialize( string/table data ): string serializedData Преобразует входной аргумент в сериализованную строку, соответствующую спецификации HTTP-запросов. Помимо строк и чисел поддерживаются также таблицы с множеством вложенных таблиц: print( web.serialize({ string = "Hello world", number = 123, array = { arrayString = "Meow", arrayInArray = { arrayInArrayNumber = 456 } } }) ) Результат: web.encode( string data ): string encodedData Экранирует специальные символы, делая строку подходящей для осуществления запросов с множеством специфических данных: print( "http://buttex.ru/test.php?message=" .. web.encode( "Привет, как дела?" ) ) Результат: web.request( string url, [string/table postData, table headers] ): string result, string reason Всем знакомый запрос к указанной URL, возвращающий строковый ответ с сервера. При указании аргумента postData сервер получит соответствующие данные в POST-массив, а при указании headers он получит кастомные заголовки. Для примера я создал PHP-скрипт на домашнем сайте, возвращающий GET/POST-данные запроса, так мы сможем легко отслеживать успешность передачи содержимого: <?php echo("\nСодержимое 'GET':\n"); print_r($_GET); echo("\nСодержимое 'POST':\n"); print_r($_POST); ?> Если требуется осуществить обращение к серверу, принимающему исключительно GET-запросы, используем сериализацию данных для удобства и присоединим результат к исходной URL: local result = web.request( "http://buttex.ru/test.php?" .. web.serialize({ string = "Hello", number = 123 }) ) print(result) В результате сервер вернул переданные данные GET-запроса: Осуществим POST-запрос к скрипту, указав таблицу в качестве аргумента postData: local result = web.request( "http://buttex.ru/test.php", { string = "Hello", number = 123 } ) print(result) Теперь сервер вернул переданные данные POST-запроса: web.download( string url, string path ): boolean result, string reason Метод для загрузки файла по URL в указанную директорию. Возвращает true в случае успеха и false, reason в случае неудачи. К примеру, следующий код загрузит в корень диска программу "матрица": web.download("https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Screensavers/Matrix.lua", "/matrix.lua") web.run( string url, ... ): ... Крайне полезная фича для быстрого запуска файла в виде Lua-программы, в которую передаются все указанные через "..." аргументы. Возвращает данные скрипта в случае успеха и false, reason в случае неудачи. Для примера запустим все ту же "матрицу: print( web.run( "https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Screensavers/Matrix.lua" ) ) Результат: web.rawRequest( string url, string/table postData, table headers, function chunkHandler, [int chunkSize]): boolean result, string reason Напоследок метод, позволяющий осуществить ручную обработку загружаемых данных почанково. Для примера напишем программу, выдающую содержимое страницы vk.com через print() маленькими порциями по 20 символов. Разумеется, никаких postData и headers указывать не требуется: print( web.rawRequest( "https://vk.com/", nil, nil, function(chunk) print(chunk) end, 20 ) ) Результат:
-
Ой-ой-ой, какая вопиющая жестокость: теперь нормальным поцыкам-кодерам с района придется пояснять за базар бездушной софтине. Лично я бы реализовал подобную систему следующим образом: Для начала создал бы конфиг с запрещенными к употреблению словами в виде отдельного файла: -- *** - нецензурные слова { ["***"] = true, ["*******"] = true, ["*****"] = true, } Далее загружал бы конфиг по указанному пути, извлекал бы из сообщения игрока отдельные слова и анализировал их на вхождение в конфиг без учета регистра: local file = io.open("/chat.cfg", "r") local forbiddenWords = require("serialization").unserialize(file:read("*a")) file:close() for word in message:gmatch("[^%s%,%.%:%;%!%^]+") do if forbiddenWords[unicode.lower(word)] then -- Вещ или бан end end Использовать string.find(), конечно, удобно, однако слишком велика вероятность случайных банов, как описал мсье Fingercomp. Однако если по какой-то причине тебе все же требуется использовать стандартный поиск, то держи функцию, поддерживающую юникод: function string.unicodeFind(str, pattern, init, plain) if init then if init < 0 then init = -#unicode.sub(str,init) elseif init > 0 then init = #unicode.sub(str, 1, init - 1) + 1 end end a, b = string.find(str, pattern, init, plain) if a then local ap, bp = str:sub(1, a - 1), str:sub(a,b) a = unicode.len(ap) + 1 b = a + unicode.len(bp) - 1 return a, b else return a end end
-
@@Koteyk0o, угу, о заливочке и сам подумываю: добавлю, когда настроение будет. Странную смену расположения окна пофиксил, спасибо. А ластик имеется: зажимай ctrl/cmd и стирай на здоровье
-
Держи рфидку: https://github.com/IgorTimofeev/OpenComputers/raw/master/Icons/RFID.pic
-
@@Koteyk0o, самый скучный способ решения проблемы - это установить атрибут .hidden = true для тех контейнеров, отрисовка которых не требуется. Этот вариант хорош, если необходимо сохранять состояние объектов в каждом контейнере - к примеру, текст, введенный пользователем. Если же сохранение данных не критично, то можно пойти другим путем, создав единый контейнер для содержимого, и при переключении кнопок/вкладок/etc очищать его, заполняя нужным содержимым. Есть даже готовый пример для такой ситуации: local buffer = require("doubleBuffering") local GUI = require("GUI") -------------------------------------------------------------------------------------------- local mainContainer = GUI.fullScreenContainer() mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0xFF8888)) -- Создаем контейнер, симулирующий окно local window = mainContainer:addChild(GUI.container(3, 2, 80, 25)) -- Добавляем в окно панель вкладок local tabBar = window:addChild(GUI.tabBar(1, 1, window.width, 3, 2, 0, 0x2D2D2D, 0xF0F0F0, 0xF0F0F0, 0x2D2D2D)) -- Добавляем также фоновую панель local panel = window:addChild(GUI.panel(1, tabBar.height + 1, window.width, window.height - tabBar.height, 0xF0F0F0)) -- Добавляем лейаут, в котором будет находиться содержимое открытой вкладки local contentLayout = window:addChild(GUI.layout(panel.localX, panel.localY, panel.width, panel.height, 1, 1)) -- Функция очищает содержимое лейаута, вызывает аргумент как функцию и отрисовывает открывшуюся вкладку на экране local function onTabSwitched(method) contentLayout:deleteChildren() method() mainContainer:draw() buffer.draw() end -- При клике на каждую вкладку лейаут будет заполняться индивидуальным содержимым. В данном примере это генератор случайных чисел tabBar:addItem("Рандомайзер").onTouch = function() onTabSwitched(function() local label = contentLayout:addChild(GUI.label(1, 1, 36, 1, 0x2D2D2D, "")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) local button = contentLayout:addChild(GUI.button(1, 1, 32, 3, 0xBBBBBB, 0xFFFFFF, 0x999999, 0xFFFFFF, "Сгенерировать")) button.onTouch = function() label.text = "Рандомное число: " .. math.random(100) mainContainer:draw() buffer.draw() end button.onTouch() end) end -- При нажатии на вторую вкладку будет открываться панель для рисования tabBar:addItem("Рисовалка").onTouch = function() onTabSwitched(function() -- Тут мы создаем с нуля простенький виджет-холст, реагирующий на клики мыши, подробности см. в документации local canvas = contentLayout:addChild(GUI.object(1, 1, contentLayout.width - 4, contentLayout.height - 4)) local colorSelector = contentLayout:addChild(GUI.colorSelector(1, 1, 20, 1, 0x0, "Выберите цвет")) local pixels = {} for y = 1, canvas.height do pixels[y] = {} for x = 1, canvas.width do pixels[y][x] = false end end canvas.draw = function() buffer.square(canvas.x, canvas.y, canvas.width, canvas.height, 0xFFFFFF, 0x0, " ") for y = 1, #pixels do for x = 1, #pixels[y] do if pixels[y][x] then buffer.set(canvas.x + x - 1, canvas.y + y - 1, pixels[y][x], 0x0, " ") end end end end canvas.eventHandler = function(mainContainer, object, eventData) if eventData[1] == "touch" or eventData[1] == "drag" then local x, y = eventData[3] - object.x + 1, eventData[4] - object.y + 1 pixels[y][x] = eventData[5] == 1 and false or colorSelector.color mainContainer:draw() buffer.draw() end end end) end -- Остальные вкладки заполняем на свое усмотрение tabBar:addItem("Вкладка 3").onTouch = function() onTabSwitched(function() -- Заполнить контейнер каким-нибудь содержимым end) end tabBar:addItem("Вкладка 4").onTouch = function() onTabSwitched(function() -- Заполнить контейнер каким-нибудь содержимым end) end -------------------------------------------------------------------------------------------- -- Очищаем содержимое буфера buffer.flush() -- Открываем первую вкладку tabBar:getItem(1).onTouch() -- Начинаем обработку событий mainContainer:startEventHandling()В результате получится окошко с переключаемыми вкладками (надеюсь, не суть важно - кнопки или вкладки, один хрен, имхо): Касаемо остановки обработчика событий - лично я это делаю в одном случае: когда выключается комп. Во всех остальных ситуациях дело можно решить путем условного ветвления и использования callback-функций, благо либа под это заточена. То же самое могу сказать и об очистке буфера. Нет, разве что средствами сторонних либ или ПО. Безусловно, можно воспользоваться растеризатором шрифтов, можно создать пиксельную карту для большинства символов в виде Lua-таблицы, можно использовать шрифт Брайля для детального рендеринга, можно в конце концов создать виджет, отрисовывающий передаваемую строку нужным тебе способом. Но это уже частный случай, к либе, отношения не имеющий. Так что ответ "нет", увы.
-
Добавлена документация к библиотеке MineOSInterface с несколькими примерами кода, позволяющей пользователям создавать собственный оконный софт: Также обновлено приложение Camera для мода Computronix:
-
Понял, не вопрос, сейчас выкачу обновление. Добавил методы get/fill/clear, а также изменил set: если аргумент color не указывается, то цвет изменяться не будет. Таким образом можно без проблем "стирать" ранее установленные пиксели, установив их state на false, сохраняя при этом цвет остальных в группе. А, ну и благодарочка за теплые слова о доке, да <3
-
Параметр state отвечает за непосредственное отображение брайль-пикселя, т.е. будет ли вообще этот брайль-пиксель рисоваться на экране. А color - это цвет текущей группы из 2x4 брайль-пикселей (обычный цвет текста пикселя gpu) Обижаешь, имеются методы container:stopEventHandling() и container:returnData(...). По сути первый вызывает второй без аргументов.
-
Ну, для начала пройдемся по ошибкам: во-первых, как я понял, тебе требуется софтина, выдающая редстоун-сигнал в том случае, если игрок провел карточкой с паролем "govno", а также с возможностью закрытия по нажатию клавиши Enter. Если так, то вовсе необязательно вызывать event.pull() множество раз друг за другом в надежде на чудо, достаточно единожды ждать какого-либо события, а затем уже анализировать его данные. Лично мне удобнее всего заносить данные события в таблицу (массив), а затем уже выбирать из нее нужные значения: local eventData = { event.pull() } if eventData[1] == "touch" then ... elseif eventData[1] == "key_down" then ... end Во-вторых, в случае валидности пароля на карте, ты используешь следующее: rs.setOutput(1, 15) rs.setOutput(1, 0) os.sleep(2) Вполне логично, что редстоун-сигнал выдастся буквально на пару игровых тиков (чего недостаточно для открытия, скажем, двери), а затем немедленно потухнет, после чего компьютер будет "спать" 2 секунды. Кроме того, ты уже подключил в коде библиотеку sides, предоставляющую user-friendly таблицу с индексами сторон, поэтому логичнее будет реализовать эту запись следующим образом: rs.setOutput(sides.up, 15) os.sleep(2) rs.setOutput(sides.up, 0) И в-третьих, как сказали товарищи выше, твой код нечитабелен от слова "совсем". Неужели так сложно нажать клавишу табуляции (или пробела) пару-тройку раз и не создавать "магических переменных" перед публикацией на форум? Ну ладн, не буду выеживаться особо, держи рабочую версию софтины. Но вообще чет как-то мда( local component = require("component") local event = require("event") local sides = require("sides") local redstone = component.redstone local password = "govno" while true do local eventData = { event.pull() } if eventData[1] == "magData" then if eventData[4] == password then redstone.setOutput(sides.up, 15) os.sleep(2) end redstone.setOutput(sides.up, 0) elseif eventData[1] == "key_down" and eventData[4] == 28 then break end end
-
Сдается мне, дело не в версии кубача, а в версии аддона, т.к. сам играю на 1.7.10. Но фиксанул, спасибо
- 6 ответов
-
- OpenSecurity
- RFID
-
(и ещё 1 )
Теги:
-
Создай два файлика под именами read.lua и search.lua, записав в них следующий код: Для write.lua: local component = require("component") local password = select(1, ...) if password then local success, reason = (component.isAvailable("OSCardWriter") and component.OSCardWriter or component.os_cardwriter).write(password) if success then print("Данные записаны на карту") else print("Ошибка записи: " .. reason) end else print("Использование: write <пароль>") end Для search.lua: local event = require("event") local sides = require("sides") local component = require("component") local redstone = component.redstone local reader = component.isAvailable("OSRFIDReader") and component.OSRFIDReader or component.os_rfidreader local password = select(1, ...) local range = tonumber(select(2, ...) or "") if password and range then while true do local eventType, _, _, key_code = event.pull(0) if eventType == "key_down" and key_code == 28 then break else local player = reader.scan()[1] if player and player.data == password and player.range <= range then redstone.setOutput(sides.up, 15) else redstone.setOutput(sides.up, 0) end end end else print("Использование: search <пароль> <радиус поиска>") end Дальше - дело техники. Пихаешь RFID-карту в устройство записи, пишешь в консоли write <пароль> для записи соответствующего пароля на карточку. Для поиска игроков, имеющих при себе карточку с указанным паролем, пишешь search <пароль> <радиус поиска>. По умолчанию софтина выдаст редстоун-сигнал на верхнюю сторону блока Redstone I/O при приближении валидного игрока к указанному радиусу. Для выхода из программы поиска достаточно нажать на клавишу Enter. Собсна, пример расположения девайсов:
- 6 ответов
-
- 4
-
-
- OpenSecurity
- RFID
-
(и ещё 1 )
Теги:
-
Проведен рефакторинг библиотеки с целью увеличения скорости отрисовки: все методы и поля таблиц, хоть как-либо используемые самой библиотекой, заменены на единоразово созданные локальные переменные. Удалена избыточная группировка по функциям. Изменен принцип растеризации отрезков. Добавлен метод buffer.formattedText, позволяющий изменять цвет текста в реальном времени через вставку синтаксических конструкций вида #RRGGBB. Как результат - общая производительность выросла в ~3 раза по сравнению со старой версией библиотеки (первая пикча) и новой (вторая):
- 36 ответов
-
- 6
-
-
- Интерфейс
- Буферизация
- (и ещё 4 )
-
Небольшое обновление, касающееся поставляемых по дефолту приложений и UX в целом: • Добавлена поддержка автоматического стакинга окон одного и того же приложения в единую иконку Dock, автоматического смещения правее и ниже при открытии нового окна, а также комплексного закрытия всех окон: • Добавлена поддержка выбора расстояния между иконками рабочего стола и файловых менеджеров: • Добавлено приложение Control, написанное по модульной концепции, где каждая вкладка - это подключаемый скрипт-модуль с отдельным функционалом. К примеру, изначально оно имеет интерпретатор Lua с автодополнением, дисковую утилиту для форматирования/переименования/дублирования, менеджер RAM и анализатор событий: • Добавлено приложение Graph для растеризации графиков любых функций с поддержкой диапазона, шага и показа квант-точек: • Добавлено приложение Braille для удобного создания изображений, составленных из символов Брайля: • Переписано приложение HEX, предназначенное для побайтового редактирования файлов:
-
Начнем с того, что на твоем скриншоте возникла ошибка с запуском скрипта после загрузки с pastebin.com, и ни в коем случае не при запуске самой программы после окончания работы инсталлера: Во-вторых, скрипт 7PjKsdNa скидывал тебе не я, и с какой стати ты сообщаешь мне об ошибке в чужом софте - не ясно. Вообще, если быть предельно корректным, то это не ошибка, а банальная приватность пасты: Если совсем туго с самостоятельным анализом ситуации, то могу вообще прям по действиям расписать: Ввводишь в консоль команду pastebin run ryhyXUKZ Открываешь новый файл (скажем, через edit <имя_файла>) и средней кнопкой мыши вставляешь скинутый выше код с содержимым окна Если требуется отключение ctrl+c, то после строчек с requir'ами вставляешь все той же средней кнопкой мыши скинутый код для отключения ctrl+c Сохраняешь файл путем нажатия ctrl+s, выходишь из редактора через ctrl+w Запускаешь сохраненную программу Неужели это так сложно? Могу в таком случае скинуть полностью собранную софтину с отключением прерываний (тык), но тогда ты ничему не научишься и будешь бездумно доставать форумчан и далее.
-
Это твоя ошибка, ко мне отношения она не имеет. Проверил на чистом компе, все без проблем устанавливается: Юзай следующий код - и все будет в шоколаде: event.shouldInterrupt = function() return false end event.shouldSoftInterrupt = event.shouldInterrupt
-
Фига тут драма разыгралась, программка-то простая совсем. Держи мой вариант: для начала запускаешь инсталлер всех библиотек: pastebin run ryhyXUKZЗатем запускаешь следующий код: local buffer = require("doubleBuffering") local GUI = require("GUI") local event = require("event") -------------------------------------------------------------- local mainContainer = GUI.fullScreenContainer() mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x002440)) local layout = mainContainer:addChild(GUI.layout(1, 1, mainContainer.width, mainContainer.height, 1, 1)) local label = layout:addChild(GUI.label(1, 1, 40, 1, 0xE1E1E1, ""):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) local input = layout:addChild(GUI.input(1, 1, 40, 5, 0xE1E1E1, 0x444444, 0x888888, 0xE1E1E1, 0x262626, nil, "Напишите ваш отзыв здесь")) layout:addChild(GUI.button(1, 1, 40, 3, 0x336DBF, 0xE1E1E1, 0xE1E1E1, 0x336DBF, "Отправить отзыв")).onTouch = function(mainContainer, object, eventData) if input.text:len() > 0 then local file = io.open("/Otzivi.txt", "a") file:write("Отзыв от пользователя " .. eventData[6] .. ": " .. input.text .. "\n") file:close() input.text, label.text = "", "Ваш отзыв отправлен" mainContainer:draw() buffer.draw() event.timer(2, function() label.text = "" mainContainer:draw() buffer.draw() end, 1) end end layout:addChild(GUI.button(1, 1, 40, 3, 0x336DBF, 0xE1E1E1, 0xE1E1E1, 0x336DBF, "Выйти")).onTouch = function() mainContainer:stopEventHandling() buffer.clear(0x0) buffer.draw(true) end -------------------------------------------------------------- mainContainer:draw() buffer.draw(true) mainContainer:startEventHandling() Вуаля, результат: Все отзывы хранятся в файлике с соответствующим именем в корне диска. Читай любым удобным способом:
-
Довольно полезное в практическом смысле обновление: дописана поддержка аналога FTP-протокола для беспроводной связи компьютеров с MineOS. Все устройства в радиусе обмена сообщениями автоматически "видят" друг друга, предоставляя возможность выдачи прав доступа: Каждый удаленный компьютер воспринимается как монтированная файловая система, поэтому работать с ним можно абсолютно так же, как и с основным компьютером с небольшой задержкой во времени, вызванной отправкой команд по модему: Все передаваемые по сети данные приватны и неотслеживаемы за исключением стартового сообщения, необходимого для обнаружения компьютеров в сети. Разумеется, пользователь может задавать собственное сетевое имя, включать и отключать сетевой режим, а также выставлять желаемый радиус поиска компьютеров (скажем, для объединения в домашнюю сеть). Надеюсь, эта фишечка придется вам по вкусу.
-
Во-первых, я никогда не заявлял, что MineOS отличается от OpenOS по back-end составляющей: эквивалентность или наличие различий между ними не противоречат самостоятельности данной ОС, а также возможности называть ее полноценной ОС. Во-вторых, моя система никому и ничего не должна за исключением заявленного выше функционала. В-третьих, она более чем предоставляет эти "особые способы": gpu - двойная буферизация графики screen - библиотека подстройки разрешения экрана для избавления от "черных полос" filesystem - ускоренные методы получения имени/пути/расширения файлов, проверки их на скрытость, получения сортированных файловых списков и кеширования часто используемых данных, чтения и обработки файлов в бинарном режиме eeprom - возможность прошивки и чтения данных "на лету" прямо на рабочем столе internet - система error-reporting'а, интеграция с магазином приложений, библиотека для выполнения запросов с интеллектуальным отслеживанием ошибок HTTP modem - интерфейсная библиотека для осуществления беспроводных соединений методом .send, поддержка передачи файлов по "воздуху" на уровне десктопа Имеется также прикладное ПО, поставляющееся с системой и обеспечивающее интерфейсные способы взаимодействия с соответствующими компонентами: printer3d - программа для печати изображений в виде пиксельных картин и программа для создания и печати 3D-моделей hologram - программа отображения игрового времени в виде голографических часов и программа для ручного рисования данных непосредственно на голопроектор (спасибо, @Totoro) geolyzer - программа для сканирования местности и отслеживания диапазона плотностей руд. Имеется поддержка вывода данных на компоненты hologram и glasses из мода OpenGlasses stargate - программа для интерфейсного контроля звездных врат из мода SGCraft camera - программа для съемки местности посредством камеры из мода Computronix
-
Затем, что я очень люблю заниматься казуистикой, а также затем, что от дефолтной OpenOS тут осталось крайне мало - большинство библиотек переписаны с нуля и "отдеговнокожены" с целью повышения производительности. Аналогичность названий методов библиотек OpenOS и MineOS вовсе не означает тождественность их выполнения, это абсолютно разные скрипты с различной механикой, я реализовал схожие названия всего лишь для обеспечения обратной совместимости. Из стандартных остались нетронутыми лишь io/fs/term/package/process/buffer и аналогичные, ибо написаны они вполне неплохо. Я могу также без проблем переписать под свои нужды и их, сделав MineOS независимой от OpenOS, отвоевав тем самым фиктивное право называть ее самостоятельно ОСью. Но это звучит уж слишком наивно, не находишь?
-
Да не-е-е, ты чо, никаких обид. Это я так, взгрустнул от безысходности
-
Верно. Однако я заменил множество этих "первых и основных" скриптов на собственные. Правильно ли я понял, что необходимо заменить их все, чтобы ОСька получила статус ОСьки более "официально"?
-
Никто и не утверждал обратного, чтобы спорить. В чем заключается "неполноценность" такой многозадачности? Запущенные скрипты выполняются параллельно в порядке иерархии на десктопе, если какой-то скрипт обращается к "non-yieldable-функции", то, разумеется, абсолютно все оставшиеся скрипты будут ждать своей очереди, это особенность мода. Также вполне логично, что использовать системную многозадачность смогут лишь те программы, которые используют API системы, все остальные будут работать в штатном монопольном режиме. Как я писал выше, быстродействие ОС находится в приоритете, и лишь этот подход сумеет удовлетворить моим требованиям. Все остальные варианты многозадачности, реализованные путем подмены pullSignal и переписывания прокси компонентов, слишком медленны для и без того прожорливой ОСи. Пробовали, тестировали, знаем. Я воспринимаю термин "многозадачность" в соответствии с его определением на соответствующих ресурсах. Моя ОСь обеспечивает псевдопараллельную обработку задач-окон, следовательно, обеспечивает поддержку многозадачности. Утомили уже, ну. Исходя из определения ОС, это и есть классическая ОС с графическим интерфейсом, от ванильной OpenOS остались лишь несколько либ, переписывать которые лень и не имеет смысла ввиду их высокого изначального качества. Все остальные скрипты заменены на авторские с обратной поддержкой OpenOS. Интереса ради задам вопрос от противного: чего этой "графической оболочке" по мнению гуру ComputerCraft.ru не хватает для становления полноценной ОС?
