forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   JAVA Micro Edition (http://forum.boolean.name/forumdisplay.php?f=52)
-   -   Получение команд в формах (http://forum.boolean.name/showthread.php?t=7280)

Phantom 05.11.2008 15:31

Получение команд в формах
 
Впервые решил использовать формы в Java, точнее TextBox. И у меня ни в какую не получается отловить нажатие команд. Смотрите. Я добавляю две команды com1 и com2. Они появляются под софтовыми клавишами. Отлавливаю в commandAction нажатую команду, сохраняю её в переменной. А после ТекстБокса делаю цикл:
while(com==null) Thread.sleep(80);
, где com - это переменная из commandAction. И цикл никогда не прерывается. Я, видимо, как-то жёстко не так делаю.

Romanzes 05.11.2008 16:10

Ответ: Получение команд в формах
 
Не надо ничего сохранять в переменной. Просто в commandAction создаешь такие конструкции:
Цитата:

public void commandAction(Command c, Displayable d)
{
if (c==ExitMidlet)
{
//операторы
}

if (c==Ok)
{
//операторы
}
//и т. д.
}
Где ExitMidlet, Ok - имена твоих команд.

Phantom 05.11.2008 16:45

Ответ: Получение команд в формах
 
Мля. Видел я такой пример. Не катит. Мне не нужно обрабатывать внутри commandAction. Хотя... Есть идея... Но это несколько криво будет...

ViNT 05.11.2008 18:58

Ответ: Получение команд в формах
 
Посмотри, как это в MP реализовано, там же можно обрабатывать комманды за пределами commandAction.

Phantom 05.11.2008 20:04

Ответ: Получение команд в формах
 
Я посмотрел. Там что-то очень странное и невнятное. И как я понял он там только одну команду обрабатывает. А если две? Или более? Ужос.

Phantom 06.11.2008 02:02

Ответ: Получение команд в формах
 
Блин. Как только уже не пробовал. По всем показателям commandAction просто напросто не вызывается вообще! ТекстБокс вызывается, команды вырисовываются (две кнопки "Далее" и "Назад"), но при нажатии на них ничего не происходит. Версия, что мидлет зависает по какой-то причие после нажатия на командную кнопку, не имеет места, так как если убираю цикл ожидания нажатия, то программа выполняется дальше, просто ТекстБокс появляется и мгновенно исчезает. Памагите :'(

Phantom 06.11.2008 02:42

Ответ: Получение команд в формах
 
Что-то мне сдаётся, что не работает setCommandListener. Он вообще для чего? Я просто по аналогии делал, всё вроде понятно, кроме этого метода. Но компилируется нормально.

ViNT 06.11.2008 08:18

Ответ: Получение команд в формах
 
setCommandListener как раз и заставляет систему сделать активным обработчик commandAction указанного объекта.

Phantom 06.11.2008 14:37

Ответ: Получение команд в формах
 
ViNT, вот! Я так и подумал! Видимо проблема в нём. commandAction не вызывается вообще. Может я setCommandListener как-то не так вызываю? Я ему передаю в качестве параметра экземпляр класса implements CommandListener. Блин. Я уже сутки не могу заставить обрабатываться команды.
- - -
Во всех примерах, что я видел, implements CommandListener делают главный класс мидлета. Это имеет значение? У меня отдельный класс для этого использован.

ViNT 06.11.2008 15:58

Ответ: Получение команд в формах
 
Собственно, нужно указывать используемый в данный момент объект - отображаемую форму, Canvas и т.д.

Phantom 06.11.2008 16:07

Ответ: Получение команд в формах
 
Не, я имею ввиду в скобочках круглых.
Я пишу так:
PHP код:

tb.setCommandListener(f); 

, где:
tb - это ТекстБокс
f - это я не знаю как назвать правильно. Короче класс имеет вид:
PHP код:

public class functions implements CommandListener
 public static 
functions f// вот она переменная f
. . .
 { 

Что же не так?

Piligrim 06.11.2008 16:12

Ответ: Получение команд в формах
 
Код:

TextBox tx = new TextBox("", "", 10, 0);
tx.setCommandListener(объект класса, который implements CommandListener);

ну и в том классе
Код:

public void commandAction(Coomand c, Displayable d){
if(d==tx){....}


Phantom 06.11.2008 16:15

Ответ: Получение команд в формах
 
Так. Напишу-ка я собственно всё:
PHP код:

import javax.microedition.lcdui.*;

 public class 
functions implements CommandListener{
// ***********************************
 
public static functions f;
 public static 
Command com1;
 public static 
Command com2;
 public static 
Display d;
 public static 
Displayable cd;
 public static 
int com;
// ***********************************
 
public void commandAction(Command c,Displayable d){
   if(
c==com1com=1;
   else if(
c==com2com=2;
   else 
com=3;
   
a.a.destroyApp(true); // Это временно воткнул, чтобы узнать, когда же наконец этот метод вызовется!
 
}
// ***********************************
 
public static String textbox(String title,int size,int othrows Exception{
   
String s=null;
   
com=0;
   
TextBox tb=new TextBox(title,"",size,o);
   
d.setCurrent(tb);
   
com1=new Command("Ok",Command.OK,1);
   
com2=new Command("Назад",Command.BACK,2);
   
tb.addCommand(com1);
   
tb.addCommand(com2);
   
tb.setCommandListener(f);
   
c.repaint();
   
c.serviceRepaints();
   while(
com==0Thread.sleep(80);
   if(
com==1s=tb.getString();
   
d.setCurrent(c);
   return 
s;
 }
// ***********************************


По моей логике работать это должно так:
Из класса, в котором выполняется основная часть программы будет вызываться метод functions.textbox(), который должен вывести на экран ТекстБокс, ожидать пока пользователь введёт в него что-нибудь, потом нажмёт одну из двух командных клавиш: "Ok" и "Назад". При нажатии "Ok" метод должен возвратить текст, набранный в ТекстБоксе, при нажатии "Назад" метод должен возвратить null. Кроме того ТекстБокс должен переключиться обратно в канвас. Вот. Возможно криво объяснил, так как терминалогия Java у меня до сих пор подхрамывает.

Phantom 06.11.2008 18:48

Ответ: Получение команд в формах
 
Сделал implements CommandListener главный класс мидлета и всё заработало... Идиотизм какой-то... Где связь?

Piligrim 06.11.2008 20:17

Ответ: Получение команд в формах
 
Код:

  c.repaint();
  c.serviceRepaints();
  while(com==0) Thread.sleep(80);
  if(com==1) s=tb.getString();

вот это прошу прощения, полный идиотизм с точки зрения программирования. Java - объектный язык и обработка событий нормальный способ взаимодействия.
скажите зачем системе в цикле проверять com==1? если при нажатии "ОК" мы просто начнем выполнять код?
Не идите на поводу методики МР, она во многом ущербна из-за желания автора упростить язык.

Код:

public class Main extends MIDlet implements CommandListener{
   
    public static Display display;
    public static TextBox tb;
    public Command cmdOK = new Command("OK", Command.OK, 0);
    public Command cmdBack = new Command("Назад", Command.BACK, 0);
   
    public void startApp() {
        display = Display.getDisplay(this);
        display.setCurrent(tb = new TextBox("Введите", null, 50, TextField.ANY));
        tb.addCommand(cmdOK);
        tb.addCommand(cmdBack);
        tb.setCommandListener(this);
    }

    public void commandAction(Command c, Displayable d) {
        if(d==tb && c == cmdOK)
            display.setCurrent(new Form("Вы ввели", new Item[] {new StringItem("Введено", tb.getString())}));
    }

примерно так.

Phantom 06.11.2008 21:19

Ответ: Получение команд в формах
 
Ну это я там уже лишнего наворотил в попытках заставить всё это работать. Проблемы так таковые две:
1) У меня commandAction вообще не вызывался, пока я не перенёс его в главный класс мидлета. Вот где тут связь - вообще не представляю.
2) А обрабатывать нажатие клавиш мне надо в основном цикле программы, а не в отдельном методе, поэтому я и получаю нажатые команды в переменную, а после их сравниваю. По мне, так в данном случае это оптимальный вариант.

Piligrim 07.11.2008 13:08

Ответ: Получение команд в формах
 
1. Такое чувство, что просто переменную забыли проинициализировать, вот и не вызывается.
2. В яве нет понятия основной цикл программы, как и в Дельфи. Это событийная среда. Ну да дело ваше.

Phantom 07.11.2008 15:04

Ответ: Получение команд в формах
 
Ну вот не могу я въехать в ООП... :'(

ViNT 07.11.2008 17:51

Ответ: Получение команд в формах
 
Цитата:

Сообщение от Phantom_wc (Сообщение 90220)
Ну вот не могу я въехать в ООП... :'(

Если, например, в Pascal можно и без ООП обойтись, то в java без него никак - это основа.

Phantom 07.11.2008 18:37

Ответ: Получение команд в формах
 
Ладно, буду исправляться. =)
- - -
Только вот понять не могу. Ну вот есть классы в программе. Каждый класс представляет свой тип данных, которым можно крутить вертеть при помощи методов, объявленных внутри. Но ведь по-любому сама программа не может выполняться путём цепочки методов, где первый метод вызывает второй, тот вызывает третий и так далее. Должна быть основная часть программы, которая всем этим рулить будет. В интернете сколько читал про ООП, ничего про это не видел. Везде только и пишут, что в ООП классы надо представлять как ящики, о внутренностях которых ничего не известно, но из него торчат проводки (методы), которыми он может взаимодействовать с другими ящиками. То есть получается, что у меня есть куча ящиков, но нет распределительного пульта управления. По мне так это то же самое, если бы я в процедурном языке написал кучу функций, но не имел возможности написать основную часть программы, которая будет вызывать эти функции.
- - -
Растолкуйте плиз.

Phantom 10.11.2008 04:12

Ответ: Получение команд в формах
 
А ещё такй вопрос. А если создать в программе два класса implements CommandListener, то что будет? Они оба будут на команды одновременно реагировать? Или вообще не скомпилируется такая программа?

Phantom 10.11.2008 05:04

Ответ: Получение команд в формах
 
Цитата:

2. В яве нет понятия основной цикл программы, как и в Дельфи. Это событийная среда. Ну да дело ваше.
У меня в потоке (как в МП) всё выполняется, там есть цикл условно бесконечный. В нём всякие меню, вывод текста и т. п. Суть программы грубо говоря просто показывать текст и менюшки. Менюшки вложены друг в друга, всё полностью в канвасе обрабатывается. Но кроме того мне надо сделать ввод текста. Было решено сделать как в опере мини. То есть всё реализовано в канвасе, только текст вводится в ТекстБоксе. И всего две команды: "Назад" и "Далее". И команды эти нужно обрабатывать только в ТекстБоксе, в канвасе команды не используются вообще. Я вывел в отдельный метод в отдельном классе код, который переключает в режим отображения ТекстБокса, ожидает набирания текста и нажатия одной из двух команд. После этого происходит переключение обратно в режим канваса и метод возвращает либо null (если была нажата команда "Назад"), либо строку, которую пользователь ввёл в ТекстБокс (если была нажата команда "Далее"). А из того, основного цикла программы я просто потом в нужном месте вызываю этот метод для вывода на экран ТекстБокса, ожидания ввода текста и нажатия команды. А затем обыкновенным условием проверяю, что вернул метод. Если null, значит пользователь нажал "Назад", если не null, значит пользователь нажал "Далее" и вернулась строка. И я не представляю, как мне это передедать так, чтобы в commandAction происходила полная обработка команд. Ведь мне не надо, чтобы в зависимости от того, какая команда была нажата, вызывался тот или иной метод. Веь мне нельзя прервать основной цикл программы. Ну а как тут без цикла - я вообще не представляю даже. Даже если я каждую менюшку вынесу в отдельный метод, то как заставить commandAction вызывать именно ту, которая мне нужна? Писать по две команды ещё и на каждую менюшку? А если менюшек много, придётся воодить много переменных. А если я захочу ещё несколько менюшек добавить? Мне потом ещё придётся добавлять эти переменные в тот класс, который implements CommandListener. Короче, мне кажется, что я всё сделал оптимально. Теперь я могу менять всё собственно в основном цикле программы, и не вспоминать о том, как там у меня работает вывод текстбокса или текста, или менюшек. Просто вызываю нужный метод и всё отрисовывается, выводится и т. п. Разве не это одно из основных правил ООП? У меня есть класс, который универсально работает, мне не нужно каждый раз в нём что-то править, если я захотел ввести мелкие изменения в основном цикле программы. Во как.

Piligrim 10.11.2008 13:28

Ответ: Получение команд в формах
 
CommandListener может быть сколько угодно, активным, т.е. тем которому передаются команды, считается тот, который установлен с помощью setCommandListener объекта на экране.

Зачем нужен условнобесконечный цикл если система всё делает сама. Зачем ждать в нём результата ввода в TextBox если мы в обязательно попадём в commandAction? Обрабатываем в нём рекцию и всё! Система сама будет ждать следующую команду или просто клавишу если это Canvas.
Программа завершится только если вызвать
destroyApp(true);
notifyDestroyed();

Напишу пример, чуть позже.

Phantom 10.11.2008 21:49

Ответ: Получение команд в формах
 
Цитата:

Программа завершится только если вызвать
destroyApp(true);
notifyDestroyed();
О я е*у... $#&* Чё правда что ли? Во офигеть... Не, я честно в шоке. Я ЭТОГО НЕ ЗНАЛ! Уахууууууууу!!! Я кажется теперь всё догнал. Во ппц... У меня мозг сломан... Прямо всё в голове перевернулось с ног на голову! Сразу куча идей появилась! Сто пудов: ООП - это круто!
pilgrim, + 1000000!!!

Phantom 11.11.2008 07:32

Ответ: Получение команд в формах
 
Так, а это, какие ещё события есть в J2me? Нажатие/отпускание клавиш в канвасе, нажатие команд в формах, startApp, pauseApp, destroyApp... Что ещё такое полезное есть?

Phantom 11.11.2008 08:27

Ответ: Получение команд в формах
 
Ещё вот что интересное заметил. Ведь если в классе есть метод, который называется также, как и сам класс, то он автоматически вызывается при инициализации (ну или как правильно сказать) класса? Я вот сколько смотрел примеров создания простого приложения про это ничего сказано не было. Везде пишут, что первым вызывается startApp(). А вот фиг. Я проверил экспериментально. Если в классе есть метод с таким же названием, как и сам класс, то при запуске мидлета сначала вызывается он, а потом уже startApp(). У меня такой вопрос: этот метод будет вызываться только при первом запуске приложения или всегда перед startApp()? Если только при первом запуске приложения, то почему нигде не написано, что туда можно вынести код инициализации приложения? Почему пишут, что его надо в startApp() засовывать с проверкой не инициилизирован ли до сей поры ещё мидлет? Хотя с другой стороны, если, например главный класс имеет название a.class, и я в другом классе сделаю экземпляр (или это назвается объект-наследник?) этого класса:
PHP код:

public static a a;
. . .
= new a(); 

, а у меня в классе a.class есть метод "a" и в нём код инициализации приложения, например:
PHP код:

display=Display.getDisplay(this);
// тут другой всякий код, например, определение переменных, присваивание им значений 

, то произойдёт повторная инициализация и мидлет зависнет, запустится заново, вылетит (нужное подчеркнуть). То есть в принципе код инициализации можно засунуть в метод "a", но только при условии, что я не буду создавать в других классах объект с типом "a"? Я правильно рассуждаю? Хочу разобраться во всех мелочах.

ViNT 11.11.2008 13:19

Ответ: Получение команд в формах
 
Цитата:

Сообщение от Phantom_wc (Сообщение 90434)
Если только при первом запуске приложения, то почему нигде не написано, что туда можно вынести код инициализации приложения?

Такой метод называется конструктором класса, и служит как раз для инициализации класса. А вызывается он только при создании экземпляра класса.
Допустим есть класс
PHP код:

public class MyClass{

public 
void MyClass(int count){}//это конструктор класса



Тогда можно написать

PHP код:

public MyClass MC;

MC=new MyClass(10); 

При этом будет вызван конструктор класса с параметром 10.

Phantom 11.11.2008 23:13

Ответ: Получение команд в формах
 
Ну я это и имел ввиду! Но почему же везде пишут, что код инициализации главного класса надо в startApp() засовывать? Примерно так:
PHP код:

import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;

public class 
extends MIDlet{
// ***********************************
 
private Display d;
// ***********************************
 
public void startApp(){
   if(
d==nulld=Display.getDisplay(this);
 }
// ***********************************
 
public void pauseApp(){ }
// ***********************************
 
public void destroyApp(boolean u){
   
notifyDestroyed();
 }
// ***********************************


То есть d=null только при первом запуске мидлета. Можно, получается, проще. Без условия, просто вынести этот код в a(){ }...

Phantom 13.11.2008 04:52

Ответ: Получение команд в формах
 
Ещё вот не понимаю логики. В мидлет паскалевских классах.
1) Зачем создаётся объект Image размером в экран телефона?
2) Почему потом через этот Image получается Graphics при помощи getGraphics()?
3) Почему метод paint() в классе, который extends Canvas, отрисовывает этот Image на дисплей?
4) И при каких условиях вызывается paint?

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

Поправте, плиз, если я что-то не так говорю =)

То есть я могу даже создать несколько таких картинок, создать для каждой свой Graphics и в каждый по очереди нарисовать что-то? А как потом подсунуть нужный Graphics в paint? Или нельзя держать одновременно несколько Graphics'ов в памяти?

Блин, если всё, что я написал выше, не полная чушь, то я кажется начинаю глобально вникать в тему! =)

Phantom 13.11.2008 05:16

Ответ: Получение команд в формах
 
Я ради теста создал два имэджа размером с экран мобилы, создал два графикса, отрисовал в каждый разные картинки. Вызываю repaint после отрисовки первого и после второго. Второй не отрисовывается, только первый. В paint в качестве параметра передаётся какой-то Графикс. Как система решает какой из них передать?
- - -
Чуть позже:
Ой блин, жёстко ступил. Я в обоих случаях в paint отрисовывал первый Image =) А какой там Графикс - это по ходу вообще не важно, paint ведь сразу на экран телефона рисует, верно? То есть это, как я понимаю, Графикс самого экрана видимо.
Верно?

Phantom 13.11.2008 05:18

Ответ: Получение команд в формах
 
Админы, сорри, я тут не по теме наоффтопил :@ , можно это перенести в отдельную тему, например, в раздел FAQ. Может кому-то пригодится. Зайдёт кто-нибудь, кто нифига не понимает в Java, почитает и может чего-то новое узнает =)

Phantom 13.11.2008 05:46

Ответ: Получение команд в формах
 
Ещё такой вопрос. Как мне вызвать destroyApp() из какого-нибудь класса, если я не знаю заранее имя главного класса мидлета? Можно сделать метод, который нужно будет вызывать из главного класса примерно так:
PHP код:

coolclass.setMIDlet(this); 

Но опять же проблема, а какой тип данных у главного класса? Такой код не катит:
PHP код:

import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
public class 
coolclass extends Canvas{
 public static 
MIDlet midlet;
 public 
void setMIDlet(MIDlet m){
   
midlet=m;
 }
...
...
...


Оно компилируется, но не работает.

Phantom 13.11.2008 08:15

Ответ: Получение команд в формах
 
Ух я дорвался. Вот ещё что непонятно.
Почему такая запись работает:
PHP код:

String s="Строка"

И такая работает:
PHP код:

String s=new String("Строка"); 

, а если я по аналогии хочу сделать свой класс, который тоже строку получает при инициализации, то почему первый вид записи не работает? Чем String лучше моего класса?

jimon 13.11.2008 08:53

Ответ: Получение команд в формах
 
возможно у строки определен оператор (или конструктор) преобразования в строку из указателя на строку (это второй вариант)

Phantom 13.11.2008 13:53

Ответ: Получение команд в формах
 
Ээээ... А по-ламерски можно, а то я не понял? =)

jimon 13.11.2008 14:45

Ответ: Получение команд в формах
 
читай что такое указатель

Phantom 13.11.2008 15:09

Ответ: Получение команд в формах
 
Ну я читал как-то давно, когда пытался учить С++. Указатель - это типа переменная, которая содержит в себе адрес другой переменной. Его можно использовать вместо самой переменной. (правда я тогда так и не понял нафига он нужен). А что, в Джаве тоже указатели есть?
Это слишком что-то заумное:
"возможно у строки определен оператор (или конструктор) преобразования в строку из указателя на строку (это второй вариант)"

Piligrim 13.11.2008 22:16

Ответ: Получение команд в формах
 
public static coolclass midlet;
так будет правильней.
и лучше в startApp
midlet=this;
тогда из любого класса
coolclass.midlet.destryApp(true);

Piligrim 13.11.2008 22:22

Ответ: Получение команд в формах
 
Image создается, чтобы в МР в любом месте работал drawText и т.д. Graphics экрана известен только в paint, а он из МР недоступен. Отрисовка возможна только на Graphics а чей он, экрана или Image системе всё равно.
paint вызывается после setCurrent, при любых изменениях размера ( например setFullScreen), принудительно после repaint, после возвращения мидлета из паузы. Примерно так.

Phantom 14.11.2008 02:24

Ответ: Получение команд в формах
 
Цитата:

public static coolclass midlet;
так будет правильней.
и лучше в startApp
midlet=this;
тогда из любого класса
coolclass.midlet.destryApp(true);
Не, так не подходит. Про это я знал. Ладно, это пофиг, просто никак не могу отбросить мечту делать всё максимум универсальным. =)
Цитата:

Image создается, чтобы в МР в любом месте работал drawText и т.д. Graphics экрана известен только в paint, а он из МР недоступен. Отрисовка возможна только на Graphics а чей он, экрана или Image системе всё равно.
paint вызывается после setCurrent, при любых изменениях размера ( например setFullScreen), принудительно после repaint, после возвращения мидлета из паузы. Примерно так.
Я это и имел ввиду. :-) Я полночи экспериментировал, столько новых мелочей узнал =)

Phantom 14.11.2008 05:50

Ответ: Получение команд в формах
 
Круто. Я просто рад до ж#%ы!!! Всё так легко стало получаться. Ща переделываю предыдущий проект =) Выкинул целую кучу ненужной фигни!!! Вместо условно бесконечного цикла перенёс всё в keyPressed(), теперь перерисовка экрана происходит только при нажатии на кнопку, а не постоянно =))) Мне только и нужно, чтобы экран перерисовывался только при каком-то действии пользователя, там в основном менюшки. Вот только сейчас даже не знаю как лучше сделать иерархию меню. Ну да ладно, что-нибудь придумаю! Всем огромное спасибо!!!

Piligrim 14.11.2008 13:59

Ответ: Получение команд в формах
 
Цитата:

Не, так не подходит. Про это я знал. Ладно, это пофиг, просто никак не могу отбросить мечту делать всё максимум универсальным. =)
а кто мешает основной класс делать во всех программах с именем, например Main? Это конечно не так круто какк coolclass, но зато универсально.
тогда Main.instance.destroyApp() будет работать всегда :)

Phantom 14.11.2008 15:27

Ответ: Получение команд в формах
 
Не, никто не мешает =) Так и делаю. Только у меня главный класс всегда называется a.class, а класс, который наследник канваса (ну или как там оно правильно говорится) - b.class. =)

ViNT 14.11.2008 15:39

Ответ: Получение команд в формах
 
Цитата:

Сообщение от Phantom_wc (Сообщение 90687)
Не, никто не мешает =) Так и делаю. Только у меня главный класс всегда называется a.class, а класс, который наследник канваса (ну или как там оно правильно говорится) - b.class. =)

Зачем такие корявые имена использовать? А если будет десять классов? Пол алфавита перебирать?

Phantom 14.11.2008 15:59

Ответ: Получение команд в формах
 
ViNT, нуу... :@ Фиг его знает... Краткость - сестра таланта. Меня вообще некоторые ходячим обфускатором называют, потому что логику в названиях моих переменных только я вижу :-D Привык всё делать так, уж не знаю почему. :dontknow: Да и тем более я так и не понял, как пользоваться Proguard'ом, уже и Хэлп перелистал и как только не пробовал, всё время пишет, что не может найти Мэйн класс. Так что пусть хотя бы так запутано будет :-D


Часовой пояс GMT +4, время: 02:30.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Перевод: zCarot