OberonCore https://forum.oberoncore.ru/ |
|
Упрощение Oberon https://forum.oberoncore.ru/viewtopic.php?f=115&t=6867 |
Страница 1 из 3 |
Автор: | Comdiv [ Воскресенье, 25 Сентябрь, 2022 23:54 ] |
Заголовок сообщения: | Упрощение Oberon |
Предлагайте, что по Вашему в Oberon избыточно. Начну с малого, но бесспорного - функции ODD. 1. Нужно очень редко. 2. Заменяется невероятно просто - x MOD 2 = 1, что указано в самом определении. 3. На мой взгляд, смысл замены очевидней предопределённой функции. Odd - это странный(да, и нечётный тоже). 4. Оптимизация генерации для него не нужна, а если, всё-таки, хочется, то более обобщённая оптимизация деления степени 2-ки не только проста, но и полезней. Однажды был зафиксирован казус - использование ORD(ODD(x)) вместо более прозрачного и короткого x MOD 2. Напомню для тех, кто забыл, что в Обероне второй вариант не требует отдельного учёта отрицательных x, поэтому он всегда тождественен первому. |
Автор: | Виктор Мясников [ Вторник, 27 Сентябрь, 2022 09:13 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
Comdiv писал(а): Предлагайте, что по Вашему в Oberon избыточно. В этом вопросе многое зависит от дефиниции слова "избыточно":например, избыточны ли CASE и FOR? Естественно, без них вполне можно обойтись. Но они нужны для упрощение написания оптимизирующего компилятора. |
Автор: | AlexBogy [ Суббота, 25 Февраль, 2023 09:49 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
Приведу цитату из статьи Н. Вирта "От Модулы к Оберону": В то же время язык программирования не должен быть одной лишь математической теорией. Он должен быть практическим инструментом. Это подразумевет определенные ограничения, накладываемые на краткость формализма. Несколько языковых средств Oberon с чисто теоретической точки зрения являются излишними. И, тем не менее, они присутствуют в языке из сугубо практических соображений, то ли для удобства самого программиста, то ли для достижения эффективной кодогенерации без использования в компиляторах сложных «оптимизирующих» алгоритмов сопоставления шаблонов. Примерами таких языковых средств являются наличие нескольких форм оператора цикла, а также существование стандартных процедур, таких как INC, DEC и ODD. Они не усложняют ни язык, ни компилятор. |
Автор: | JackKatch [ Суббота, 25 Февраль, 2023 15:27 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
Никлаус Вирт упоминал, что по этому вопросу было много обсуждений в его команде. Для таких предложений нужен большой опыт. Для чего вообще что то исключать? Встраиваемая функция ODD транслируется в одну, две, или около того инструкции процессора (для этого она и нужна). А вот выражение x MOD 2 = 1, неизвестно во сколько инструкций (зависит от компилятора, опций оптимизации и тд). Оператор CASE вероятно занимает больше места в коде чем последовательность операторов IF, но он выполняет переход к требуемому блоку по значению выражения за одно сравнение. По моему тут нет избыточности. Более ценно, с моей точки зрения, реализация самодостаточной среды поддержки компилятора (операционной системы) для всех доступных архитектур вычислительных машин. На примере Ричарда Столмана и попытки создания свободной UNIX, видно что у каждого свой вкус и взгляд (Каждый сделал какой то инструментарий, а на ядро пороха не хватило.). И бесконечные дебаты не позволят что либо сделать. Нужно (с моей точки зрения) как Линус, поставить сообщество перед фактом чего то готового, тогда возможно это что то обретёт поддержку и жизнь. А иначе - лебедь, рак и щука. (Сделайте самостоятельно что то рабочее и продвигайте. Если ваша работа будет обладать преимуществами, то её поддержат.) |
Автор: | Comdiv [ Суббота, 25 Февраль, 2023 19:27 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
AlexBogy писал(а): Приведу цитату из статьи Н. Вирта "От Модулы к Оберону": Если хочется процитировать Вирта, то лучше его и цитировать, а не переводчика. Не всегда есть разница, но раз берёте на себя ответственность за высказывание, то не лишне и проделать небольшую дополнительную работу на всякий случай. Спасибо Руслану Богатырёву за перевод, но сейчас даже машины... Впрочем, предоставим им слово.ЕИ писал(а): Предложение "They complicate neither the language conceptually nor the compiler to any significant degree" было переведено как "Они не усложняют ни язык, ни компилятор". Что можно сказать об этом? ИИ писал(а): Перевод не полностью передает смысл оригинальной фразы.
В оригинальной фразе используются слова "conceptually" и "to any significant degree", которые означают, что изменения, которые описываются, не имеют значительного влияния на язык или компилятор, поэтому они не сильно усложняются. То есть, "conceptually" указывает на то, что изменения не затрагивают основополагающие концепции языка программирования, а "to any significant degree" указывает на то, что изменения не существенны и не вносят значительных изменений в язык или компилятор. В переводе отсутствует уточнение о том, что изменения не существенны и не влияют на язык или компилятор. Перевод "Они не усложняют ни язык, ни компилятор" может быть воспринят как полное отсутствие изменений, в то время как оригинальный текст указывает на наличие некоторых изменений, которые просто не являются существенными. Более точный перевод оригинальной фразы мог бы звучать как "Они не существенно усложняют язык и компилятор с концептуальной точки зрения", что более точно передает смысл оригинальной фразы. |
Автор: | Comdiv [ Суббота, 25 Февраль, 2023 19:33 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
JackKatch писал(а): Для таких предложений нужен большой опыт. Этот опыт уже давно лежит в виде готовых исходных кодов. Например.Код: cat ProjectOberon2013/Sources/*.Mod | grep INC\( | wc --lines Видите, почему речь была про ODD, а не об INC?
312 cat ProjectOberon2013/Sources/*.Mod | grep ODD\( | wc --lines 19 |
Автор: | Comdiv [ Вторник, 05 Ноябрь, 2024 19:38 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
Пришёл к выводу, что лишними в Oberon являются "строки" в паре с CHAR. Строки — это устаревший плоскотекстовый костыль для кучи всего, но по-хорошему, все части этой кучи необходимо делать нормально, а не через напишите-что-хотите-а-там-разберутся. Строки вынуждают поставить язык в зависимость от кодировки, либо лишая его переносимости даже без обмена со средой, либо вынуждая принять один из имеющихся плохих вариантов, вероятно, с половинчатой поддержкой. Также это стимулирует поломки и избыточную ресурсоёмкость в обмене со средой. |
Автор: | budden [ Среда, 06 Ноябрь, 2024 10:25 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
По теме сказать нечего, но, если нужен более простой язык, чем Оберон, то это лисп. Если выкинуть лишнее из Common Lisp, то полученный язык будет обладать примерно такими свойствами:
Мало того, будучи более простым, язык получится более выразительно мощный
А дальше упрощать именно Оберон - ну не ясно, зачем. Оберон не является самым простым языком, т.е. та точка, к которой вы стремитесь - я не вижу, каковы в ней какие-то объективные свойства, по которым её можно определить. Субъективно - может быть. Т.е. можно сказать только "упрощать Оберон, чтобы он остался Обероном". Можно придраться к тому, что деоптимизация рантайм-среды больно ударяет по эффективности, но на SIM-картах наших телефонов вообще прошивка на Java написана, если я не ошибаюсь, а это ещё больнее. А ещё дальше можно попробовать вычислить некую точку, среднюю между тем минимумом, который я описал, и Обероном 07. Например, вернуть константность и сделать более эффективный рантайм. Получится примерно такой лисп, который я начал для дел, связанных со своей работой писать, https://tvoygit.ru/budden/ja-o-s/src/branch/главная/source/Общелисп.ярм , хотя это лишь нашлёпка в рамках АО, а не самодостаточная реализация, и в ней нет полного набора перечисленных возможностей и ограничений, да и надобность уже отпала, так что дальше это вряд ли продвинется. |
Автор: | budden [ Среда, 06 Ноябрь, 2024 10:39 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
После Лиспа некоторые вещи в Обероне выглядят как наказание. Например, почему я не могу в качестве параметра принять любой объект и сделать ветвление по типу элементов массива, если объект - массив? Непонятно. Почему я не могу иметь функцию с переменным числом аргументов? Самое обидное, что в компиляторе и в рантайме всё это есть, но мне не дают этим пользоваться. В итоге приходится городить костыли на ровном месте, и простота языка работает не на качество кода, а против. Ну ладно, не всё там есть, на самом деле в A2/ЯОС рантайм-среда не всё знает про тип объекта в рантайме, а знает только минимум, достаточный для сборки мусора. Но всё равно там есть тег типа, специально деградированный для рантайма. Достигнутая экономия довольно мала и для меня она не выглядит оправданной. Хотя, если нужно ужаться по размеру, то тогда да. Однако простота языка и ужатость кода по размеру тоже противоречат друг другу, неясно, почему всегда нужно предпочитать именно те выборы, которые были сделаны для Оберона, и в каких случаях нужно предпочесть именно Оберон, а в каких - что-то другое. Так-то если ужатость по размеру является наиболее приоритетной, то сборка мусора с тегами типов, флагами сборщика и резервом пространства для обеспечения цикличности сборки - уже неоптимальна, т.е. одно из фундаментальных свойств Оберона этому противоречит. Если же мы выкидываем сборку мусора, то я уже с трудом смогу сказать, чем этот язык по сути дела отличается от Паскаля. |
Автор: | Comdiv [ Среда, 06 Ноябрь, 2024 21:30 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
Поясню, что мой вопрос не касался предложения создания или выбора самого простого языка, а только устранения избыточностей — это хороший способ поразмышлять и обобщить свой опыт и посмотреть на чужой. Вы ответили не то, чтобы совсем не по теме, сколько сформулировали его, уведя в сторону. Вы могли бы написать, что синтаксис Оберона избыточен, и предложить более простой, а не писать про мифическую простоту Lisp. Про Lisp могу сказать, что утверждение, что его синтаксис прост — это заблуждение, основанное на том, что люди путают его синтаксис с синтаксисом s-expressions. К слову, даже синтаксис 1-го уровня, не дающий представления о самом языке, описывается в спецификации на 44 страницах — больше 2-х описаний всего языка Oberon. Конечно, можно забыть про синтаксис Lisp и предложить свой простой вариант S-expression для Oberon и писать, например, так: Код: (module Hell-o (import Out) (procedure Go * () ( ((Out String) "Hell world") (Out Ln) )) ) Да только и тогда синтаксис Oberon не упростится, поскольку порядок и состав конструкций останется прежним, и только от того, что синтаксис станет трёхуровневым вместо двухуровневого, волшебства не произойдёт. Наоборот, синтаксис Оберона гениален в том плане, что его разбор является тривиальной задачей даже без специализированных средств, а программисту не нужно подстраиваться под ограничения/особенности концепции/инструмента. |
Автор: | budden [ Четверг, 07 Ноябрь, 2024 16:42 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
Можно не искать везде подвох и манипуляцию, а просто попытаться понять сжато изложенные для людей в теме мысли. Синтаксис лиспа проще по причине отсутствия в нём приоритетов операций, а не по причине отсутствия таких конструкций, как PROCEDURE (они на самом деле есть, просто ниже по течению компиляции, тут я согласен, но я обратного и не утверждал). Так что Вы просто-напросто тут были неправы, и неплохо бы это признать, а не сразу начинать с обвинений, что я что-то там увожу в сторону. Ссылки на краткость описания Оберона для меня не убедительны. Я считаю, что Оберон недостаточно специфицирован, некоторые вещи там подразумеваются неявно, а некоторые дают неопределённое поведение. Поэтому это не тот параметр, которым нужно меряться. Дальше, я не говорил про CL, а говорил про некий мифический упрощённый лисп. Из какой книги Вы взяли эти 44 страницы? > Поясню, что мой вопрос не касался предложения создания или выбора самого простого языка, а только устранения избыточностей — это хороший способ поразмышлять и обобщить свой опыт и посмотреть на чужой. Так тут весь вопрос, насколько глубоко мы готовы переработать язык и что считать избыточностью. Например, считать ли избыточностью модули? Си и лисп без них обходятся. Я вчера ещё над этим подумал. В общем-то необходимыми они являются (на мой взгляд, если ничего не упустил) для сборки и раздельной компиляции. Если мы будем кросс-компилировать программу на лиспе, всё равно там будут единицы трансляции, а в Обероне порядок сборки определяется (точнее сказать, может определяться, если это реализовано) деревом зависимостей модулей. Т.е. можно считать это преимуществом. Но опыт Си и Лиспа опять же показывает, что оно некритично, и язык и без этого будет пригоден (и даже масштабируем). |
Автор: | budden [ Четверг, 07 Ноябрь, 2024 19:13 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
P.S. ещё в лиспе, уж не знаю, отнести ли это к синтаксису или к чему, меньше разнообразие разных эээ, конструкий. По идее там есть функции, макросы и специальные операторы (special operators). Вроде как их больше, чем в Обероне, но это как посмотреть. Например, if - это специальный оператор, typecase (аналог case) и or - это макросы, а not - функция. Но с другой стороны, в Обероне макросов нет (минус много выразительности), case и if - это операторы, отличающиеся синтаксически и семантически от функций, not можно точно так же сделать процедурой, но синтаксически она другая, or - это точно так же специальная псевдо-процедура, но синтаксически она не процедура. halt - это оператор (предписание), но синтаксически он выглядит как процедура. Дальше ещё есть (тип)значение и значение(тип) - это операции (в лиспе были бы макросами), но выглядят так же, как функции. В лиспе получается с точки зрения формы разнообразие минимальное (один вид форм), но семантически есть три категории. В Обероне категорий может быть и две с точки зрения семантики (потому что нельзя определять свои макросы), но синтаксически я не знаю сколько их, видимо три: процедура, оператор (предписание) и операция. Тут нельзя сказать, что лисп проще Оберона в плане разнообразия форм, скорее он сложнее, но если смотреть только на синтаксическую часть, то он проще. Притом в лиспе этот простой синтаксис позволяет создавать литералы деревьев (про макросы уже было сказано), а в Обероне этого нет и в помине. Нужны ли литералы деревьев в сверх-простом языке - это конечно уже вопрос само по себе. Однако в лиспе они уже и так есть, если есть сам лисп, т.е. получается бесплатное приложение к тому, без чего и так не получится обойтись. Т.е. в компиляторе вопросом становится только их укладка в объектный (или какой там будет) файл. Если идти дальше в сторону простоты, то, наверное, останется ассемблер или там какой-нибудь Форт. Но они ниже уровнем, чем Оберон, а Лисп - выше (т.к. есть макросы, дающие возможность создавать свои абстракции, что в Обероне можно сделать только косвенным путём, отображая их на скудный набор тех абстракций, которые уже есть). Но в принципе, если нужен совершенно минимальный язык, то и этой дорогой стоило бы пройти. Видимо, не в этой теме ![]() |
Автор: | budden [ Пятница, 08 Ноябрь, 2024 13:50 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
Ладно. Лисп не подходит по условию задачи. Смотрите, сейчас от Оберона почти ничего не останется. Выкидываем избыточное. Любую программу можно будет переписать на Oberon--07, и она по-прежнему будет так же работать. * OR, AND, NOT - их можно заменить условными операторами * циклы FOR и UNTIL - их можно заменить циклом WHILE * модули - они вообще не являются необходимыми, а если необходимо переименование, то это решается через записи * экспорт - экспортируем всё * наследование записей - можно добавить явные поля с указанием кода типа, введённого на уровне приложения, а методы решить через явно реализованные таблицы методов * CASE - для записей он больше не нужен ввиду несуществования наследования, а для простых типов его можно заменить на ветвления * приоритет операций. Выражение упрощается и может содержать только одну операцию, операнды которой являются идентификаторами или литералами * комментарии - они не являются необходимыми для минимального языка * INC и DEC, кажется, можно заменить присваиванием выражения Если идти ещё дальше, то тут уже могут начаться некоторые проблемы с качеством работы программ, например, нагрузкой на кучу, или просто будут делаться какие-то лишние действия: * убрать отличие между процедурами и функциями, оставить только функции * константы - можно заменить переменными * выкинуть записи как таковые и оставить только указатели на них * VAR параметры (при необходимости вернуть более одного значения пользоваться указателями, или возвращать указатели на запись) * числовые литералы со знаком минус * так-то по-хорошему вообще можно выкинуть целочисленные литералы, кроме единицы. Любое целое число можно получить с помощью арифметических операций из единицы. * да наверное и плавающие литералы не нужны, но это не точно * строковые литералы тоже можно выкинуть, их можно заменить массивами чисел, хотя тут я не на 100% уверен. |
Автор: | budden [ Пятница, 08 Ноябрь, 2024 14:07 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
Если вы думаете, что я издеваюсь, то это будет лишь частично верно. Когда-то я реально хотел сделать язык без отрицательных литералов, чтобы не стало операций, которые являются одновременно унарными и бинарными. Данная неоднозначность не только усложняет код лексера, но и потенциально является источником ошибок при достаточно сложном синтаксисе. В Обероне прошли по краю и она вроде бы не работает, но я уже забыл. Наследование записей в Обероне сделано не весьма удачно, т.к. нет статических методов (если я правильно понимаю). При том, что это можно сделать библиотекой, зачем оно в языке? В Си этого нет, а ООП там есть, например, gobjects. На надёжность языка никакого положительного воздействия эрзац-ООП не оказывает, скорее отрицательное (я менял язык в ЯОС, чтобы нельзя было допустить опечатку при перекрытии методов, т.е. добавил слово "перекрыта"). На быстродействие - тоже. Наоборот, если я правильно помню, то в записи добавляется столько дополнительных полей, сколько у неё предков, чтобы быстро можно было проверять соответствие типу. Только не помню, это делается в самом экземпляре записи или в информации о типе. Это не является единственно возможным решением, а значит, неясно, почему оно должно быть зашито в язык. Модули реально не являются необходимыми, я уже приводил примеры распространённых языков, на которых без модулей пишут огромные приложения. Реализация модулей через записи (и даже ещё хуже - через функции) используется в JavaScript. Дубликаты конструкций циклов я бы и сам выкинул из языка, претендующего на простоту. Отсутствие записей, а наличие только указателей на них является реалиями жизни в лиспе, java и javascript. Но кстати, я забыл ещё одну вещь. Неявные преобразования типов при арифметических операциях. Они не только усложняют язык, они ещё являются ненадёжными, т.к. постижимость программы снижается. Их надо выкинуть при упрощении языка обязательно. В той мере, в которой я читал компиляторы Оберона, мои меры по сокращению языка приведут к существенному упрощению компилятора. Правда, писать на таком языке будет ненамного удобнее, чем на ассемблере, или ещё хуже. Но тем не менее, если поставлена задача устранения избыточности, то она решается так. Либо надо более ясно определить, что мы называем избыточностью, а где уже начинается мясо, и почему это так, если вспоминать лозунг про простоту. В моём случае я понимаю под мясом то, что язык компилируемый, статически типизированный и безопасный по памяти, если не используется модуль SYSTEM. Если, конечно, под мясом понимать, что он модульный, то модули выкидывать нельзя. Что ещё является сутью Оберона? А кстати не всё хорошо с записями. Если выкинуть записи, то не останется полиморфизма совсем, т.е. нет ни void*, ни union-ов. Ну решение-то понятно какое правильное (тип ANYREC), но если добавлять ничего нельзя, то придётся всё же использовать композицию. Теряется свойство линейности при переписывании программ, т.к. иерархии придётся переворачивать и делать насыщенными. В общем, если именно ничего нельзя выкидывать, то наследование записей придётся оставить, хотя я не могу сказать, что оно украшают язык. В этом случае можно выкинуть хотя бы методы, хотя вроде их уже выкинули (я смотрю вот сюда: https://people.inf.ethz.ch/wirth/Oberon ... Report.pdf ) |
Автор: | SovietPony [ Пятница, 08 Ноябрь, 2024 20:41 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
Из Oberon-07 я бы однозначно выкинул оператор ^, он бесполезен. А так же тип BYTE, он бесполезен, а из-за молчаливой обрезки при конверсии INTEGER->BYTE ещё и вреден. ODD использую когда есть такая возможность, выпиливать бы не стал. Вернул бы BITS и WITH(не нравится мне смешивание двух разных по смыслу конструкций в одну). |
Автор: | Trurl [ Суббота, 09 Ноябрь, 2024 13:34 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
SovietPony писал(а): Из Oberon-07 я бы однозначно выкинул оператор ^, он бесполезен. А как различать a:= b и a^:=b^ ? |
Автор: | SovietPony [ Суббота, 09 Ноябрь, 2024 17:48 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
А никак. Операция копирования содержимого по указателям редкая (5 использований на всю оберон-ос) и вредная (копирует приватные поля родительских типов, значения в которых может ожидаться уникальными). |
Автор: | Comdiv [ Суббота, 09 Ноябрь, 2024 23:01 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
SovietPony писал(а): Из Oberon-07 я бы однозначно выкинул оператор ^, он бесполезен. А я постоянно использую в фактических параметрах вызовов и детали семантики там другие.«А так же тип BYTE, он бесполезен, а из-за молчаливой обрезки при конверсии INTEGER->BYTE ещё и вреден.» Специфиакация задаёт семантику присваивания как получение тождества, что при переполнении диапазона нарушается. Отсутствие диагностики — это выбор(нежелание) воплотителя, а не предписание языка. При отсутствии BYTE фактическое переполнение в некой алгоритмической замене BYTE никуда не денется. «ODD использую когда есть такая возможность, выпиливать бы не стал.» Можете привести личную статистику по ODD в сопоставлении с некоторымм другими предопределёнными процедурами? |
Автор: | SovietPony [ Воскресенье, 10 Ноябрь, 2024 21:35 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
Comdiv писал(а): А я постоянно использую в фактических параметрах вызовов и детали семантики там другие. Ну для такого случая можно сделать автоматическое разыменование. Хотя тоже сомнительная фича - получится делать x := y^ через вызов.Надо какой-нибудь аттрибут для защиты от копирования приватных данных. Comdiv писал(а): Отсутствие диагностики — это выбор(нежелание) воплотителя А иначе никак. Байт не встраивается в систему типов оберон-07, потому что тут нету иерархии типов, а значит и нету функции SHORT() которая бы явно сказала об обрезке.Если использовать CHAR как замену, то тут есть CHR() как замена SHORT(). Так-то можно не выпиливать, а вернуть взад в SYSTEM. Comdiv писал(а): Можете привести личную статистику по ODD в сопоставлении с некоторымм другими предопределёнными процедурами? У меня нет столько кода на оберон-07 что бы такая статистика показывала хоть что-нибудь связанное с реальностью.Кстати, в оберон-07 не хватает функции BITS() из КП. Приходится лезть в SYSTEM когда он совершенно не нужен. |
Автор: | Comdiv [ Понедельник, 11 Ноябрь, 2024 22:19 ] |
Заголовок сообщения: | Re: Упрощение Oberon |
SovietPony писал(а): А иначе никак. В случае наличия желания все провекри работают. Для этого нет необходимости в SHORT. Нарушение правил спецификации является достаточным условием. «У меня нет столько кода на оберон-07» А в данном контексте совершенно не важен диалект. Подойдёт любой. «Кстати, в оберон-07 не хватает функции BITS() из КП. Приходится лезть в SYSTEM когда он совершенно не нужен.» Понимаю, что не хватает, но достаточно ровно один раз полезть в SYSTEM, чтобы воплотить соответствующую функцию, а потом лезть в этот модуль, а не SYSTEM. Есть ещё компиляторный хак с псевдомодулем, но это скорее лишнее, потому что с совместимостью всё равно никто не заморачивается, а просто функцию добавить проще. Можете привести примеры кода, для которых вы используете число как множество? Для каких операций? |
Страница 1 из 3 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |