|
Основной форум Сюда все проблемы связанные с программированием. |
20.06.2009, 04:37
|
#166
|
Нуждающийся
Регистрация: 10.02.2007
Сообщений: 99
Написано 18 полезных сообщений (для 28 пользователей)
|
Re: создание MIDletPascal compiler'a
пример редактора на Tmemo со структурой
|
Ээээ а по подробнее, это что за зверь?
ЗЫ...
Мля... и поставте наконец Turbo Delphi или FreePascal нафик, иначе в будущем не разгребешь...
|
(Offline)
|
|
22.06.2009, 23:02
|
#167
|
Нуждающийся
Регистрация: 03.01.2009
Сообщений: 93
Написано 8 полезных сообщений (для 15 пользователей)
|
Ответ: создание MIDletPascal compiler'a
2abcdef - по компилятору....
начни всётаки с компилятора JavaAsmbler to Class
ведь по идее - какойбы небыл язык в ИДЕ, он оттранслируется в жаваасм
а также в Проекте появится возможность :
- имеем jar проги - нажали кнопочку - бац... произошло дизасемблирование...(несколькоуровневое) -
из Class - появится JavAsm - который по возможности, преобразуется в MPascal - со вставками недиз. в кодах Asm.... EndAsm
===
2satan - имеется в виду пример(исходник редактора) основанный на стандартных компонентах delphi из TMemo или TRichEdit - с гуттером (полоска с номерами строк и [+] [-] развёрток структур
---
а скоко весит TDelphi ? где можно скачать? (я оттого спрашиваю - потому что, юзаю инет, через жопорез... а там многого нескачать... :-(
|
(Offline)
|
|
23.06.2009, 01:40
|
#168
|
Нуждающийся
Регистрация: 03.01.2009
Сообщений: 93
Написано 8 полезных сообщений (для 15 пользователей)
|
Ответ: создание MIDletPascal compiler'a
чтобы например AsemblerJavaByte (AJ понимал и делалл Class из такого файла...
; в заголовке указываем имя основного класса (например, Hello)
; Объявляем класс Hello наследуемый от MIDlet
.class public Hello
.super javax/microedition/midlet/MIDlet
; объявляем поля:
; Display display - менеджер дисплея
.field display Ljavax/microedition/lcdui/Display;
; Form form - форма отображаемая на экране
.field form Ljavax/microedition/lcdui/Form;
; конструктор класса
.method public <init>()V
.limit stack 1
.limit locals 1
aload_0
invokespecial javax/microedition/midlet/MIDlet/<init>()V
return
.end method
; точка входа в программу - метод startApp
.method public startApp()V
.limit stack 4
.limit locals 1
; display = Display.getDisplay(this) - получаем ссылку на менеджер дисплея
aload_0
aload_0
invokestatic javax/microedition/lcdui/Display/getDisplay(Ljavax/microedition/midlet/MIDlet;)Ljavax/microedition/lcdui/Display;
putfield Hello/display Ljavax/microedition/lcdui/Display;
; form = new Form("Hello") - создаем новую форму
aload_0
new javax/microedition/lcdui/Form
dup
ldc "Hello"
invokespecial javax/microedition/lcdui/Form/<init>(Ljava/lang/String;)V
putfield Hello/form Ljavax/microedition/lcdui/Form;
; form.append("Hello, World!") - добавляем в форму текст "Hello, World!"
aload_0
getfield Hello/form Ljavax/microedition/lcdui/Form;
ldc "Hello, World!"
invokevirtual javax/microedition/lcdui/Form/append(Ljava/lang/String;)I
pop
; display.setCurrent(form) - выводим форму на экран
aload_0
getfield Hello/display Ljavax/microedition/lcdui/Display;
aload_0
getfield Hello/form Ljavax/microedition/lcdui/Form;
invokevirtual javax/microedition/lcdui/Display/setCurrent(Ljavax/microedition/lcdui/Displayable;)V
; возвращаемся из метода
return
.end method
; метод pauseApp
.method public pauseApp()V
.limit stack 0
.limit locals 1
return
.end method
; метод destroyApp
.method public destroyApp(Z)V
.limit stack 0
.limit locals 2
return
.end method
|
(Offline)
|
|
23.06.2009, 04:12
|
#169
|
Нуждающийся
Регистрация: 10.02.2007
Сообщений: 99
Написано 18 полезных сообщений (для 28 пользователей)
|
Re: создание MIDletPascal compiler'a
Я выше закидывал пример, но вот ссылка на компонент
http://www.silicontaiga.ru/home.asp?artId=5131
А TDelphi - около 30 метров (Китайский урез, называется Delphi 10 lite)... Но она из простой делфи, у меня к ней
пристройка есть что бы все было чин-чинарем - типа Turbo...
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
23.06.2009, 20:15
|
#170
|
Нуждающийся
Регистрация: 03.01.2009
Сообщений: 93
Написано 8 полезных сообщений (для 15 пользователей)
|
Ответ: создание MIDletPascal compiler'a
2Satan - спасибо за ссылку... поковыряю оттуда реализацию гуттера...
(щас проблемка в алгоритме свёртывания блоков текста)
---
а вообщето только от реализации Ассемблера/дизасемблера class файлов(в отдельных от IDE модулях(ехе)) - зависит какой язык(синтаксис) получится...
ведь если асм есть - то можно будет сделать "легко" и мидлетбейсик и паскаль и си и вообще свой скриптоязык... ведь там будет просто транслятор Язык--> в Аsм -
---
2abcdef - кажется ты уже сделал именно ассемблерный компилятор(asm-->class)?
будь ласка, опиши спецификацию реализованного, я тогда к Иде прикручу транслятор и будем пробовать уже чтото писать...
|
(Offline)
|
|
23.06.2009, 23:10
|
#171
|
Нуждающийся
Регистрация: 03.01.2009
Сообщений: 93
Написано 8 полезных сообщений (для 15 пользователей)
|
Ответ: создание MIDletPascal compiler'a
---
да и ассемблер должен быть более "дружественным"...
например в текущем асме числа загружаются в стек такими командами
числа от -1 до 5: iconst_m1, iconst_0, iconst_1, iconst_2, iconst_3, iconst_4, iconst_5.
Числа от 6 до 127: bipush 6, bipush 44, bipush 127.
Числа от 128 до 32767: sipush 128, sipush 255, sipush 1000, sipush 4096, sipush 32767.
Числа от 32768 до (2^31)-1: ldc 32768, ldc 16777215, ldc 1000000000.
Числа от 2^31 до (2^63)-1: ldc2 1000000000000
---
так пускай асм возмёт на себя проверки диапазонов и вставку нужного байт кода - а юзер пусть пишет типа iPush 25235(любые числа) или dPush 3.14592
|
(Offline)
|
|
24.06.2009, 03:39
|
#172
|
Нуждающийся
Регистрация: 10.02.2007
Сообщений: 99
Написано 18 полезных сообщений (для 28 пользователей)
|
Re: создание MIDletPascal compiler'a
Да хренотенью вы страдаете
abcdef уже давно выложил структуры class файла, их заполнить парсером три секунды, тут их штуки три или четыре...
Я говорю наверно раз в 10, что весь гиморой начнётся с качественным парсингом математических выражений, тоесть самый начальный нижний уровень, а ассемблер java писать, тока руки марать, вот пример асма java на коленях (типа теория)
type operator = (op1,op2,op3.........op50,op51);
var NameOp = ('iconst_0', 'iconst_1', 'iconst_2'......'ldc')
.... -> типа сканер уже написан
ReadToken // Читаем слово If Token=op1 then addCodeList(ord(Token)); // Добавляем код в листинг кода сразу опкод по позиции case Token of op1..op9: f=1;// Сдесь по диапазону задаем флаг кол-ва операндов для опкода op10..op30: f=2; op31..op50: f=3; end; i:=0; repeat readToken; // читаем операнд case Token of _int:; // проверяем токен на корректность _float:; _string:; .... else error; // Ошибка если не корректный end inc(i); if i>f then error;// ошибка если кол-во операндов больше ReadToken; // читаем след. слово(по идее ',') until Token=','; // Крутим код пока токен - ','
Типа все... Строку разобрали и запихнули в листинг...
Я не пойму что тут сложного?
|
(Offline)
|
|
24.06.2009, 04:36
|
#173
|
Нуждающийся
Регистрация: 03.01.2009
Сообщений: 93
Написано 8 полезных сообщений (для 15 пользователей)
|
Ответ: создание MIDletPascal compiler'a
>>>что весь гиморой начнётся с качественным парсингом математических выражений,
---
приведи примеры таких выражений... я гдето видел на дельфях парсер(ехпрессион) математических выражений... я поковыряю его насчёт алгоритмов...
я просто в примерах и библиотеках MidletPascala невстречал очень уж сложных выражений... так, в одной строке (+-)*/ 3-4-5 операндов....
|
(Offline)
|
|
24.06.2009, 06:44
|
#174
|
Нуждающийся
Регистрация: 10.02.2007
Сообщений: 99
Написано 18 полезных сообщений (для 28 пользователей)
|
Re: создание MIDletPascal compiler'a
Ну например
x:=((12+(y/z-33.456)+d[a+b-c]*56) mod 5 = 44.5);
К стати когда пишешь типовые компиляторы потом глубоко осознаешь почему вот этот код
for i:=0 to 100 do writeln(chr(i));
коренным образом отличается от
S:=''
for i:=0 to 100 do S:=S+chr(i)+#13#10;
WriteLn(S);
Последний раз редактировалось satan, 24.06.2009 в 07:03.
|
(Offline)
|
|
24.06.2009, 12:25
|
#175
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Ответ: создание MIDletPascal compiler'a
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
25.06.2009, 03:02
|
#176
|
Нуждающийся
Регистрация: 03.01.2009
Сообщений: 93
Написано 8 полезных сообщений (для 15 пользователей)
|
Ответ: создание MIDletPascal compiler'a
2satan - вот твой оператор - x:=((12+(y/z-33.456)+d[a+b-c]*56) mod 5 = 44.5);
а что ты от него хотел оптимизировать? - покажи результат?.
---
а так ещё в редакторе текста он выдаст Error о несоответсвии типов операндов подкрасив в красный цвет слово mod - оператор остатка Целочисленного деления(для операндов типа Integer...
опятьже - изменив оператор деления на / x:=((12+(y/z-33.456)+d[a+b-c]*56) /5 = 44.5);
получим логическое выражение.. true или false
т.е транслятор схавает такое выражение и передаст ассемблеру на формирование байт кода
[1oe преобразование текста - Язык в Java]
public static int x;
public static int a;
public static int b;
public static int c;
public static int d[];
public static int y;
public static int z;
F.D(y, z) - F.fI(33, 45600);
F.fI(12);
JVM INSTR swap ;
JVM INSTR iadd ;
F.M(d[(a + b) - c - 1], F.fI(56));
JVM INSTR iadd ;
F.fI(5);
F.D();
F.fI(44, 50000);
JVM INSTR icmpeq 147;
goto _L1 _L2
_L1:
break MISSING_BLOCK_LABEL_143;
_L2:
break MISSING_BLOCK_LABEL_147;
x = 0;
break MISSING_BLOCK_LABEL_151;
x = -1;
[2oe преобразование текста будет - Java -> Asm ]
...
типа так будет....
|
(Offline)
|
|
25.06.2009, 09:18
|
#177
|
Нуждающийся
Регистрация: 10.02.2007
Сообщений: 99
Написано 18 полезных сообщений (для 28 пользователей)
|
Re: создание MIDletPascal compiler'a
Вот... наконец то мы подошли к главному...
А теперь, что бы мысль не скакала впереди носа, попробуй ПРОГРАМНО определить ошибку в любом выражении... Так, для прикола набросай функцию (эдакий маленький синтаксический анализатор) на корректность...
Просто кнопочку и Edit в котором будем вводить выражения... а лучше что бы он еще и считал все что ему на данном этапе можно просчитать...
Не надо спешить и формировать как это БУДЕТ выглядеть в компиляторе, тут до этого куча работы... ))
А вот уже после этого компилятор написать, что к подруге сходить...
ЗЫ к стати public static int d[]; может быть совсем не int или сначала будет int а потом real (приведение типа) а z сначала может быть одним, а в самый неподходящий момент(например выше по коду) вдруг оказаться нулём, и компилер упадет от переполнения...
Самое интересное начнется в выражениях такого плана
x:= d[d[a]*a] или d[d[c-a[d[c]]]] если диапазон не верный...
Вобщем тут куча примерчиков, которая очень хорошо понимается когда кодируешь а не когда рассказываешь...
Последний раз редактировалось satan, 25.06.2009 в 09:42.
|
(Offline)
|
|
25.06.2009, 17:07
|
#178
|
Нуждающийся
Регистрация: 03.01.2009
Сообщений: 93
Написано 8 полезных сообщений (для 15 пользователей)
|
Ответ: создание MIDletPascal compiler'a
навскидку...
во первых - чтобы анализировать выражения - нужно знать Типы операндов
- далее разбиваем выражения на "лексемы" -
минимальные выражения ^+-*/ ,(+добавляем Вес к выражению
в виде табл (операнд|тип || Операнд Тип || операция+-* || вес || признак законченности разложения
(щас я не знаю конкретную реализацию асм - куда промежутоные результаты вносить, в стек или промеж переменные - генерируемые транслятором -
---
именно редактор текста(IDE) , совместно с транслятором на АСМ(Java) -
будут подготавливать текст уже для Компилятора
===
например x:=((12+(y/z-33.456)+d[a+b-c]*56) /5 = 44.5);
табличка будет формироваться в несколько интераций
1-
(это относится к компилятору - продолжу попозже...
а вот насчёт анализатора выражений...
...приведу пример из дельфи, выражение которое мы хотим парсировать:
(23.34 + 21.21) * 2.92 - 12.21 * sin (180) * -1
Вот пример синтаксического анализатора выражений, наследника TParser, который может разобрать вышеуказанное выражение. Он использует следующие определения для выражений:
Expr ::= Term + Expr | Term - Expr | Term
Term ::= Factor * Term | Factor / Term | Factor
Factor ::= + Item | - Item | Item
Item ::= ( Expr ) | Fn( Expr ) | Number
Fn ::= Sin | Cos
Number ::= floating point literal number (плавающая точка литерала числа)
Далее идет модуль и форма, показывающие как это можно использовать. Вы должны скопировать текст формы в окно редактора Delphi и сохранить как DFM-файл. Мои расчеты вашего выражения привели к результату 130.086 - это правильно?
Примечание: TParser имеет ошибку в подпрограмме парсирования плавающего числа. Любое сочетание символов с символами '+' или '-' воспринимается как часть плавающего числа, поскольку 1e+3 корректное выражение. Естественно, это должно быть правильным только в совокупности с символом 'e'. Поэтому вы должны убедиться, что перед символами '+' и '-' имеется хотя бы один пробел, как показано в вашем выражении. Вы можете это исправить (если у вас есть исходный код VCL), редактируя функцию TParser.NextToken.
Скопируйте поочередно три приведенных ниже файла и вставьте их в окно редактора Delphi. Самый простой способ - закройте все открытые проекты и создайте новый модуль. Выделите весь текст, сгенерированный Delphi и вставьте текст модуля ExpParse. Сохраните его под именем ExpParse.pas. Затем создайте другой модуль, перенесите в него EvalForm.pas и также сохраните. Снова закройте файл и создайте новый модуль. Вставьте в него EvalForm.dfm и сохраните, выбрав меню "Save as" и отметив в списке тип файла DFM. Затем создайте новый проект, удалите форму, созданную по умолчанию и добавьте файл EvalForm.pas.
-----------------------ExpParse.pas----------------------------
unit ExpParse;
interface
uses Classes ;
{ Набор парсируемых элементов определяется как подмножество выражений Delphi Object Pascal, подобно этому:
Expr ::= Term + Expr | Term - Expr | Term
Term ::= Factor * Term | Factor / Term | Factor
Factor ::= + Item | - Item | Item
Item ::= ( Expr ) | Fn( Expr ) | Number
Fn ::= Sin | Cos | другое...
Number ::= floating point literal number (плавающая точка литерала числа)
}
type
TExpressionParser = class( TParser )
protected
function SkipToken( Value : char ) : boolean ;
function EvalItem : double ; virtual ;
function EvalFactor : double ; virtual ;
function EvalTerm : double ; virtual ;
public
function EvalExpr : double ;
end ;
implementation
uses SysUtils ;
function TExpressionParser.SkipToken( Value : char ) : boolean ;
begin
{ возвращаем истину, если текущий признак Value,
и если так, то получаем следующий признак }
Result := Token = Value ;
if Result then NextToken ;
end ;
function TExpressionParser.EvalItem : double ;
var
Expr : double ;
Fn : integer ;
begin
case Token of
toInteger : Result := TokenInt ;
toFloat : Result := TokenFloat ;
'(' : begin
NextToken ;
Result := EvalExpr ;
CheckToken( ')' ) ;
end ;
toSymbol : begin
if CompareText( TokenString, 'SIN' ) = 0 then Fn := 1 else
if CompareText( TokenString, 'COS' ) = 0 then Fn := 2 else
Raise EParserError.CreateFmt( 'Неизвестный элемент "%s"', [ TokenString ]
) ;
NextToken ;
CheckToken( '(' ) ;
NextToken ;
Expr := EvalExpr ;
CheckToken( ')' ) ;
case Fn of
1 : Result := SIN( Expr ) ;
2 : Result := COS( Expr ) ;
end ;
end ;
else
Raise EParserError.CreateFmt( 'Неожидаемый символ "%s"', [ Token ] ) ;
end ;
NextToken ;
end ;
function TExpressionParser.EvalFactor : double ;
begin
case Token of
'+' : begin
NextToken ;
Result := EvalItem ;
end ;
'-' : begin
NextToken ;
Result := -EvalItem ;
end ;
else Result := EvalItem ;
end ;
end ;
function TExpressionParser.EvalTerm : double ;
var
AToken : char ;
begin
Result := EvalFactor;
if SkipToken( '*' ) then Result := Result * EvalTerm else
if SkipToken( '/' ) then Result := Result / EvalTerm ;
end ;
function TExpressionParser.EvalExpr : double ;
begin
Result := EvalTerm ;
if SkipToken( '+' ) then Result := Result + EvalExpr else
if SkipToken( '-' ) then Result := Result - EvalExpr ;
end ;
end.
--------------------------EvalForm.pas---------------------------
unit EvalForm;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, ExpParse;
type
TForm1 = class(TForm)
Edit1: TEdit;
Label1: TLabel;
Button1: TButton;
Label2: TLabel;
procedure Button1Click(Sender: TObject);
private { Private declarations }
public { Public declarations }
end;
var Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var s : string ;
MemStream : TMemoryStream ;
ExpressionParser : TExpressionParser ;
begin { get the string to evaluate }
s := Edit1.Text ;
{ создаем поток для работы с памятью, содержащий текст -
TParser может разбирать выражения из потока}
MemStream := TMemoryStream.Create ;
try
MemStream.SetSize( Length( s ) ) ;
MemStream.WriteBuffer( s[ 1 ], Length( s ) ) ;
MemStream.Position := 0 ;
{ создаем анализатор выражения, используя поток }
ExpressionParser := TExpressionParser.Create( MemStream ) ;
try
Label2.Caption := Format( 'Результат=%g', [ ExpressionParser.EvalExpr ]) ;
finally
ExpressionParser.Free ;
end ;
finally
MemStream.Free ;
end ;
end;
end.
-------------------------EvalForm.dfm-----------------------------
object Form1: TForm1
Left = 216
Top = 102
Width = 433
Height = 300
Caption = 'Form1'
Font.Color = clWindowText
Font.Height = -13
Font.Name = 'System'
Font.Style = []
PixelsPerInch = 96
TextHeight = 16
object Label1: TLabel
Left = 8
Top = 8
Width = 74
Height = 16
Caption = 'Выражение'
end
object Label2: TLabel
Left = 120
Top = 72
Width = 297
Height = 16
AutoSize = False
Caption = 'Результат='
end
object Edit1: TEdit
Left = 8
Top = 27
Width = 409
Height = 24
TabOrder = 0
Text = '(23.34 + 21.21) * 2.92 - 12.21 * sin (180) * -1'
end
object Button1: TButton
Left = 8
Top = 64
Width = 89
Height = 33
Caption = 'Оценка'
Default = True
TabOrder = 1
OnClick = Button1Click
end
end
|
(Offline)
|
|
25.06.2009, 18:59
|
#179
|
Нуждающийся
Регистрация: 03.01.2009
Сообщений: 93
Написано 8 полезных сообщений (для 15 пользователей)
|
Ответ: создание MIDletPascal compiler'a
PS -
а z сначала может быть одним, а в самый неподходящий момент(например выше по коду) вдруг оказаться нулём, и компилер упадет от переполнения...
----
диапзаон - почему именно компилятор должен упасть - если диапазон неверный? - ведь он просто транслирует комманды введёные пользователем в машинный код...
(тут 2 варианта - 1-добавить в математическую библиотеку
выражения типа
try
{
}
catch(Exception exception) { }
для обработки массивов - да и почему компилятор должен
2 - на стадии ввода текста (при синт анализе выводить при "сложных"
выражениях сообщения о Оптимизации кода - пускай юзер преобразует
код в более лёгкое для понимания выражение
-----------
стати public static int d[]; может быть совсем не int или сначала будет int а потом real (приведение типа)
---
в мобильнике нет реал - это будет в библиотеке.. try { } и туда вставить
---
Самое интересное начнется в выражениях такого плана
x:= d[d[a]*a] или d[d[c-a[d[c]]]] если диапазон не верный...
---
неее - ты приведи пример где Реально требуются такие выражения - что это за изврат???
ну и всё одно транслятор сгенерирует примерно такой код
;x:= d[d[a]*a];
varK1 = d[a]
varK2 = varK1 * a
x = d[varK2]
или
;x:= d[d[c-a[d[c]]]] - надеюсь а[ это отдельный массив?
varK1 = d[с]
varK2 = a[varK1]
varK3 = c - varK2
varK4 = d[varK3]
x := d[varK4]
---
тут конечно можно пооптимизировать насёт повторного использования
переменных сгенерированных компилятором(varKn)...
но это уже поле для дальнейшего "улучшения" реального транслятора...
==========
ЗЫ - под транслятором я понимаю промежуточную програмку(модуль ЕХЕ) - который преобразует введёный пользователем тест на Языке(мПамкаль) - в код понятный Именно компилятору (псевдо ассемблер - или.. если у нас пользуется Мидлет - то типа к JASMin коду)
а уже Компилятор сгенерирует обьектынй код (Class) - для использования в мобиле...
---
а засовавать ВСЁ в одно.. это точно Извращение...
какая мне разница(юзеру) - сколько прогонов будет сделано для получения из Текста - готовый JAr Jad файлы?
3..4... 5 секунд или 10? если я пользую это на своём двухядерном E6600 к примеру...
|
(Offline)
|
|
25.06.2009, 19:39
|
#180
|
Нуждающийся
Регистрация: 03.01.2009
Сообщений: 93
Написано 8 полезных сообщений (для 15 пользователей)
|
Ответ: создание MIDletPascal compiler'a
2Satan - поясни пжлста что ты подразумеваешь под "оптимизациями" с примерами....
----
- неотимизированное Выражения на Языке(паскаль)
- оптимизированное выражение на Языке
- неотимизированный код на псевдо ассемблере
- оптимизированный код на псевдо ассемблере
------
покажи примеры - какой "выйгрышь" даст оптимизация - в чём она будет заключаться....
=====
да... по проекту Нового Мидлет Паскаля... нужно всётаки составить ТЗ на весь комплекс (IDE, компиляторы, трансляторы, дизасемблеры редакторы рисунков, редакторы файлов помощи, сами фалы помощи, доп файлы... хз что ещё добавить... )
а также составить список ToDo
---------------
подробное| кто | исполнение
задание | взялся | zip исходников
---------------------------------------
1
2
3....
|
(Offline)
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 19:42.
|