Робота з аудіо і відео Windows Runtime

Якщо Ви працювали з Silverlight або Windows Presentation Foundation, то в першій частині цієї глави знайдете знайомий матеріал Адже елемент управління MediaElement був основою для побудови всіх інтерфейсів, що підтримують відображення відео або тільки аудіо У Windows Runtime цей елемент виконує аналогічні функції, і механізм роботи з ним практично той самий

У WinRT, як і в Silverlight, MediaElement підтримує ряд форматів для відображення відео і програвання аудіо Ось ці формати:

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp WMV1: Windows Media Video 7

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp WMV2: Windows Media Video 8

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp WMV3: Windows Media Video 9

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp WMVA: Windows Media Video Advanced Profile, non-VC-1

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp WVC1: Windows Media Video Advanced Profile, VC-1

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp H264

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp Підтримка відео у форматі 3D (функція, відсутня в Silverlight)

Якщо Ваше відео в іншому форматі, його необхідно перетворити в один з підтримуваних форматів за допомогою однієї з утиліт, наприклад Expression Encoder

Розглянемо, які формати підтримуються для аудіо:

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp WAV

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp WMA7: Windows Media Audio 7

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp WMA8: Windows Media Audio 8

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp WMA9: Windows Media Audio 9

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp WMA10: Windows Media Audio 10

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp MP3: ISO/MPEG-1 Layer 3

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp AAC

І, нарешті, якщо говорити про протоколи, які підтримує MediaElement, То це http, https і mms Останній з протоколів використовує Windows Media Service для трансляції потокового відео Залежно від зазначеного протоколу MediaElement намагається виконати або прогресивну, або потокову завантаження

Якщо Ви вказуєте протокол http або https, То спочатку здійснюється спроба виконати прогресивну завантаження, а в разі невдачі – потокову Якщо ж ви вказуєте протокол mms, То першою буде спроба виконати потокову завантаження

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

В ієрархії класівMediaElement    є прямим спадкоємцем FrameworkElement Це означає, що він володіє більшістю властивостей, характерних для інших елементів управління Але кілька властивостей характерні тільки для цього елемента Розглянемо ці властивості:

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp Source – Дозволяє встановити шлях до відеофайла (потоку), який має бути відображений в MediaElement Крім цього властивості існує метод SetSource, Про яке буде сказано нижче

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp AutoPlay – Дозволяє вказати, чи потрібно програвати вказаний відео або аудіо відразу після завантаження програми За умовчанням це властивість встановлено в true Тим часом, якщо Ваш відео або аудіо не передається разом з додатком, краще встановити значення в false

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp IsMuted – Дозволяє відключити звук, якщо властивість встановлено в true

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp Volume  – Задає поточний рівень гучності Значення гучності варіюється від 0 до 1 За замовчуванням значення встановлено в 0,5 Тому якщо Ваш інтерфейс не надає механізму регулювання гучності, встановіть Volume в 1 Інакше отримаєте багато відгуків про те, що занадто тихо

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp Balance – Приймає значення в діапазоні від -1 до +1 За умовчанням це властивість встановлено в 0, що гарантує однаковий баланс між правим і лівим аудіовиходом Якщо значення встановлено в -1, то весь звук буде направлений на ліву колонку, а якщо +1, то на праву

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp Position – Містить поточну позицію у видимій відеофайл

Щоб встановити або отримати властивість Position, Необхідно використовувати типTimeSpan, Який задає час в годинах, хвилинах і секундах

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp CanSeek – Дозволяє визначити, чи можливо використовувати властивість Position для переміщення по відео Адже якщо MediaElement приймає потокове відео, то ні про яке переміщення не може бути й мови

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp CanPause  – Визначає, чи можна призупинити відтворення контенту Якщо передається потокове відео, то повертає значення false

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp CurrentState – Визначає стан медіаелементів і може містити одне із значень перечислимого типуMediaElementState: Buffering, Opening, Playing, Closed, Paused, Stopped

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp DownloadProgress  – Визначає відсоток контенту, завантаженого з сервера Ця властивість застосовно при прогресивній завантаженні, коли файл з контентом завантажується з сервера

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp DownloadProgressOffset – Визначає зсув (позицію), з якого починається завантаження фрагмента відео Дана властивість встановлюється в тому випадку, якщо користувач змінив поточну позицію на фрагмент, який ще не був завантажений

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp DroppedFramesPerSecond – Показує кількість фреймів у секунду, які були викинуті з потоку через неможливість їх відобразити Використовується для потокового відео

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp Markers – Містить колекцію маркерів, які містяться у відео

Про маркерах буде сказано в наступному розділі

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp NaturalDuration – Визначає загальну тривалість відео-або аудіофрагмента Властивість задається за допомогою екземпляра класу TimeSpan

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp NaturalVideoWidth – Це властивість, а також властивість NaturalVideoHeight,

задають вихідну довжину і ширину відео

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp NaturalVideoHeight – Повертає початкову ширину відео

Приклад використання MediaElement:

&ltGrid Background=&quot{StaticResource ApplicationPageBackgroundBrush}&quot&gt

&ltGrid x:Name=&quotLayoutRoot&quot Background=&quotGray&quot Width=&quot400&quot Height=&quot400&quot&gt

&ltMediaElement Source=&quotWildLifewmv&quot&gt&lt/MediaElement&gt

&lt/Grid&gt

&lt/Grid&gt

Тут ми спеціально встановили явні розміри батьківського елементу і сірий фон Запустивши це додаток, Ви зможете побачити таку картину:

Рис 91

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

На додаток до розглянутих властивостей можна виділити властивістьClip Властивість може містити будь-яку геометрію, створюючи вигадливі форми, заповнені відео

Розібравшись з властивостямиMediaElement, Розглянемо основні методи,

дозволяють управляти відео:

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp SetSource – МетодSetSource дозволяє встановити властивістьSource

медіаелементів

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp Play  – Запускає відео або аудіо для програвання Якщо відео передається у вигляді потоку, то просто починає вибирати дані з потоку

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp Pause – Зупиняє програвання контенту Якщо відео передається у вигляді потоку, то виклик методу буде проігнорований

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp Stop – Зупиняє відтворення

І, нарешті, найважливіше, – це події, які повязані зMediaElement Адже саме реакція на події дозволить зробити Ваш інтерфейс найбільш динамічним і привабливим для користувача Розглянемо всі події, характерні для медіаелементів:

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp BufferingProgressChanged  – Генерується при зміні властивості BufferingChanged, Тобто при буферизації чергового фрагмента відео

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp CurrentStateChanged   – Генерується при зміні стану медіаелементів

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp DownloadProgressChanged – Генерується при зміні відсотка завантаження відео з сервера

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp MarkerReached – Генерується тоді, коли був досягнутий один з маркерів, встановлених усередині відео Про маркерах буде сказано в наступному розділі

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp MediaEnded – Подія відбувається тоді, коли медіаелементів припинив програвати відео або аудіо

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp MediaFailed – Важлива подія, оскільки саме воно дозволяє реагувати на помилки, повязані з читанням медіаконтенту, в керованому коді Якщо обробник на цю подію не знайдений, то помилка буде передана в JavaScript, а додаток припинить свою роботу

·&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp MediaOpened  – Відбувається, коли медіапотоків був успішно відкритий і була отримана початкова інформація про нього

Розглянувши таку кількість властивостей, методів і подій, можна зробити висновок, що MediaElement володіє всім необхідним для реалізації інтерфейсу будь-якої складності Давайте розглянемо невеликий приклад, що демонструє деякі властивості, події та методи медіаелементів

Реалізуємо інтерфейс нашого застосування наступним чином:

&ltStackPanel HorozontalAlignment=&quotLeft&quot&gt

&ltMediaElement Name=&quotmyMedia&quot Height=&quot300&quot Source=&quotWildLifewmv&quot

Margin=&quot5&quot AutoPlay=&quotFalse&quot MediaOpened=&quotmyMedia_MediaOpened&quot MediaEnded=&quotmyMedia_MediaEnded&quot&gt

&lt/MediaElement&gt

&ltStackPanel Orientation=&quotHorizontal&quot&gt

&ltTextBlock Name=&quotdurationText&quot Text=&quotDuration: &quot Margin=&quot5&quot&gt

&lt/TextBlock&gt

&ltTextBlock Text=

&quot{Binding PositionTotalSeconds, ElementName=myMedia, Mode=OneWay}&quot

Margin=&quot5&quot&gt

&lt/TextBlock&gt

&ltTextBlock Text=&quot/&quot Margin=&quot5&quot&gt&lt/TextBlock&gt

&ltTextBlock Text=&quot&quot Name=&quotsecondsText&quot Margin=&quot5&quot&gt

&lt/TextBlock&gt

&lt/StackPanel&gt

&ltSlider Name=&quotpositionSlider&quot Minimum=&quot0&quot Margin=&quot5&quot IsEnabled=&quotFalse&quot

Value=

&quot{Binding PositionTotalSeconds, ElementName=myMedia, Mode=OneWay}&quot

&gt&nbsp

&lt/Slider&gt

&ltStackPanel Orientation=&quotHorizontal&quot &gt

&ltButton Content=&quotPlay&quot Name=&quotplayButton&quot Margin=&quot5&quot Width=&quot100&quot IsEnabled=&quotFalse&quot Click=&quotplayButton_Click&quot&gt&lt/Button&gt

&ltButton Content=&quotPause&quot Name=&quotpauseButton&quot IsEnabled=&quotFalse&quot Margin=&quot5&quot Width=&quot100&quot Click=&quotpauseButton_Click&quot &gt&lt/Button&gt

&ltButton Content=&quotStop&quot Name=&quotstopButton&quot Margin=&quot5&quot Width=&quot100&quot IsEnabled=&quotFalse&quot Click=&quotstopButton_Click&quot &gt&lt/Button&gt

&ltCheckBox Content=&quotMute&quot Margin=&quot5&quot IsEnabled=&quotFalse&quot Name=&quotmuteBox&quot IsChecked=

&quot{Binding IsMuted, ElementName=myMedia, Mode=TwoWay}&quot

&gt&nbsp

&lt/CheckBox&gt

&lt/StackPanel&gt

&ltStackPanel Orientation=&quotHorizontal&quot &gt

&ltTextBlock Text=&quotVolume:&quot Margin=&quot5&quot&gt&lt/TextBlock&gt

&ltSlider Name=&quotvolumeSlider&quot Minimum=&quot0&quot Maximum=&quot1&quot Width=&quot200&quot IsEnabled=&quotFalse&quot StepFrequency=&quot01&quot Value=

&quot{Binding Volume, ElementName=myMedia, Mode=TwoWay}&quot&gt

&lt/Slider&gt

&lt/StackPanel&gt

&lt/StackPanel&gt

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

Ось як має виглядати наш інтерфейс:

Рис 92

Більшість елементів ми встановили за допомогою механізму звязування з даними, але якийсь код нам доведеться написати Ось як виглядатимуть наші обробники подій:

private void myMedia_MediaOpened(object sender, RoutedEventArgs e)

{

positionSliderIsEnabled = true volumeSliderIsEnabled = true playButtonIsEnabled = true stopButtonIsEnabled = true

positionSliderMaximum = myMediaNaturalDurationTimeSpanTotalSeconds

secondsTextText = myMediaNaturalDurationToString()

}

private void playButton_Click(object sender, RoutedEventArgs e)

{

playButtonIsEnabled = false pauseButtonIsEnabled = true

myMediaPlay()

}

private void pauseButton_Click(object sender, RoutedEventArgs e)

{

pauseButtonIsEnabled = false playButtonIsEnabled = true

myMediaPause()

}

private void stopButton_Click(object sender, RoutedEventArgs e)

{

pauseButtonIsEnabled = false playButtonIsEnabled = true

myMediaStop()

}

private void myMedia_MediaEnded(object sender, RoutedEventArgs e)

{

pauseButtonIsEnabled = false playButtonIsEnabled = true

}

У цих обробниках подій ми викликаємо відповідні методи (Stop, Start, Pause) І активуємо кнопки, які повинні бути доступні виходячи з логіки інтерфейсу

Як видно, реалізувати повноцінний медіаплейер не дуже складно Більше часу піде на дизайн інтерфейсу Природно, якщо ви хочете реалізувати універсальний плейер, який буде програвати і потокове відео, доведеться додати додаткові перевірки Однак ідея від цього не зміниться

Розглянемо ще одну особливість медіаелементів – маркери

Маркери представляють собою спеціальні мітки, привязані до конкретної точки на часовій шкалі відео Ці мітки здатні містити дані (текст) і можуть бути створені або за допомогою Microsoft Expression Encoder (тоді вони зберігаються в відеофайлі), або динамічно (такі мітки зберігаються лише в памяті)

Сценаріїв застосування маркерів багато Наприклад, маркери можуть бути використані для створення навчальних уроків, коли в процесі відображення відео необхідно пройти проміжні тести або запустити анімацію

Ще один приклад – це управління субтитрами Фактично, щоб асоціювати субтитри з відео, досить створити колекцію маркерів і при досягненні чергового маркера (подія MarkerReached) Відобразити субтитр на екран Покажемо використання маркерів на прикладі сценарію з субтитрами

Створимо просте додаток, що містить медіаелементів і поле для відображення субтитрів:

&ltStackPanel&gt

&ltMediaElement Width=&quot400&quot Height=&quot300&quot Name=&quotmyMedia&quot Source=&quotWildlifewmv&quot MediaOpened=&quotmyMedia_MediaOpened&quot MarkerReached=&quotmyMedia_MarkerReached&quot&gt

&lt/MediaElement&gt

&ltTextBlock Text=&quot&quot HorizontalAlignment=&quotCenter&quot Name=&quotsubtitleText&quot FontSize=&quot16&quot FontWeight=&quotBold&quot &gt

&lt/TextBlock&gt

&lt/StackPanel&gt

Було б добре вибирати субтитри з XML або текстового файлу Але щоб не писати багато коду, просто створимо кілька екземплярів класу Subtitle, Який ми визначили самостійно Примірники цього класу будуть містити час і сам текст субтитрів

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

public sealed partial class BlankPage : Page

{

Subtitle[] subtitles = new Subtitle [3]

public BlankPage()

{

InitializeComponent()

Subtitle s = new Subtitle () stext = Побігли конячки; stime = new TimeSpan (0, 0, 0) subtitles [0] = s

s = new Subtitle()

stext = Полетіли пташки; stime = new TimeSpan (0, 0, 5) subtitles [1] = s

s = new Subtitle()

stext = Ховрахи на пляжі; stime = new TimeSpan (0, 0, 7) subtitles [2] = s

}

private void myMedia_MediaOpened(object sender, RoutedEventArgs e)

{

TimelineMarker t

foreach (Subtitle s in subtitles)

{

t = new TimelineMarker() tTime = stime

tText = stext myMediaMarkersAdd(t)

}

}

private void myMedia_MarkerReached(object sender, TimelineMarkerRoutedEventArgs e)

{

subtitleTextText = eMarkerText

}

}

class Subtitle

{

public TimeSpan time public String text

}

Результат роботи програми показаний на малюнку

Рис 93

Таким чином, робота з маркерами не представляє складнощів Разом з тим,

маркери є потужним інструментом при роботі з відео

Сергій Лутай, Сергій Байдачний, Windows 8 для C # розробників

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


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

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

Ваш отзыв

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

*

*