FreeBasic
Главная
Вход
Регистрация
Четверг, 28.03.2024, 14:04Приветствую Вас Гость | RSS
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 2
  • 1
  • 2
  • »
Форум » Freebasic » Вопросы по языку FreeBasic » Синтаксис и конструкции языка FreeBasic (Различные вопросы)
Синтаксис и конструкции языка FreeBasic
ТесторДата: Среда, 04.04.2018, 17:06 | Сообщение # 1
Сержант
Группа: Пользователи
Сообщений: 24
Репутация: 0
Статус: Offline
Понемногу погружаюсь в фреебейсик, возникают вопросы по синтаксису и правильной работе с конструкциями языка.

Первую очередь по работе с классами хочу уточнить.

1. Объявляю и описываю класс с данными, конструктором, деструктором, методами, как правильно создавать и уничтожать объект данного класса?
Когда надо так:

Код
'Создали экземпляр класса
dim ExzemplarClassa as StringList Ptr=new StringList()
'Уничтожили экземпляр класса
ExzemplarClassa->destructor()
Delete ExzemplarClassa


А когда достаточно так:

Код
dim ExzemplarClassa as StringList 'Ptr=new StringList() 'Создали экземпляр класса
ExzemplarClassa.destructor() 'Уничтожили экземпляр класса

Как во втором случае обнулить саму переменную класса?

2. Есть ли возможность прописать предварительное объявление класса и как это сделать? Что бы вышеобъявленный класс мог включать объекты ниже объявленного класса?
 
haavДата: Среда, 04.04.2018, 18:34 | Сообщение # 2
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Цитата Тестор ()
1. Объявляю и описываю класс с данными, конструктором, деструктором, методами, как правильно создавать и уничтожать объект данного класса?Когда надо так:

Код
'Создали экземпляр класса
dim ExzemplarClassa as StringList Ptr=new StringList()
'Уничтожили экземпляр класса
ExzemplarClassa->destructor()
Delete ExzemplarClassa

А когда достаточно так:

Код
dim ExzemplarClassa as StringList 'Ptr=new StringList() 'Создали экземпляр класса
ExzemplarClassa.destructor() 'Уничтожили экземпляр класса

Как во втором случае обнулить саму переменную класса?

Тебе нужно понимать принципы создания переменных , их время жизни в программе.

при объявлении:

Код
dim P as Byte


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

Ответь, не запуская код , сколько будет напечатано в консоли?

Код
for i as integer = 0 to 5

    dim P as Byte

    P+=10

next

Print P


при объявлении:

Код
dim P as Byte ptr = new Byte


или:

Код
dim P as Byte ptr = allocate(1)


переменная будет жить пока не удалить ее вручную с помощью delete

Цитата Тестор ()
2. Есть ли возможность прописать предварительное объявление класса и как это сделать? Что бы вышеобъявленный класс мог включать объекты ниже объявленного класса?

http://users.freebasic-portal.de/freebas....as.html


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
ТесторДата: Среда, 04.04.2018, 18:42 | Сообщение # 3
Сержант
Группа: Пользователи
Сообщений: 24
Репутация: 0
Статус: Offline
Цитата haav ()
Ответь, не запуская код , сколько будет напечатано в консоли?

Переменная объявленная в цикле не существует за его пределами?

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

Код
dim ExzemplarClassa as StringList 'Ptr=new StringList() 'Создали экземпляр класса
ExzemplarClassa.destructor() 'Уничтожили экземпляр класса

Так предлагалась в справочнике, я проверил оно работает... но сомнения остались, всё ли я сделал. Компилятор этим занимается. ну пускай, я только за biggrin


Сообщение отредактировал Тестор - Среда, 04.04.2018, 18:54
 
haavДата: Среда, 04.04.2018, 18:55 | Сообщение # 4
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Цитата Тестор ()
Переменная объявленная в цикле не существует за его пределами?

Правильно понимаешь , но еще правильнее: компилятор не даст такой программе скомпилироваться (выдаст ошибку).

А если строку Print P переместить перед строкой Next , сколько покажет консоль?


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
ТесторДата: Среда, 04.04.2018, 19:30 | Сообщение # 5
Сержант
Группа: Пользователи
Сообщений: 24
Репутация: 0
Статус: Offline
Строка:

Код
dim P as Byte

будет переинициировать переменную на каждом цикле? Ну тогда 6 раз по 10, нет то числа от 10 до 60.
 
haavДата: Среда, 04.04.2018, 19:37 | Сообщение # 6
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Цитата Тестор ()
будет переинициировать переменную на каждом цикле?

Что в твоем понимании слово "переинициировать"? Я не просто так спрашиваю , потому что твой вопрос противоречит ответу:


Цитата
Ну тогда 6 раз по 10, нет то числа от 10 до 60.


Далее:


Цитата
'Уничтожили экземпляр класса
ExzemplarClassa->destructor()


Это что такое? И где ты откопал такой код? Ты понимаешь принцип работы конструкторов\деструкторов? Ты всерьез считаешь , что вызвав деструктор , уничтожается объект класса автоматически?


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
ТесторДата: Среда, 04.04.2018, 21:12 | Сообщение # 7
Сержант
Группа: Пользователи
Сообщений: 24
Репутация: 0
Статус: Offline
Цитата haav ()
Что в твоем понимании слово "переинициировать"? Я не просто так спрашиваю , потому что твой вопрос противоречит ответу:


Я не представляю что там происходит с памятью, но догадываюсь что объявление одной и той же переменной будет присваивать ей значение по умолчанию

Цитата haav ()
Ты понимаешь принцип работы конструкторов\деструкторов? Ты всерьез считаешь , что вызвав деструктор , уничтожается объект класса автоматически?


У меня этот код правда вот так выглядел:

Код
'Уничтожили экземпляр класса
ExzemplarClassa->destructor()
Delete ExzemplarClassa


Где я его откопал... я сейчас заколебусь искать, но это действительно не моё изобретение, накануне вечером перед тем как запостить эту тему я пытался найти описание правил создания и уничтожения объектов во фреебасике... и где то я нашёл упоминание что вызвать делет недостаточно.

Что касается моих представлений о классах, опять таки я не вникал глубоко в механнику их работы, а изучал только как ими пользоваться. Что я знаю о конструкторах/деструкторах, первый вызывается при создании, второй при уничтожении, объект класса не может уничтожить себя, для этого нужен внешний инициатор или в его роли отсроченный вызов (если что за терминологию пардон). Потому я и вопрос запостил, однозначного описания правил создания/уничтожения не нащёл, фундаментального понимания по данному предмету не имел - оно бы было иначе, дак и вопрос задавать не пришлось, так что поясни как надо, буду признателен.

Слушай, уточню вдогонку...  я правильно понял, что если я объявил указатель вот так:

Код
dim zag_ as GtkWidget ptr


Я обязательно должен буду по завершению его использования вызвать:

Код
Delete zag_


Да и ещё, вот это нижнее подчёркивание в конце имени переменной указателя, это правила хорошего тона для объявления указателей? Подсмотрел в твоём примере по ГТК3.

Ещё до одного вопроса дозрел... я не знаю как создать "сигнал", "событие"... когда к классу можно привязать внешний метод и клас его будет вызывать при наступлении некого события, когда например курсор защёл на кнопку, нажатие, ресайз и т. д. Как это реализуется средствами фреебасика?


Сообщение отредактировал Тестор - Среда, 04.04.2018, 21:45
 
haavДата: Среда, 04.04.2018, 22:32 | Сообщение # 8
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Цитата Тестор ()
Я не представляю что там происходит с памятью, но догадываюсь что объявление одной и той же переменной будет присваивать ей значение по умолчанию

Точно! И значение по умолчанию в FB равно нулю. То есть  dim P as Byte  будет обозначать выделение памяти для переменной и присваивание ей нуля. А если ты понимаешь , что ей присваивается значение по умолчанию , то почему тогда ты даешь такой ответ? :


Цитата
Ну тогда 6 раз по 10, нет то числа от 10 до 60.


Как видишь, твой метод экспресс обучения не сильно тебе помогает. И если бы ты банально прочел учебник (пусть он и не идеальный), то на многие бы вещи смотрел бы по другому.

Цитата
Что касается моих представлений о классах, опять таки я не вникал глубоко в
механнику их работы, а изучал только как ими пользоваться. Что я знаю о
конструкторах/деструкторах, первый вызывается при создании, второй при
уничтожении, объект класса не может уничтожить себя, для этого нужен
внешний инициатор или в его роли отсроченный вызов (если что за
терминологию пардон). Потому я и вопрос запостил, однозначного описания
правил создания/уничтожения не нащёл, фундаментального понимания по
данному предмету не имел - оно бы было иначе, дак и вопрос задавать не
пришлось, так что поясни как надо, буду признателен.


Да точно,  конструкторы\деструкторы вызываются , но их не вызывают! Чтобы ты понимал , конструкторы\деструкторы - это такие же функции , но вызываются автоматически. То есть твой код бред, но он мог иметь место в языке до появления ООП (либо вообще в другом языке , где ключевое слово destructor не зарезервировано):


Код
'Уничтожили экземпляр класса
ExzemplarClassa->destructor()
Delete ExzemplarClassa


Чисто технически компилятор , анализируя код , вставляет вызов деструктора (читай функции) прямо перед вызовом  Delete ExzemplarClassa . А уж что ты там напишешь во внутренностях деструктора , на это компилятору чихать (конечно же в рамках правил синтаксиса языка) . Так же обстоит дело с конструктором. Только там компилятор вставляет вызов конструктора сразу после создания объекта.


Цитата
Слушай, уточню вдогонку...  я правильно понял, что если я объявил указатель вот так:

Код
dim zag_ as GtkWidget ptr

Я обязательно должен буду по завершению его использования вызвать:

Код
Delete zag_


Нет. Оператор Delete работает в тандеме с оператором New. Так же как оператор Allocate\Callocate работает в тандеме с Deallocate.  


Цитата
Да и ещё, вот это нижнее подчёркивание в конце имени переменной указателя,
это правила хорошего тона для объявления указателей? Подсмотрел в твоём
примере по ГТК3.

Нет , это плохой тон, однако мне это сэкономило время при переписывании исходника с СИ. Чтобы ты понимал , слово window зарезервировано в FB и его нельзя использовать для имен переменных. Поэтому я по шустрому впендюрил подчеркивание smile


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
ТесторДата: Среда, 04.04.2018, 23:42 | Сообщение # 9
Сержант
Группа: Пользователи
Сообщений: 24
Репутация: 0
Статус: Offline
Цитата haav ()
то почему тогда ты даешь такой ответ? :

Да я действительно не проверял код, и я догадывался, но не был окончательно уверен )))

Цитата haav ()
Как видишь, твой метод экспресс обучения не сильно тебе помогает.


Я не говорил что безупречный, бескомпромиссность это идеализм. Но в учебнике этом я на самом деле регулярно пасусь.

С вот этим то же подскажи пожалуйста:

Цитата
Ещё до одного вопроса дозрел... я не знаю как создать "сигнал",
"событие"... когда к классу можно привязать внешний метод и клас его
будет вызывать при наступлении некого события, когда например курсор
защёл на кнопку, нажатие, ресайз и т. д. Как это реализуется средствами
фреебасика?




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




Сообщение отредактировал Тестор - Среда, 04.04.2018, 23:47
 
DarkDemonДата: Среда, 04.04.2018, 23:52 | Сообщение # 10
Полковник
Группа: Друзья
Сообщений: 188
Репутация: -2
Статус: Offline
Стас, терпения тебе. Грустно.

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

Тестор, коротко: изучить операторы, конструкции и ключевые слова языка (можно начать с QuickBasic),
далее изучить методологию ООП(раз вы хотите кодить, используя её) и только потом приступать к GTK,
причём желательно не к последнему. Без хотя бы одного из этих пунктов - пазл не сложится.
Кстати чем паскаль не устроил? FreePascal - ЯП точно такого же ранга, юниты аппетитно подключаются,
на ассемблере точно так же вставочками писать можно, указатели и ООП там тоже есть. "мене ни панимать"
 
haavДата: Четверг, 05.04.2018, 09:05 | Сообщение # 11
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Цитата Тестор ()
Ещё до одного вопроса дозрел... я не знаю как создать "сигнал","событие"... когда к классу можно привязать внешний метод и клас его
будет вызывать при наступлении некого события, когда например курсор
защёл на кнопку, нажатие, ресайз и т. д. Как это реализуется средствами
фреебасика?

Во первых , я уже писал , что с GTK3 я не работал. Что я могу тебе подсказать?
Во вторых, я не гадалка. Напиши код, покажи что не получается , может кто нибудь подскажет.
В третьих, постарайся задавать вопрос как можно проще, больше вероятности что поймут и ответят. Твой же вопрос выглядит примерно так:


Цитата
Oнo и кoнeчнo, oнo и пoнятнo, oнo и нe чтo-либo кaк, и нe кaк-либo чтo, a чтo кacaтeльнo oтнocитeльнo — тo и дeйcтвитeльнo


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
ТесторДата: Понедельник, 09.04.2018, 21:32 | Сообщение # 12
Сержант
Группа: Пользователи
Сообщений: 24
Репутация: 0
Статус: Offline
Цитата haav ()
В третьих, постарайся задавать вопрос как можно проще, больше вероятности что поймут и ответят.

Это не касалось ГТК, для примера пытался привести..., касалось только конструкций Басика. Хорошо постараюсь выражаться яснее. Кажется я нашёл то что искал, если ошибаюсь попозже переформулирую вопрос.

DarkDemon, нет конечно спасибо за красочные примеры и советы, только... без обид, но тема что мне делать - это точно не тема данного форума, ровно как она не касается тебя. Я так понимаю, мы на форуме посвященном фреебасику, я конечно не демонстрирую глубинных познаний, но и от тематики не отклоняюсь..., информации о том, что есть некий ценз уровня знания языка для доступа на форум я не видел. Я это к тому, что на самом деле рад любому конструктивному общению, в особенности помощи по существу задаваемых вопросов, но субоколотемные ответы пространственного характера, с неособо адекватным эмоциональным окрасом и свербящей наивностью, мягко говоря не к месту. Это флуд на гране тролинга.

Что б не возвращаться к этой теме... тот уровень на котором я изучаю/использую программирование (в том числе бейсик), это не случайность, а осознанный выбор.  Мои методы, мой подход уже не однократно обкатаны и проверены на практике, это принципы соотношение целей к время и трудо затратам, принцип достаточности. Какие ..лядь заказчики? Кто там претендует на валидатора моего кода? Если кто то претендует... это меня как то касается? Я из другой отрасли. Ты говоришь я не понимаю принципов ООП?... ну где то, со своего уровня ты наверное прав... (это что то для меня должно меняет?), я вот считаю, что я понимаю ООП на достаточном уровне, на уровне чёрного ящика, я не знаю, что там под капотом и почему это так, но я знаю, что оно мне даёт и как в общем с ним нужно обращаться... бинго, и вот это цель моих вопросов, я ранее использовал один чёрный ящик (потом ещё второй), теперь заинтересовался ещё одним, ну а у него "кнопочки, рычажки, педальки" оказались немного иначе сконфигурированы... возникли местами неуверенность, местами вопросы.

Пологаеш это такой неприемлемый подход? Но на самом деле, ты ведь каждый день им, вероятно не осознанно, пользуешься. Ты водишь машину? А ты закончил ВУЗ'ы технического, дорожностроительного и юридического профилей? Ты можешь разобрать до болтика и собрать современный автомобиль, знаешь всю историю и предтече от моторизированной коляски дядюшки Бенца до наших дней? Владеешь теохнологиями строительства дорог и объектов дорожной структуры, досконально изучим принципы и подходы конфигурации дорожной структуры? Ты владеешь исчерпывающими знаниями по правовыми аспектам данной сферы? Нет... только автошколу закончил?!!... Ты пользуешься лифтом даже не владея сопроматам? Пользуешься сотовым телефоном? А как же доскональное изучение корпускулярно-волновых явлений? И т. д. до бесконечности. А на самом деле, тебе просто нужно пообщаться с узкопрофильными специалистами, которые с позиции бога тебе обстоятельно "объяснят на 10 листах", что ты просто "задравши нос" лузер по жизни... и они тебя "мене ни панимать".

Добавлено (09.04.2018, 21:32)
---------------------------------------------
Код
type TipeA extends Object
~
End Type

type TipeB extends TipeA
~
End Type

type TipeC extends TipeA
~
End Type

Sub identify(ByVal n As Any Ptr)
     
    dim mn as Object Ptr = Cast(Object Ptr, n)
     
    if *mn is TipeA then
        print "ДА"
    else
        print "НЕТ"
    endif
End Sub

Dim test1 as TipeC

identify(@test1)


Возможно ли в методе "identify" помимо подтверждения о наследовании от корневого родителя установить является ли это "TipeB" или "TipeC" и обратиться к их уникальным полям?


Сообщение отредактировал Тестор - Понедельник, 09.04.2018, 21:47
 
haavДата: Вторник, 10.04.2018, 09:41 | Сообщение # 13
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Цитата Тестор ()
Возможно ли в методе "identify" помимо подтверждения о наследовании от корневого родителя установить является ли это "TipeB" или "TipeC"

Да возможно. Проверять следует от самого младшего ребенка по цепочке к корневому родителю. Если брать пример, который ты привел, то проверка должна быть такой:

сначала проверяется на принадлежность объекта к классу TipeC , потом TipeB , потом TipeA.

Если у тебя будет объект класса  TipeC , а ты сразу будешь проверять его принадлежность например к корневому классу TipeA , то он покажет принадлежность этому классу , что является ошибкой.

Цитата Тестор ()
и обратиться к их уникальным полям?

Здесь есть некоторые "закорючки".

А именно, если поля классов имеют уникальные имена , то доступ к ним не представляет проблем. Например:


Код
type TipeA extends Object

   p1 As Integer = 1 ' имя P1

End Type

type TipeB extends TipeA

   p2 As Integer = 2 ' имя P2

End Type

type TipeC extends TipeB

   p3 As Integer = 3 ' имя P3

End Type

Sub identify(ByVal n As Object Ptr)

   if *n is TipeC Then

      print "Object C"

      ?  Cptr(TipeC Ptr, n)->p1
      
      ?  Cptr(TipeC Ptr, n)->p2
      
      ?  Cptr(TipeC Ptr, n)->p3
      
   elseif *n is TipeB Then   
      
      print "Object B"
      
   elseif *n is TipeA Then     

      print "Object A"

   EndIf

End Sub

Dim test1 as TipeC

identify(@test1)

Sleep


А вот если названия полей будут иметь одинаковые имена... Здесь мне даже пришлось консультироваться у более грамотных ребят с оф. форума. В итоге получить к ним доступ можно только так (обрати внимание на приведение типов к нужному классу для доступа к его полям):


Код
type TipeA extends Object

   p As Integer = 1

End Type

type TipeB extends TipeA

   p As Integer = 2

End Type

type TipeC extends TipeB

   p As Integer = 3

End Type

Sub identify(ByVal n As Object Ptr)

   if *n is TipeC Then

      print "C"

      ?  Cptr(TipeA Ptr, n)->p
      ?  Cptr(TipeB Ptr, n)->p
      ?  Cptr(TipeC Ptr, n)->p

   EndIf

End Sub

Dim test1 as TipeC

identify(@test1)

Sleep


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
ТесторДата: Среда, 11.04.2018, 11:50 | Сообщение # 14
Сержант
Группа: Пользователи
Сообщений: 24
Репутация: 0
Статус: Offline
haav, спасибо, я немного не правильно обращался к полю и получал ошибку.

Всё таки вернусь к вопросу который не смог объяснить. Код привести не могу, иначе бы и вопроса не было.

Как я почитал, по английски это часто называют Event, мне привычнее по русски событие/сигнал. Мне нужно в своём классе создать свой Event/событие/сигнал, для примера:

1. У меня есть КлассА, в котором есть некий счётчик, который в ходе выполнения программы будет непрывно расти.
2. На каждую 1000 этого счётчика КлассА должен вызвать внешний (переданный ему после создания экземпляра) метод заданого типа.

То есть как я понимаю со стороны класса мне нужна переменная которая хранит указатель на метод с определёнными параметрами, нужен метод через который в эту переменную будет передан указатель, и нужна конструкция которая по указателю вызовит внешни метод. Со стороны программы мне нужен сам метод (с заданными параметрами) и способ создать указатель на этот метод.

Не смог разобрать как это сделать в басике, если описанное непонятно могу привести код. но не на басике (если это уместно).
 
WQДата: Среда, 11.04.2018, 16:39 | Сообщение # 15
Полковник
Группа: Проверенные
Сообщений: 215
Репутация: 7
Статус: Offline
Цитата
Цитата Tестор ()
1. У меня есть КлассА, в котором есть некий счётчик, который в ходе выполнения программы будет непрывно расти.


В класс можно отправить указатель на функцию\процедуру
И потом также можно через метод передавать
А вот внутри между методами и конструктором - сложнее (по крайней мере, на моем уровне понимания)
В некоторых библиотеках, например, IUP, есть возможности для упрощения таких действий(конечно, если класс будет использоваться с функциями IUP)

Код
Declare Sub set(n As Integer)

Type type_example
   Declare Constructor (func As Any Ptr)
   Declare Destructor()
   As Integer Y
 Declare Static Function write_ (func As Any Ptr) As Integer
End Type

Destructor type_example()
End Destructor

Constructor type_example(func As Any Ptr)
   Dim Set1 As Sub(n As Integer)

   Set1=Cast(Any Ptr,func)
   set1(200)

End Constructor

Function type_example.write_ (func As Any Ptr) As Integer
   Dim Set1 As Sub(n As Integer)

   Set1=Cast(Any Ptr,func)
   set1(100)
   Return 0
End Function

Dim As type_example Ptr example

example = New type_example(@set)
example->write_(@set)

Sleep
Delete example 

Sub set(n As Integer)
   ? n
End Sub
 
Форум » Freebasic » Вопросы по языку FreeBasic » Синтаксис и конструкции языка FreeBasic (Различные вопросы)
  • Страница 1 из 2
  • 1
  • 2
  • »
Поиск: