ECS
-
Публикации
533 -
Зарегистрирован
-
Посещение
-
Победитель дней
203
Сообщения, опубликованные пользователем ECS
-
-
Вам не надоело?Ну, это зависит от того, что подразумевается под термином "надоедание". Не надоело выкладывать программы на данный форум? Не надоело выкладывать софт, который и так уже имеется в схожих исполнениях? Нет и нет. Да и вообще, LeshaInc, сколько уже просматриваю тут различные топики - почти ни разу не увидел теплого или хотя бы нейтрального словечка от тебя. Как-то неприятно

-
3
-
-

Перед вами простенькая программа для защиты жилища от вторжения посторонних людей. У нее имеется два варианта авторизации пользователя - классическая по паролю и биометрическая по сенсору. Для работы программе требуется редстоун-контроллер.
Команда для загрузки:
pastebin run HztSLLPT
При первом запуске вам предложат настроить программу для более удобной работы с ней.

При вводе верного пароля компонент redstone будет излучать сигнал сверху, а при вводе неправильного - снизу.

Аналогичным образом работает "биометрическая" защита - после первого успешного ввода пароля ваш ник будет занесе в базу данных, и впоследствии вы будете иметь доступ к сканеру отпечатка пальца (квадратная зона справа от клавиш)
-
5
-
-

Хочу поделиться с вами редактором изображений, созданным мной и моим товарищем. Изначально в OpenComputers отсутствует такое понятие, как изображение - поэтому мы решили создать собственный графический формат, а также удобный редактор под него.
Ссылка на загрузку:pastebin run WYrTnmPx
После загрузки запускайте файл Photoshop.lua.
Начало работы:
При старте программы или по нажатию контекстного меню Файл - Новый вам будет предложено создать новый файл c указанными шириной и высотой.

В левой части редактора располагается панель инструментов, в верхней - меню и тулбар с параметрами кисти. В левом нижнем углу имеются иконки цветов - вы можете выбрать любой цвет в удобной HSB-палитре. Каждое поле в палитре доступно для ввода данных, так что можете спокойно работать с RGB-цветами, если вам угодно.

Инструменты:
У вас имеется несколько инструментов на выбор. С помощью кисти осуществляется основное взаимодействие с изображением. Например, с ее помощью мы можем нарисовать такую вот рожицу:

Вы также можете изменять размер и прозрачность кисти с помощью правого клика на зоне рисования или же на верхнем тулбаре. Размер варьируется от 1 до 10, а прозрачность от 0 до 255.

Работу системы прозрачности можно легко понять, рисуя крупной кистью с прозрачностью около 140.

Инструмент ластик действует точно так же, как и кисть, разве что он удаляет пиксели с экрана.

Инструмент заливка позволяет закрашивать большие области изображения с учетом содержимого. Давайте раскрасим нашу рожицу!

Также крайне интересен инструмент Текст - он позволяет вам делать любые надписи на изображении с помощью клавиатуры. Цветом текста будет являться первичный цвет из нижнего левого угла экрана. В данном инструменте также есть поддержка буфера обмена - так что вы можете вставлять некие особые символы или большие участки текста, если вам угодно.

Фильтры:
В данном редакторе есть несколько фильтров для работы с готовым изображением. Нажимаем на вернее меню Изображение и видим список:

По нажатию на Отразить по горизонтали наше изображение трансформируется в это:

Аналогичным образом работает и Отразить по вертикали. Если вы хотите инвертировать цвета - нажмите соответствующую кнопку и получите результат.

Ну, и напоследок можно наложить Черно-белый фильтр на нашу рожицу.

Сохранение и загрузка файлов:
При нажатии кнопки Файл - Сохранить как вам будет предложено сохранить файл с указанным именем и методом кодирвания. Рекомендую использовать метод OCIF4 для экономии места на диске, RAW полезен для дебага, он максимально понятен пользователю, но не имеет алгоритмов сжатия информации.

При нажатии кнопки Файл - Открыть вам будет предложено ввести путь к ранее сохраненному файлу в одном из поддерживаемых форматов (.pic или реальный .png)

Сочетания клавиш:
- B - выбрать инструмент Кисть
- E - выбрать инструмент Ластик
- G - выбрать инструмент Заливка
- T - выбрать инструмент Текст
- D - установить первичный цвет как черный, а вторичный как белый
- X - поменять цвета местами
- Стрелки - переместить изображение на экране
- Пробел - перерисовать изображение из памяти
Отрисовка сохраненных изображений в других программах:
При скачивании самого фотошопа идет загрузка библиотеки image.lua, обеспечивающей загрузку, сохранение и отрисовку картинки на экране. Поэтому вы при желании можете ее подключить и нарисовать сохраненное изображение из любого скрипта. Делается это следующим образом:
--Подключаем библиотеку local image = require("image") --Загрузка изображения по указанному пути. Путь к моей картинке - "Sample.pic" local myPicture = image.load("Sample.pic") --Отрисовка изображения на позиции x = 2, y = 2 image.draw(2, 2, myPicture)И тут же на экране отобразится наша картинка!

Для демонстрации возможностей этой библиотеки проще всего представить скриншот моей "ОС", где каждая иконка и обои рабочего стола - это изображение в формате .pic:

Ну, и напоследок не забудем показать всех трудившихся над этим проектом:

-
9
-

Зачастую вместе со своими программами мне приходится выкладывать дополнительные файлы к ним - библиотеки, картинки, конфиги и прочее. Чтобы решить эту проблему, я написал простенький инсталлер для автоматической загрузки указанных приложений.
Исходный код:
https://github.com/IgorTimofeev/OpenComputers/blob/master/Applications/Installer.lua
Инструкция по использованию:
В коде нас с вами будет интересовать лишь пара участков - во-первых, таблица files, в которой вы указываете, что и куда необходимо загрузить:

Во-вторых, вы можете кастомизировать инсталлер так, как вам угодно: изменять цвета, текстовую локализацию, размеры и позицию загрузочного окна на экране и т.п.:

-
10
-
-
К слову, в теории календарик автоматически определяет текущую дату методом конвертации UNIX-времени, используя os.date(). Однако выяснилось, что месяц и день данная функция выдает некорректно, скриншот ниже. Если кто-либо знает, как пофиксить данный баг - буду крайне признателен за помощь.

А должно быть:

-

На днях вспоминал, как в давние школьные годы на олимпиаде нас заставляли писать программу-календарь. Захотелось окунуться в прошлое и сделать нечто подобное на OpenComputers.
Команды для загрузки:
wget https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/ECSAPI.lua lib/ECSAPI.lua -f wget https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Calendar/Calendar.lua Calendar.lua -f
Для работы этой программе требуется моя библиотека с основными функциями, поэтому ее загрузка в первой строке обязательна. Также ей необходимы монитор и видеокарта 3 уровня.
-
4
-
-
Внутри кода sicot.lua есть простая формула генерации, и комментарии по безопасной палитре.Красава, спасибо!
-
Похоже, я на подсознательном уровне понимал, что это возможно, но не мог объяснить =))Кстати, знаешь, какие костыли мы придумываем, чтобы сделать адекватную трансляцию 0xffffff -> 0xff? Кошмар какой-то - начинали с генерации 8-битной палитры и заканчиваем какими-то совершенно безумными формулами

Вот примерчик:

-
Давно юзаю данную библиотеку в своей "ОС", каждая иконка - файл со структурой ocif. Удобная штука, рекомендую


-
Если она модульная — то мы можем легко загружать и использовать кастомные модули. Где этот функционал, в чем заключается модульность?Если либа модульная - это означает, что она имеет несколько готовых модулей (компонентов, элементов, пресетов, объектов) и возможность их подключения по желанию. Создание и подключение кастомных модулей никак не подразумевается термином "модуль". Давайте не будем заниматься казуистикой и построчно выискивать причины для критики каждой софтины

-
1
-
-
А я forms использую для всего, и для замены, и для новых проектов)Так используй, запрещает кто-то что ли? Можно и в универ, находящийся в 50 метрах от дома, ехать через северо-запад, это уже вопрос личностных привычек и предпочтений. Зачем оффтопить-то? хд
-
3
-
-
Перечисли преимущества по сравнению с forms, по исходному коду я пока не вижуПреимущества? Минимализм, простой однострочный синтаксис, автоматическое позиционирование, наличие слайдеров/селекторов/свитчей/текстовых полей. И вообще что за глупости, это две совершенно разные библиотеки с различными целями и функционалом, крайне странно их сравнивать.
Forms - серьезная либа, предназначенная для создания основы Window-based программ, данная же либа создавалась с целью встраивания в готовый софт, дабы упростить его.
А насчет "лишнего кода" - убрал, ибо действительно глаза мозолило.
-
2
-
-

Хочу поделится с вами своей библиотекой, которую использую практически в каждой программе с графическим интерфейсом. С ее помощью можно генерировать любые "окна" на свой вкус, работать с ними, а затем получать результат работы в обычном массиве.
Cкачать библиотеку:pastebin get wtWVFpKZ lib/windows.lua
Подробное описание основной функции и ее аргументов:
Из всей массы функций в данном файле нас будет интересовать лишь одна:
- windows.universalWindow(x, y, width, background, closeWindowAfter, ...)
Она отрисовывает окно с перечисленными вместо двоеточия объектами. Любой объект выделяется с помощью клика мыши, после чего функция приступает к работе с этим объектом.Аргументы функции:- x и y: это числа, обозначающие стартовые координаты левого верхнего угла данного окна. Вместо цифр вы также можете написать "auto" - и программа автоматически разместит окно по центру экрана по выбранной координате. Или по обеим координатам, если вам угодно.
-
width: это ширина окна, которую вы можете задать по собственному желанию. Если некторые объекты требуют расширения окна, то окно будет автоматически расширено до нужной ширины. Да, вот такая вот тавтология
- background: базовый цвет окна (цвет фона, кому как понятнее).
- closeWindowAfter: eсли true, то окно по завершению функции будет выгружено, а на его месте отрисуются пиксели, которые имелись на экране до выполнения функции. Удобно, если не хочешь париться с перерисовкой интерфейса.
- ... : многоточием тут является перечень объектов, указанных через запятую. Каждый объект является массивом и имеет собственный формат. Ниже перечислены все возможные типы объектов.
{"Button", {Цвет кнопки1, Цвет текста на кнопке1, Сам текст1}, {Цвет кнопки2, Цвет текста на кнопке2, Сам текст2}, ...}
Это объект для рисования кнопок. Каждая кнопка - это массив, состоящий из трех элементов:цвета кнопки, цвета текста на кнопке и самого текста. Кнопок может быть неограниченное количество,однако чем их больше, тем большее требуется разрешение экрана по ширине.Интерактивный объект.{"Input", Цвет рамки и текста, Цвет при выделении, Стартовый текст [, Маскировать символом]}Объект для рисования полей ввода текстовой информации. Удобно для открытия или сохранения файлов,Опциональный аргумент "Маскировать символом" полезен, если вы делаете поле для ввода пароля.Никто не увидит ваш текст. В качестве данного аргумента передается символ, например "*".Интерактивный объект.{"Selector", Цвет рамки, Цвет при выделении, Выбор 1, Выбор 2, Выбор 3 ...}Внешне схож с объектом "Input", однако в этом случае вы будете выбирать один из предложенныхвариантов из выпадающего списка. По умолчанию выбран первый вариант.Интерактивный объект.{"Select", Цвет рамки, Цвет галочки, Выбор 1, Выбор 2, Выбор 3 ...}Объект выбора. Отличается от "Selector" тем, что здесь вы выбираете один из вариантов, отмечаяего галочкой. По умолчанию выбран первый вариант.Интерактивный объект.{"Slider", Цвет линии слайдера, Цвет пимпочки слайдера, Значения слайдера ОТ, Значения слайдера ДО, Текущее значение [, Текст-подсказка ДО] [, Текст-подсказка ПОСЛЕ]}Ползунок, позволяющий задавать определенное количество чего-либо в указанном интервале. Имеются дваопциональных аргумента, позволяющих четко понимать, с чем именно мы имеем дело.К примеру, если аргумент "Текст-подсказка ДО" будет равен "Съедено ", а аргумент "Текст-подсказка ПОСЛЕ"будет равен " яблок", а значение слайдера будет равно 50, то на экране будет написано "Съедено 50 яблок".Интерактивный объект.{"Switch", Активный цвет, Пассивный цвет, Цвет текста, Текст, Состояние}Переключатель, принимающий два состояния: true или false. Текст - это всего лишь информация, некоеназвание данного переключателя.Интерактивный объект.{"CenterText", Цвет текста, Сам текст}Отображение текста указанного цвета по центру окна. Чисто для информативных целей.{"WrappedText", Цвет текста, Текст}Отображение большого количества текста с автоматическим переносом. Прото режет слова на кусочки,перенос символический. Чисто для информативных целей.{"TextField", Высота, Цвет фона, Цвет текста, Цвет скроллбара, Цвет пимпочки скроллбара, Сам текст}Текстовое поле с возможностью прокрутки. Отличается от "WrappedText"фиксированной высотой. Чисто для информативных целей.{"Separator", Цвет разделителя}Линия-разделитель, помогающая лучше отделять объекты друг от друга. Декоративный объект.{"EmptyLine"}Пустое пространство, помогающая лучше отделять объекты друг от друга. Декоративный объект.Каждый из объектов рисуется по порядку сверху вниз. Каждый объект автоматическиувеличивает высоту окна до необходимого значения. Если объектов будет указано слишком много -т.е. если окно вылезет за пределы экрана, то программа завершится с ошибкой.Что возвращает функция:Возвратом является массив, пронумерованный от 1 до <количества объектов>. То есть 1 индекс данного массива соответствует 1 указанному интерактивному объекту. Каждый индекс массива несет в себе какие-то данные, которые вы внесли в объект во время работы функции. Например, если в 1-ый объект типа "Input" вы ввели фразу "Hello world", то первый индекс в возвращенном массиве будет равен "Hello world".Конкретнее это будет вот так: massiv[1] = "Hello world".Примеры работы с библиотекой:
Пример 1
Сгенерируем наше первое окошко, создав программу со следующим кодом:
--Подключаем скачанную библиотеку local windows = require("windows") --Рисуем окошко на экране windows.universalWindow("auto", "auto", 30, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x262626, "Hello world!"}, {"EmptyLine"}, {"Button", {0x880000, 0xffffff, "Йо"}})На экране отобразится следующее:

Командой выше мы рисуем окно по автоматически рассчитанным координатам (по центру экрана), так как первые два аргумента равняются "auto", "auto". Затем мы указали ширину окна - 30 пикселей. Затем указали, что основной фон окна будет иметь цвет 0xeeeeee, то есть почти белый. Затем начинается самое интересное - мы задаем объекты нашего окна!
- {"EmptyLine"} служит всего лишь для красоты, так мы разделяем объекты окна друг от друга.
- {"CenterText", 0x262626, "Hello world!"} рисует текст "Hello world" цвета 0x262626 по центру окна.
- {"Buttons", {0x880000, 0xffffff, "Йо"}} рисует одну-единственную кнопку красного (0x880000) цвета, а на ней уже белый (0xffffff) текст "Йо".
По нажатию на кнопку окно автоматически закрывается, а на его месте рисуются те пиксели, которые были до старта окна, так как мы задали параметр closeWindowAfter = true.
Пример 2
Теперь попытаемся извлечь практическую пользу из наших окошек - напишем программу, спрашивающую, стоит ли совершить какое-то действие. И чтобы как только мы нажмем на одну из кнопок, нам писалось это действие.
Создадим следующую программу:
local windows = require("windows") --Получаем массив с данными о работе нашего окна local action = windows.universalWindow("auto", "auto", 30, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x262626, "Файл \"OS.lua\" уже имеется в этом месте."}, {"CenterText", 0x262626, "Заменить его перемещаемым объектом?"}, {"EmptyLine"}, {"Button", {0xdddddd, 0x262626, "Оставить оба"}, {0xffffff, 0x262626, "Отмена"}, {0x99b2f2, 0xffffff, "Заменить"}}) --Вызываем функцию очистки окна и установки курсора на 1, 1 (она тут имеется) windows.prepareToExit() --Выводим содержимое массива окна print(table.unpack(action))На экране отобразится следующее:

Но как только мы нажимаем, к примеру, на кнопку "Заменить", экран очистится, и перед нами предстанет следующее:

Как и в предыдущем примере, мы нарисовали окно по центру экрана с основным цветом 0xeeeeee, разве что мы вывели две строки с текстом вместо одной и нарисовали сразу три кнопки друг за другом.
Затем, как только мы нажали на кнопку, программа автоматически завешилась и вернула нам массив с состояниями объектов. Поскольку в нашей программе интерактивными объектами являются только кнопки, массив будет иметь лишь один элемент - название кнопки, на которую мы нажали. Таким образом наша программа может взаимодействовать с пользователем на графическом уровне, получать от него информацию, и выдавать эту информацию компьютеру для дальнейшей обработки.
Пример 3
В последнем примере мы создадим самую сложную программу со всеми возможными элементами окна. Далее следует много текста, аккуратнее:
local windows = require("windows") --Очищаем экран перед использованием окна и ставим курсор на 1, 1 windows.prepareToExit() --Рисуем окно и получаем данные после взаимодействия с ним local data = windows.universalWindow("auto", "auto", 36, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x880000, "Здорово, ебана!"}, {"EmptyLine"}, {"Input", 0x262626, 0x880000, "Сюда вводить можно"}, {"Selector", 0x262626, 0x880000, "Выбор формата", "PNG", "JPG", "GIF", "PSD"}, {"EmptyLine"}, {"WrappedText", 0x262626, "Тест автоматического переноса букв в зависимости от ширины данного окна. Пока что тупо режет на куски, не особо красиво."}, {"EmptyLine"}, {"Select", 0x262626, 0x880000, "Я пидор", "Я не пидор"}, {"Slider", 0x262626, 0x880000, 1, 100, 50, "Убито ", " младенцев"}, {"EmptyLine"}, {"Separator", 0xaaaaaa}, {"Switch", 0xF2B233, 0xffffff, 0x262626, "✈ Авиарежим", false}, {"EmptyLine"}, {"Switch", 0x3366CC, 0xffffff, 0x262626, "☾ Не беспокоить", true}, {"Separator", 0xaaaaaa}, {"EmptyLine"}, {"TextField", 5, 0xffffff, 0x262626, 0xcccccc, 0x3366CC, "Тест текстового информационного поля. По сути это тот же самый WrappedText, разве что эта хрень ограничена по высоте, и ее можно скроллить. Ну же, поскролль меня! Скролль меня полностью! Моя жадная пизда жаждет твой хуй!"}, {"EmptyLine"}, {"Button", {0x57A64E, 0xffffff, "Да"}, {0xF2B233, 0xffffff, "Нет"}, {0xCC4C4C, 0xffffff, "Отмена"}}) --Еще раз ставим курсор на 1, 1 windows.prepareToExit() --С помощью цикла выводим данные из массива data, полученные после взаимодействия с окном print(" ") print("Вывод данных из окна:") for i = 1, #data do print("["..i.."] = " .. tostring(data[i])) end print(" ")На экране отобразится следующее:

Далее давайте введем в текстовое поле какую-то белиберду:

Затем выберем формат файла "JPG":

Затем укажем программе, что у нас все в порядке с сексуальной ориентацией:

Cдвинем ползунок влево, указав, что никакие младенцы не были убиты:

Переключим оба слайдера в значение "ON":

И наконец, кликнем на кнопку "Да". Экран очистится, а в левом верхнем углу выведется содержимое массива, возвращенного окном после работы.

Подытожив, можно сказать, что на экране отобразилось содержимое всех интерактивных объектов окна, то бишь:
privetEpta - значение объекта Input
JPG - значение объекта Selector
Я не пидор - значение объекта Select
0 - значение объекта Slider
true - значение первого объекта Switch
true - значение второго объекта Switch
Да - значение объекта Button, т.е. название кнопки, на которую мы нажали
Надеюсь, общий принцип работы данной библиотеки ясен, поэтому расписывать все досканально в мельчайших деталях не вижу смысла. Главное, чтобы данные "окошки" послужили вам верой и правдой.
-
15
-
1
-

Ссылка на скачивание:
pastebin get CcusRikg lib/scale.lua
Данная библиотека избавит вас от надоедливых "черных полос", возникающих при выставлении собственного разрешения экрана. Она крайне проста в использовании:--Подгружаем библиотеку local scale = require("scale") --Выставляем масштаб монитора scale.set(1)Функция scale.set() требует одно-единственное число в диапазоне от 0.1 до 1, при этом 1 представляет собой максимальный масштаб. Она универсальна, работает с любыми типами мониторов и видеокарт, работает также с вертикальной ориентацией экрана. Ниже несколько примеров использования:-
10
-
-
Не понял назначения параметра limit. По моему ничего он там не ограничивает.Это аналог string:sub() по сути. Если строка имеет 1000 символов, то логично, что ее нужно обрезать по ширине экрана, чтобы не рисовался лишний кал и не нагружался gpu. Limit этим и занимается. И не нужно писать "по-моему" - мне, как автору либы, лучше знать, ограничивает данный аргумент что-то или нет. Насчет обрезки слева - да, сделаю в ближайшем времени, спасибо

-
Не совсем понял для чего использовать библиотеку отдельноДля сторонних программ, разумеется. Меня стандартный Edit не устраивает ни коим образом, буду допиливать свою среду разработки. А помимо этой среды подсветку буду юзать в предпросмотре файлов в клиенте Pastebin - то есть мы уже имеем как минимум две программы, где потребуется данная либа. Не дублировать же один и тот же код в каждой из них, верно?
В циклах используй кеширование функций для unicode.find,А вот за это большое спасибо, люблю конструктив. Сейчас потестирую быстродействие.
UPD: прироста скорости не заметил вовсе. Если она и возросла, то визуально это не подтвердилось.
-
1
-
-
Вступление:
Решил я на днях написать хорошую IDE для OpenComputers и столкнулся с тем, что в ванильной OpenOS
напрочь отсутствует подсветка синтаксиса. Надо это исправить!
Если найдутся какие-либо недочеты в плане правильности подсветки - пишите, пофиксим.
Скачать библиотеку:
Инструкция по использованию:
--Подключаем библиотеку local syntax = require("syntax") --Создаем любую строку с операторами lua local stroka = "while true do print(\"Hello world!\")" --x, y - стартовые координаты отрисовки текста. --limit - ограничение отрисовки по ширине строки. Зачем рисовать лишние пиксели? local x, y, limit = 2, 2, 20 --Выводим строку на экран в подсвеченном варианте syntax.highlightAndDraw(x, y, limit, stroka)На экране отобразится следующее:
Другие функции:
● syntax.setColorScheme(цветовая схема)
Устанавливает цветовую схему по выбору пользователя.На данный момент есть лишь две схемы: "midnight" и "sunrise".
● syntax.highlightFileForDebug(путь к файлу [,цветовая схема])
Открывает обычный файл по указанному пути и выводит его содержимое
в подсвеченном виде на экран. Размер содержимого ограничен размером экрана.
Пример использования этой функции предоставлен на самом первом скриношоте.
Насчет оптимизации и ускорения:
Я постарался минимизировать задержки в выполнении скрипта различными путями.
Во-первых, отрисовка выполняется не попиксельно, а построчно. То есть если мы имеем строку красного цвета,
то функция отрисовки выведет на экран сразу всю строку, а не каждый символ по отдельности.
Во-вторых, цвет текста изменяется только тогда, когда это необходимо, а не каждый раз при смене символов.
На данный момент у программы есть существенный минус: при отрисовке выполняется поиск совпадений шаблонов
по строке через оператор string.find(), однако изначально он не дружит с юникодом. Поэтому пришлось использовать
костыль unicode.find(), существенно замедляющий процесс поиска. Если у кого-то имеется более оптимизированный
костыль или способ поиска по юникоду, буду крайне благодарен за помощь в этом деле.
Для ясности прикладываю видосик:
http://www.youtube.com/watch?v=T-f8jGdYO0M&feature=youtu.be
Исходный код unicode.find():
function unicode.find(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
-
7
-

Кодовая и биометрическая защита двери
в Инфраструктура
Опубликовано: · Изменено пользователем EliteClubSessions
И ведь в каждом микросоциуме такой индивид найдется! Печаль-беда.
Вот те раз, оказывается, я ее писал не единолично, а с друзьями: признаюсь, это новость для меня. А если серьезно, то мои друзья маразмом не страдают, и даже если бы мы и писали "ОС" вместе, то они точно не стали бы обижаться на такую чушь, как отсутствие упоминания их имен "где-то там"