Спільне використання Delphi і CASE Rational Rose при проектуванні користувальницького інтерфейсу, Інтеграція додатків і даних, Бази даних, статті

Введення


В даний час Delphi є одним з найбільш популярних програмних продуктів для створення інформаційних систем. На його основі створюються як невеликі програми, так і системи масштабу підприємства. Чим же так приваблює Delphi з точки зору розробника? Насамперед, це звичайно чудова середовище візуального програмування, зрозуміла, проста для вивчення і, найчастіше, не вимагає знань професійного розробника (які, як відомо, по крупицях накопичуються протягом багатьох років і десятиліть і коштують неймовірно дорого). У середовищі Delphi можна створювати досить складні програмні системи практично з нуля, написавши мінімум програмного коду. При цьому мова, на якому пишеться програма, знайомий багатьом (принаймні, в нашій країні) Object Pascal, Вивчається в даний час на молодших курсах більшості вітчизняних технічних інститутів.


Однак, не все так просто. Якщо для створення невеликих програмних систем для власних потреб можна обмежиться середовищем візуального програмування, то створення будь-якого більш-менш критичного до якості програмного забезпечення (ПО) Вимагає принципово іншого підходу, як мінімум, використання при розробці моделі життєвого циклу ПО (З усіма наступними звідси вимог до документування процесу).


Принциповим для систем подібного класу є наявність базової архітектури (незмінною протягом усього життєвого циклу розробки і експлуатації системи), основні елементи якої закладаються на ранніх стадіях проектування. Базова архітектура створюється, як правило, з використанням низки моделей, що відображають основні моменти, пов’язані зі структурою системи і її функціями. На жаль, середа Delphi для вирішення подібних завдань не застосовна.


Але давайте повернемося до переваг Delphi. Якщо відкинути середу візуального програмування, то, що ж залишиться? Об’єктна модель. А ось це вже гідність Delphi, Привабливе з точки зору проектувальника системи і саме об’єктна модель (як би це не здалося комусь дивним) у багато визначає успіх середовища візуального програмування. Об’єктна модель Delphi охоплює широке коло завдань, забезпечуючи високорівневі (але при цьому виключно гнучкі, практично без обмежень) кошти організації призначеного для користувача інтерфейсу, управління ресурсами операційної системи, маніпулювання даними БД, підтримки стандартів відкритих систем, підтримку популярних технологій (включаючи CORBA і COM), Багаторівневу архітектуру і, нарешті, Internet/Intranet технології. Базова архітектура може використовувати елементи об’єктної моделі Delphi (Навіщо заново створювати все вище перераховане), доповнивши її необхідними складовими, що відбивають специфіку прикладну конкретної системи.


Ми використовуємо для проектування систем продукт Rational Rose фірми Rational Software Corporation. Rational Rose володіє всіма необхідними характеристиками для створення базової архітектури системи будь-якого масштабу. Маючи достатній досвід програмування в середовищі Delphi, Для нас привабливим є використання Rational Rose і Delphi спільно, в рамках єдиного технологічного процесу.


Метою цієї статті є розгляд спільного використання Rational Rose і Delphi і точне (зрозуміло, з нашої точки зору) зазначення місця кожного продукту в процесі розробки. Для розробників, ми сподіваємося, це дозволить скласти думку про те, наскільки подібна технологія застосовна для їх власних потреб, і заощадити час на вивченні деталей.


Що ми хочемо від Rational Rose і Delphi?



Методологія, якої ми дотримуємося при розробці ПО, Це методологія розробки програмного забезпечення Rational Unified Process фірми Rational Software Corporation. Методологіяс технологічної точки зору включає в себе наступні етапи (зрозуміло, в рамках кожної ітерації): моделювання предметної області, визначення вимог до системи, аналіз і проектування, реалізацію (кодування і автономну налагодження), тестування і впровадження. Нижче наведена таблиця, в якій представлено те, що ми очікуємо отримати за допомогою Rational Rose і Delphi на кожному етапі (див. Табл. 1.).

Табл. 1. Використання Rational Rose і Delphi
на різних етапах розробки ПЗ
































Етап

Що ми очікуємо від Rose

Що ми очікуємо від Delphi


Моделювання предметної
області


Виконується моделювання предметної області, описується предметна
область “як є”


Нічого


Визначення вимог до системи


Визначаються функціональні вимоги до системи, вимоги до інтерфейсу системи.


Створюється прототип інтерфейсу користувача


Аналізу та проектування


Визначаються базові компоненти архітектури, моделюються дані, детально проектуються компоненти системи.


Елементи об’єктної моделі Delphi включаються в базову архітектуру. Забезпечується однозначна відповідність елементів діаграм класів Rose та елементів компонент Delphi.


Реалізація


Реалізуються у вигляді програмних модулів діаграми класів, розробляються діаграми компонентів і діаграми розміщення.


Реалізується програмний код, забезпечується однозначна відповідність проекту в Rose і Delphi. Документування коду в Delphi відбивається в Rose.


Тестування


Моделі залишаються практично незмінними. Розробляються тестові приклади для тестування функцій системи.


Вносяться зміни в програмний код. Зміни в програмному коді відображаються в коді Delphi.


Впровадження


Діаграми розміщення є основою для впровадження ПЗ. На основі моделей може бути отримана актуальна документація системного рівня.


Нічого.


Як можна помітити з таблиці 1, основна взаємодія Rose і Delphi може відбуватися на етапах визначення вимог до системи, аналізу і проектування та реалізації. Основними моделями, що використовуються на цих етапах, є модель функцій системи, модель інтерфейсу, модель даних, модель специфікацій програмних модулів.


Для забезпечення зв’язку між Delphi і Rose використовується проміжне ПО зване кодогенератором. Строго кажучи, завдання цього ПЗ не обмежуються тільки генерацією коду. Перш, ніж перейти до опису конкретного кодогенератора перерахуємо, що, на нашу думку він повинен забезпечувати.


Отже, кодогенератор повинен:



  • мати можливість перетворювати класи Rational Rose в код визначення класів на цільовому мовою, в даному випадку Delphi, При цьому опис, пов’язане з конкретним класом має міститися у відповідне місце програмного коду;
  • для діаграми класів підтримувати стереотипи, пов’язані зі специфічними особливостями мови (наприклад, стереотип unit, interface або property, Відповідно визначаючи, що конкретний пакет – є модуль Delphi або клас – є інтерфейс Delphi, Або атрибут – є властивість для компоненти Delphi);
  • мати описаний, очевидний і однозначний спосіб відображення діаграми класів в код Delphi, При цьому відображення має бути налаштованим;
  • мати можливість імпорту актуальною об’єктної моделі Delphi (Бажано для різних версій бібліотеки VCL);
  • підтримувати генерацію коду для створення компонент Delphi;
  • вміти правильним чином відображати типові види зв’язків між класами (хоча б узагальнення, агрегацію і композицію);
  • вміти відображати в програмний код кардинальність зв’язку;
  • виходячи з діаграми компонент Rose, Створювати проект Delphi, Що містить необхідні програмні модулі (forward engeneering);
  • на основі готового проекту Delphi будувати діаграму компонент Rose, Що містить у вигляді компонент всі модулі проекту Delphi та пов’язані з ними класи, отримані з Delphi в результаті зворотного проектування (reverse engeneering). Діаграми повинні бути компактними і очевидними;
  • забезпечувати автоматичне узгодження моделі Rose і Delphi після внесення змін в код модулів Delphi (round trip engeneering);
  • після внесення змін у модель Rose і повторної генерації коду не знищувати, фрагменти, написані в середовищі Delphi;
  • крім генерації коду мати спосіб відображення такого важливого елемента Delphi, Як форми;
  • на реальних проектах (сотні класів і модулів) працювати з прийнятною продуктивністю.

Кодогенератор Delphi від фірми Ensemble Systems, Inc.


Компанія Ensemble Systems, Inc. в даний час є одним з провідних постачальників додаткових компонент (add ins) для Rational Rose. Ці компоненти підтримують кодогенерацію для широкого спектру популярних систем програмування, у тому числі і для Delphi. Розглянемо роботу кодогенератора Delphi в середовищі Rational Rose.


Після установки компонента Delphi від фірми Ensemble Systems, Inc. В середовищі Rational Rose з’являється новий пункт меню в розділі Tools (Рис. 1).

Рис. 1. Пункти меню кодогенератора Delphi


Кодогенератор носить назву Rose Delphi Link (RDL). Як користуватися RDL ми опишемо в наступному розділі, коли будемо розглядати конкретний приклад. Зараз же ми зосередимо нашу увагу на основних можливостях RDL (Не маючи про них уявлення навряд чи можна використовувати його ефективно).


Перш за все, зауважимо, що код, створюваний RDL не містить реалізацію (Для об’єктної моделі це, як правило, це тіло методу). Коли модель оновлюється з коду Delphi (reverse engeneering або round trip), Модель не підвантажує програмний код, написаний у середовищі Delphi для тіл методів. Зміни в моделі стосуються тільки декларативних елементів: визначень класів, інтерфейсів, типів, записів і т. п. Однак, при повторній генерації коду з Rose, Тіла методів у Delphi також залишаються незмінними, а міняються тільки декларативні елементи. Таким чином “зіпсувати” програмний код при повторній генерації не можна. Для відображення елементів моделі в програмний код RDL використовує Code Generation Properties (CGP) – набір спеціальних таблиць, які зв’язуються з кожним елементом моделей Rational Rose і містять специфічну для Delphi інформацію, що використовується для кодогенераціі. Набір цих таблиць доступний з головного меню (пункт Tools/Options, Закладка Delphi) (Рис. 2).

Рис. 2. Таблиця властивостей CGP для операцій в кодогенераторе Delphi.


Для того, щоб CGP для Delphi було доступно із специфікації необхідно встановити значення поля Default Language = Delphi в закладці Notation пункту меню Tools/Options. Для спрощення роботи в розділі меню Tools/Ensemble Tools з’являється також закладка Delphi Property Editor, Де можна налаштувати властивості вибраного елемента моделі. Зауважимо, що використання CGP є типовим прийомом для всіх кодогенераторов від Ensemble Systems, Inc і для Rational Rose взагалі. При використанні Delphi Property Editor можна, не виконуючи кодогенераціі, переглянути код відповідного елемента моделі (наприклад, класу), що часто буває дуже зручно.


Тепер розглянемо, як відображаються RDL в програмний код конкретні типові прийоми проектування


1. Спадкування від класу і реалізація інтерфейсу


Перетвориться в код:

type SampleClass1 = class (BaseClass, SampleInterface)
{…}
end;

2. Асоціативні зв’язки з ролями і різної кардинальність зв’язку


Перетвориться в код:

type SampleClass3 = class
private
ArrayRole1 : array of SupplierClass2;
ArrayRole2 : array [1..10] of SupplierClass5;
ArrayRole3 : array [SampleRange] of SupplierClass3;
ArrayRole4 : TItems;
end;

Зауважимо, що для представлення ролей з кардинально зв’язку не рівною 1 використовуються масиви (або фіксованої довжини, або динамічні). Константа SampleRange в прикладі повинна бути визначена у властивості Array_Range для ролі ArrayRole. Зверніть увагу, що для Role4 в коді визначений не масив, а тип TItems, який повинен представляти колекцію.


3. Агрегація та композиція



Перетвориться в код:

SampleClass1 = class
Public
A : SampleClass2;
B : SampleClass3;
C : array of SampleClass4;
D : array of SampleClass5;
end;

Зауважимо, що ми не знайшли суттєвої різниці в коді для агрегації і композиції і, взагалі, вийшов код дуже нагадує код для звичайної асоціативного зв’язку з ролями.


4. Стереотипи для типових елементів програмного коду Delphi RDL має декілька стереотипів для подання типових елементів програмного коду Delphi: Покажчиків, масивів, файлів, посилань на клас і т.п. Правда, на наш погляд, ці елементи маловживаних при високорівневе проектування об’єктної моделі. На закінчення короткого опису особливостей RDL зазначимо таке. Важливим елементом проектування є документація в специфікації для відповідного елемента моделі. RDL забезпечує її передачу в програмний код. Так для операцій (методів класу Delphi) Значення поля documentation в специфікації вставляється в код перед визначенням методу. І назад, коментарі у програмному коді Delphi можуть бути перетворені в поля documentation в специфікації елементів моделі Rose.


Що не вміє RDL


Раніше ми визначили, що, на нашу думку, повинен забезпечувати кодогенератор Delphi. В цілому RDL охоплює всі перераховані можливості, за винятком, мабуть, одного: він не дозволяє створювати форми. Ви може уявити собі середовище Delphi без форм? Ми, на жаль, теж. Основна парадигма візуального програмування в середовищі Delphi полягає в завданні значень відповідних властивостей (значень атрибутів класів) і написанні коду обробників подій. І тут, на жаль, RDL нам не помічник. Але, чи дійсно це настільки серйозне обмеження? Тут можуть існувати різні думки.


Один із шляхів такий. Проектується користувальницький інтерфейс в середовищі Delphi (А де це зробити швидше і простіше?) І виконується перетворення програмного коду в моделі Rational Rose. Незважаючи на те, що форми виходять досить громіздкими, їх можна “причесати”, а головне, не відображати в них несуттєві деталі. В Rational Rose проектується, власне, об’єктна модель, модель даних, компонентна модель, тобто архітектурно істотні елементи. У поєднанні з моделлю інтерфейсу користувача системи вони утворюють, ту структуру системи, яка може бути відстежено засобами управління конфігураціями, включається в документацію, легко аналізується на предмет наявності принципових помилок і є основою для функціонального тестування, тобто може бути використана на будь-якому етапі життєвого циклу (ЖЦ) Розробки ПО. RDL при цьому забезпечує повне узгодження моделей та програмного коду протягом всього ЖЦ ПО. Ми намагаємося дотримуватися саме такого підходу.


Приклад спільного використання Delphi Rational Rose і



На жаль, навряд чи можливо в рамках невеликої статті продемонструвати повноцінний приклад реального застосування. Проте це і не потрібно. Повертаючись до того місця статті, де ми описували, що очікуємо від Rose і Delphi на кожному етапі розробки, ми відзначили, що важливим для нас при проектуванні є створення базової архітектури, в даному випадку, з включенням елементів об’єктної моделі Delphi. Ось тут ми і продемонструємо можливості RDL.


Як приклад ми вибрали фрагмент системи, що забезпечує відображення показників стану пацієнта для лікуючого лікаря. Функціональні вимоги до системи представлені на наступній діаграмі.

Рис. 3. Функціональна діаграма системи


На діаграмі відображені три діючі особи: адміністратор, прилад, лікар. Функції системи, пов’язані з приладом, ми розглядати не будемо. Щодо приладу для нас суттєво, що показник виходить з певною періодичністю, і система надає інтерфейс для його збереження в БД. Все, що залишилися функції системи пов’язані з призначеним для користувача інтерфейсом і забезпеченням збереження інформації в БД або її вибіркою.


В основу системи ми закладаємо такі архітектурні рішення:



  • користувальницький інтерфейс (GUI) Системи будується на основі об’єктної моделі Delphi;
  • інтерфейс з СУБД будується на основі об’єктної моделі Delphi;
  • в якості СУБД використовується реляційна СУБД.

При проектуванні системи ми повинні визначити класи для подання інтерфейсу користувача (boundary classes), Керуючі класи, що реалізують логіку роботи системи (control classes) І класи-сутності для відображення структури зберігання інформації (entity classes).


Класи – сутності, спроектовані нами, представлені на рис. 4.

Рис 4. Класи – сутності системи


З об’єктної моделі класів – сутностей ми отримали фізичну модель даних для реляційної СУБД і забезпечили її генерацію для конкретної СУБД. Подробиці того, як це можна зробити в середовищі Rational Rose, Тут ми опускаємо.


Оскільки ми плануємо побудова GUI на основі об’єктної моделі Delphi, Розумно припустити, що класи для подання інтерфейсу користувача (boundary classes ) Ми можемо отримати при прототіпірованії користувача інтерфейсу в середовищі Delphi. Проектуються класи для користувача інтерфейсу (boundary classes) для вікна представленого на рис. 5.

Рис. 5. Зовнішній вигляд головного вікна системи

Рис. 6. Вікно узгодження моделей Rational Rose і Delphi


Це вікно є основним при узгодженні об’єктних моделей Delphi і Rose і при його використанні реалізується будь-яка з трьох технологій спільної роботи – пряме проектування, зворотне проектування та узгодження (round trip). Ліва панель на екрані містить дерево проекту в Rational Rose (В частині Component View). Права панель відображає дерево проекту в Delphi. Для оновлення інформації про проекти потрібно натиснути кнопку Refresh, А для виконання узгодження моделей в ту чи іншу сторону (з Rational Rose в Delphi або з Delphi в Rational Rose) Кнопки Update All. Для зручності роботи неузгоджені елементи в моделях позначені знаком оклику. Для вибору необхідного проекту в Delphi слід скористатися головним меню вікна.


Ми виконали узгодження моделей за допомогою даного вікна і при цьому одержали наступне:




  1. Кожному модулю проекту в Delphi сопоставлен компонент зі стереотипом <Unit> У розділі Component View дерева проекту Rose. Нашому проекту patient.dpr сопоставлен компонент зі стереотипом <Program>.



  2. Для кожного модуля Delphi у розділі Logical View утворився пакет зі стереотипом <Unit>, А всередині пакету міститься діаграма класів, що відповідає даному модулю. У нас вийшов один такий модуль – main. Поруч у дереві проекту знаходиться посилання на файл main.pas і єдиним клацанням миші ми можемо перейти до нього в середовищі Delphi і подивитися на зовнішній вигляд форми. Це принципово важливо, оскільки якими б образотворчими можливостями не володів мову UML, зовнішній вигляд форми з його використанням описати важко (та й навіщо)! Фактично ми забезпечуємо подання модуля в двох зрізах: з точки зору зовнішнього представлення інтерфейсу користувача і з точки зору об’єктної моделі. На наш погляд, відсутність одного з цих зрізів давало б не повну картину.


Діаграма класів для модуля main представлена ​​на рис. 7.

Рис. 7. Діаграма класів для модуля main


На діаграмі класів ми прибрали атрибути та операції для всіх класів об’єктної моделі Delphi (Оскільки цих атрибутів і операцій в кожному класі кілька десятків – діаграма в такому разі стала б неозорої). Діаграма наочно демонструє, які саме класи об’єктної моделі Delphi використовуються для представлення елементів користувальницького інтерфейсу і що саме вони представляють. З уявлення моделі відразу ж слід виключити TGroupBox і TLabel як архітектурно несуттєві елементи. Діаграма класів для форми табличного редагування представлена ​​на рис. 8.

Рис. 8. Діаграма класів для форми табличного редагування


Крім головного вікна нам також буде потрібно інтерфейс (GUI) для ведення БД пацієнтів, типів показників та одиниць виміру. Ми плануємо використовувати для цього типову форму табличного редагування на основі стандартних компонент Delphi. Намалюємо цю форму в Delphi і перетворимо в модель Rational Rose (Рис. 9).

Рис. 9. Таблична форма редагування.


Всі інші екранні форми за допомогою механізму спадкування отримаємо від табличній форми редагування. Ось як, наприклад, буде виглядати довідник типів спостережень (рис. 10).

Рис. 10. Довідник типів спостережень


Тепер із зовнішнім виглядом користувальницького інтерфейсу ми повністю визначилися, і можна зосередиться на реалізації логіки роботи програми. Для зручності (не треба сприймати це як типову практику), будемо використовувати в якості керуючого класу вже існуючий інтерфейсний клас TMainForm.


TMainForm повинен забезпечувати:





    • навігацію між екранами, обробку подій натискання кнопок для відображення інших форм;

      • заповнення випадаючих списків, пацієнтів, показників, одиниць виміру;

        • автоматичний розрахунок одиниці виміру за типом показника;

          • вибір пацієнта за номером картки;

            • вибір номера картки по пацієнту;

              • розрахунок і відображення останнього значення показника.

                Створимо в середовищі Rational Rose операції для реалізації описаних вище функцій класу TMainForm (Рис. 11).

                Рис. 11. Клас TMainForm.


                Операції класу TMainForm слід розділити на дві групи: розрахунки і реакції на події. Операції, що закінчуються на Click або Change, А також FormShow – Реакції на події, решта – розрахунки.


                Операції повинні реалізовувати наступне:





                • FillPatientList – заповнення списку пацієнтів;


                • FillMeasureList – Заповнення списку одиниць виміру;


                • FillObservList – Заповнення списку типів спостережень;


                • CalcObservVal – Розрахунок останньої величини, що спостерігається;


                • ChPatientByCard – Пошук пацієнта за номером картки;


                • ChCardByPatient – Пошук номера картки по пацієнту;


                • ChMeasureByObserv – Повернути одиницю виміру для заданого типу наблюдненій;


                • CardValChange – Реакція на зміну номера картки;


                • PatientChComboChange – Реакція на вибір нового пацієнта в списку;


                • ObservTypeComboChange – Реакція на вибір типу спостереження;


                • GetValueButtonClick – Реакція на натиснення кнопки розрахунку значення;


                • PatientDictClick – Реакція на натиснення кнопки “Пацієнти”;


                • ObservTypeDictClick – Реакція на натиснення кнопки “Типи спостережень”;


                • MeasureDictClick – Реакція на натиснення кнопки “Одиниці виміру”;


                • FormShow – Обробка при першому відображенні форми на екрані.

                  І останнє, що необхідно для завершення проектування – керуючі класи для реалізації взаємодії з БД. Без них неможливо як наповнення БД, так і реалізація розрахункових операцій управителя класу TMainForm. Як і для інтерфейсних класів, скористаємося середовищем Delphi для проектування керуючого класу взаємодії з БД – TDataModule1, А потім виконаємо узгодження моделей. Новий модуль взаємодії з БД представлений на рис. 12.

                  Рис. 12. Організація взаємодії з БД


                  На основі об’єктів QueryPatient, QueyObType, QueryMeasures і PatientDataSource, ObTypeDataSource, MeasureDataSource реалізується робота з БД пацієнтів, типів спостережень і одиниць виміру – стандартним для Delphi способом, заснованим на використанні пари об’єктів класів TQuery, TdataSource і їх взаємодією з класами GUI. ObservDataSource використовується для доступу до інформації про зроблені спостереженнях. Для опису взаємодії керуючих класів TDataModule1 і TMainForm слід створити кілька діаграм взаємодії, пов’язаних з виконанням необхідних запитів до БД (на увазі обмеженого обсягу статті ці діаграми ми опускаємо).


                  Зауважимо, що в процесі додавання в систему нових модулів і класів і узгодження моделей ми автоматично отримали компонентну модель системи (рис. 13).

                  Рис. 13. Компонентна модель системи


                  Отже, підведемо короткі підсумки. В результаті спільного використання Rational Rose і Delphi ми отримали:




                    • інтерфейсні і керуючі класи, організовані в пакети;

                      • компонентну модель системи.

                        Класи – сутності та діаграми, що описують динаміку, спроектовані в Rational Rose. Надалі моделі Rational Rose дають нам базу для документування проекту, відстеження його стану та організації функціонального тестування. Проект, отриманий в Delphi, В свою чергу, є основою для виконання реалізації. У процесі реалізації проводиться періодичне узгодження проекту в Delphi з моделлю Rational Rose на основі технології round trip, Що дозволяє підтримувати моделі в актуальному стані і плавно здійснювати їх еволюцію відповідно до зміненими вимогами до системи.


                        Висновок



                        На закінчення ми хочемо звернути увагу на ті етапи, де на нашу думку спільне використання Delphi і Rational Rose найбільш привабливо з технологічної точки зору.


                        По перше, це створення прототипу для користувача інтерфейсу. Швидке створення форм у середовищі Delphi дозволяє також швидко отримати і модель інтерфейсних класів у Rose, А на її основі виділити принципові архітектурні моменти (наприклад, спільність поведінки, типові елементи GUI, Надмірність), а також зіставити інтерфейсні класи з функціональними вимогами до системи.


                        По друге, це створення керуючих класів у моделях Rational Rose з наступною генерацією коду в Delphi. Керуючі класи представляються в середовищі Rational Rose при використанні UML більш очевидним чином (в Delphi вони можуть бути розмиті серед значних за обсягом інтерфейсних класів).


                        І, нарешті, по-третє, це етап реалізації програмного коду, на якому в модель можуть бути внесені зміни, пов’язані з питаннями реалізації. Періодичне узгодження моделей на даній стадії дозволяє розробнику переконається, що принципові архітектурні рішення не зазнали істотних змін, а також мати актуальні моделі, що відображають дійсний стан розробки.


                        Схожі статті:


                        Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

                        Коментарів поки що немає.

                        Ваш отзыв

                        Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

                        *

                        *