Поиск на сайте: Расширенный поиск


Новые программы oszone.net Читать ленту новостей RSS
CheckBootSpeed - это диагностический пакет на основе скриптов PowerShell, создающий отчет о скорости загрузки Windows 7 ...
Вы когда-нибудь хотели создать установочный диск Windows, который бы автоматически установил систему, не задавая вопросо...
Если после установки Windows XP у вас перестала загружаться Windows Vista или Windows 7, вам необходимо восстановить заг...
Программа подготовки документов и ведения учетных и отчетных данных по командировкам. Используются формы, утвержденные п...
Red Button – это мощная утилита для оптимизации и очистки всех актуальных клиентских версий операционной системы Windows...
OSzone.net Microsoft Разработка приложений .NET Framework Исследуем Microsoft .NET Framework 4.5.1 RSS

Исследуем Microsoft .NET Framework 4.5.1

Текущий рейтинг: 0 (проголосовало 0)
 Посетителей: 2352 | Просмотров: 4032 (сегодня 0)  Шрифт: - +

В выпуске Microsoft .NET Framework 4.5.1 наряду с Visual Studio 2013 введены инновационные средства для повышения эффективности труда разработчиков и производительности приложений. Кроме того, предлагаются новые средства для более удобного использования NuGet-пакетов для .NET, что очень важно, поскольку NuGet является основным механизмом доставки библиотек для .NET Framework.

Предыдущий продукт, .NET Framework 4.5, был значимым выпуском со множеством новшеств. Он установлен более чем на 200 миллионах компьютеров. .NET Framework 4.5.1 выпустили примерно 14 месяцев назад (в октябре 2013 г.), и, несмотря на столь короткий период, в этой инфраструктуре появилось много средств, о которых часто просили клиенты. В этой статье я дам обзор новых средств в .NET Framework 4.5.1, а за более подробными сведениями обращайтесь к публикациям по .NET Framework 4.5.1 RTM (bit.ly/1bBlEPN) и .NET Framework 4.5.1 Preview (bit.ly/10Vr2ft) в блоге .NET Framework.

.NET Framework 4.5.1 — это лишь часть того, над чем работала группа .NET (членом которой я являюсь) за последние годы. Мы также поставили несколько библиотек через NuGet, которые заполняют пробелы в этой платформе и обеспечивают поддержку новых сценариев использования. Я дам обзор наших .NET-библиотек, распространяемых через NuGet, и освещу новый JIT-компилятор для .NET, который мы уже давно разрабатывали и выпустили в виде CTP-версии (Community Technology Preview) приблизительно в то же время, что и .NET Framework 4.5.1.

Более продуктивная разработка

Начну с новых средств отладки, предоставляемых с .NET Framework 4.5.1 для более продуктивной разработки.

Совершенствование отладки асинхронного кода После создания основательной и простой в использовании базы для модели асинхронного программирования в предыдущих выпусках Framework мы хотели сгладить некоторые остающиеся шероховатости в общей работе с .NET Framework 4.5.1. Для отладки асинхронного кода важны два вопроса: «Как попасть в конкретный асинхронный метод при отладке?» и «Каково состояние всех задач в приложении?». В Visual Studio 2013 введены усовершенствования в окна Call Stack и Tasks, которые помогут вам найти ответы на эти вопросы гораздо более интуитивно понятным способом. Эти усовершенствования поддерживаются для настольных и веб-приложений, а также для приложений Windows Store в Windows 8.1; они также доступны для языков C++ и JavaScript.

Вызовы асинхронных методов в приложении или библиотеке часто вложенные, и в управлении потоком выполнения полагаются на ключевое слово await. Ранее Visual Studio не показывал цепочку асинхронных вызовов при остановке на точке прерывания в окне Task. Visual Studio 2013 обеспечивает логическое и последовательное представление методов в цепочке вложенных вызовов как асинхронных, так и синхронных методов. Это упрощает понимание того, как программа попала в некую точку внутри асинхронного вызова.

На рис. 1 показан пример асинхронного кода, а на рис. 2 и 3 демонстрируется разница между представлениями стеков вызовов для этого кода в Visual Studio 2012 и Visual Studio 2013. Подробнее об этой функциональности см. «Debugging Asynchronous Code in Visual Studio 2013—Call Stack enhancements» в блоге по ссылке bit.ly/19NTNez.

Рис. 1. Пример асинхронного кода

private async void ShowSampleImg_Click(object sender,
    RoutedEventArgs e)
{
    string imgUri = "http://example.com/sample.jpg";
    BitmapImage bitmap = new BitmapImage();
    bitmap.BeginInit();
    bitmap.StreamSource = await GetSampleImgMemStream(imgUri);
    bitmap.EndInit();
    sampleImg.Source = bitmap;
}
private async Task<MemoryStream> GetSampleImgMemStream(string srcUri)
{
   Stream stream = await GetSampleImage(srcUri);
   var memStream = new MemoryStream();
   await stream.CopyToAsync(memStream);
   memStream.Position = 0;
   return memStream;
}
private async Task<Stream> GetSampleImage(string srcUri)
{
  HttpClient client = new HttpClient();
  Stream stream = await client.GetStreamAsync(srcUri);
  return stream;
}

*
Рис. 2. Окно Call Stack в Visual Studio 2012

*
Рис. 3. Окно Call Stack в Visual Studio 2013

Окно Tasks в Visual Studio 2013 помогает понять состояние асинхронных задач в ваших приложениях, отображая все выполняемые и запланированные на данный момент задачи. Оно заменяет окно Parallel Tasks, которое было доступно в предыдущих версиях Visual Studio. На рис. 4 приведен экранный снимок окна Tasks в Visual Studio 2013 для примера кода, показанного на рис. 1.

*
Рис. 4. Окно Tasks в Visual Studio 2013

Поддержка x64 для функции Edit and Continue Эту функцию отладчика часто запрашивали клиенты, и за нее было отдано более 2600 голосов на сайте Visual Studio UserVoice, где пользователи могут оставлять запросы на новые средства (bit.ly/14YIM8X). Разработчикам нравилось пользоваться функцией Edit and Continue, введенной в Visual Studio 2005 и .NET Framework 2.0 для x86-проектов. Edit and Continue упрощает написание корректного кода, позволяя изменять исходный код в течение сеанса отладки при доступном состоянии приложения. Вы даже можете смещать указатель команд так, чтобы повторять выполнение кода после внесения изменения. Это повышает продуктивность труда, так как разработчику не нужно останавливать и сеанс и запускать его заново для проверки изменений.

Поддержка x64 для функции Edit and Continue теперь включена в Visual Studio 2013 и .NET Framework 4.5.1. Вы можете использовать эту функцию для отладки настольных приложений (Windows Presentation Foundation, Windows Forms и т. д.), приложений Windows Store, веб-приложений ASP.NET и проектов Windows Azure Cloud Services, ориентированных на архитектуры x64, AnyCPU или x86.

Анализ возвращаемого значения в управляемом коде Поддержка отладчиком возвращаемых значений в управляемом коде (managed return values) — еще один популярный запрос, набравший более 1000 голосов на сайте UserVoice. Отладчик Visual C++ давно имеет такую функцию, которая позволяет наблюдать за значениями, возвращаемыми методами, и мы хотели ввести ту же возможность для .NET. Эта функция полезна во многих шаблонах кода. Однако ее настоящую ценность вы увидите в случае вложенных вызовов методов, как демонстрируется на рис. 5. Благодаря этой функции вам больше незачем беспокоиться о сохранении результатов ваших методов в локальных переменных исключительно для того, чтобы упростить отладку. Когда вы перешагиваете через вызов метода, в окне Autos будут показаны непосредственное возвращаемое значение и значения, возвращаемые вложенными методами, наряду со значениями параметров, переданными функциям. Кроме того, вы можете задействовать окно Immediate для доступа к последнему возвращенному значению, используя новую псевдопеременную $ReturnValue.

*
Рис. 5. Окна Autos и Intermediate в Visual Studio 2013

Улучшения в разработке приложений Windows Store Мы отреагировали на отзывы и обращения и обеспечили в .NET поддержку новых средств Windows Runtime (WinRT) для повышения эффективности разработки .NET-приложений Windows Store.

Одной из болевых точек было преобразование .NET Stream в WinRT IRandomAccessStream. В .NET Framework 4.5.1 для System.IO.Stream добавлен новый метод расширения, AsRandomAccessStream, который решает эту проблему. Теперь можно писать следующий код, позволяющий легко предоставлять IRandomAccessStream:

// Пример: получаем изображение по URL через сетевой ввод-вывод
var client = new HttpClient();
Stream stream = await client.GetStreamAsync(imageUrl);
var memStream = new MemoryStream();
await stream.CopyToAsync(memStream);
memStream.Position = 0;
var bitmap = new BitmapImage();
bitmap.SetSource(memStream.AsRandomAccessStream());
image.Source = bitmap;

Этот пример кода считывает изображение из Интернета и отображает его в XAML-элементе управления Image (представленном переменной image).

Другое усовершенствование — распространение ошибки в Windows Runtime (WinRT). WinRT в Windows 8.1 обеспечивает передачу исключений между WinRT-компонентами. Благодаря этой поддержке исключение может быть вызвано в WinRT-компоненте на C++ и захвачено кодом на C# (или наоборот). Дополнительная информация об исключении теперь доступна через свойства Message и StackTrace в System.Exception.

В Windows Runtime также добавлена поддержка в структурах значимых типов, которые могут содержать null. Вы можете создавать управляемые WinRT-компоненты, предоставляющие структуры с этим новшеством, как, например, в следующем коде:

public struct PatientRecord
{
  public string Name;
  public int Age;
  public string HomeAddress;
  // InsuranceID может быть равен null
  public int? InsuranceId;
}

Повышение производительности приложений

Производительность приложений постоянно находится в центре внимания группы .NET Framework. В этом выпуске мы отреагировали на предложения по сборщику мусора и значительно ускорили запуск приложений ASP.NET.

ASP.NET App Suspension Эта функция — одна из самых главных в .NET Framework 4.5.1 из-за значительного прироста производительности, который она обеспечивает, в частности для сценариев с общим хостингом, где критичны плотность сайтов и задержки в запуске. ASP.NET App Suspension позволит провайдерам общего хостинга (коммерческим компаниям в области веб-хостинга или корпоративным ИТ-системам) размещать намного больше веб-сайтов ASP.NET на сервере и при этом добиваться ускорения запуска приложений.

ASP.NET App Suspension зависит от IIS Idle Worker Process Page-Out — новой функциональности IIS в Windows Server 2012 R2. IIS Idle Worker Process Page-Out вводит для веб-сайтов новое состояние «приостановлен» (suspended) в дополнение к существующим состояниям «неактивный» и «активный». При переходе в это новое состояние освобождаются задействованные данным сайтом критические ресурсы, которые с этого момента доступны другим сайтам; к таким ресурсам относятся процессорное время и память. В то же время сайт может быстро возобновить свою работу.

На рис. 6 показаны переходы состояний ASP.NET-сайтов при использовании App Suspension. Веб-сайт запускается в неактивном состоянии. Он загружается в память и переходит в активное состояние, получив запрос на первую страницу. По истечении некоего периода простоя сайт будет приостановлен в соответствии с конфигурацией пула приложений (bit.ly/1aajEeL). При последующих запросах этот сайт может быстро вернуться в активное состояние. Такой цикл может происходить многократно. Раньше сайты завершались и становились неактивными после определенного периода простоя.

*
Рис. 6. Переходы состояний для веб-сайтов ASP.NET

InactiveНеактивный
ActiveАктивный
SuspendedПриостановлен

Для использования этой новой функциональности никаких изменений в коде не требуется. ASP.NET App Suspend автоматически включается настройкой пула приложений IIS на «Suspend» в Windows Server 2012 R2.

Ранее я уже расхваливала «значительный прирост производительности», достигаемый с помощью этой функциональности, и теперь хотела бы вернуться к данному вопросу с некоторыми цифрами, полученными в наших лабораториях. Мы провели обширные эксперименты для замера показателей времени запуска, сравнивая «возобновление из приостановленного состояния» с «запуском после завершения». Эти эксперименты мы проделали на компьютере под значительной нагрузкой, создаваемой запросами и при обращении к большому количеству пулов приложений — мы стремились воссоздать среду общего хостинга. Результаты показали уменьшение времени запуска для сайтов, к которым было обращение после приостановки, на 90%. Кроме того, мы измерили увеличение плотности сайтов. Мы смогли разместить примерно в семь раз больше ASP.NET-сайтов в Windows Server 2012 R2 при включенной ASP.NET App Suspension. Результаты экспериментов представлены на рис. 7. Более подробное описание этих экспериментов см. в «ASP.NET App Suspend—Responsive Shared .NET Web Hosting» в блоге по ссылке bit.ly/17fI6dM.

*
Увеличить

Рис. 7. Показатели производительности для ASP.NET App Suspension, наблюдавшиеся в .NET Lab

Hosted ASP.NET SitesРазмещенные ASP.NET-сайты
Windows Server 2012Windows Server 2012
Windows Server 2012 R2 PreviewWindows Server 2012 R2 Preview
7x Improvement in Site DensityСемикратное увеличение в плотности сайтов
Number of hosted sites – single serverЧисло размещенных сайтов — один сервер
Startup timeВремя запуска
90% Reduction in startup timeСокращение времени запуска на 90%
Cold Start (before)Холодный запуск (раньше)
Resume, SSD (after)Возобновление из приостановленного состояния (теперь)
DotNetNukeDotNetNuke
dasBlogdasBlog
UmbracoUmbraco
Simple ASP.NET appПростое ASP.NET-приложение
ASP.NET SitesASP.NET-сайты

Усовершенствования в JIT-компиляции на многоядерных процессорах Такая JIT-компиляция теперь включена по умолчанию для ASP.NET-приложений. Замеры производительности показали ускорение холодного времени запуска при включенной JIT-компиляции, использующей многоядерный процессор, вплоть до 40%. Выигрыш достигается JIT-компиляцией на нескольких ядрах параллельно с выполнением кода. На внутреннем уровне «многоядерная JIT-компиляция» была расширена для поддержки динамически загружаемых сборок, общих в ASP.NET-приложениях. От такой дополнительной поддержки выигрывают и клиентские приложения, где эта функциональность остается не обязательной. Подробнее о данной функциональности см. «An easy solution for improving app launch performance» в соответствующем блоге .NET Framework по ссылке bit.ly/RDZ4eE.

Уплотнение кучи крупных объектов (Large Object Heap, LOH) по запросу Уплотнение LOH — важное требование в некоторых сценариях, которое теперь доступно в этом выпуске. Сначала немного информации о LOH, так как этот механизм может быть незнаком вам. Сборщик мусора сохраняет объекты, размер которых превышает 85 000 байтов, в LOH. LOH может стать фрагментированной, и в некоторых случаях это может привести к разрастанию LOH или даже к исключениям OutOfMemoryException. Такие ситуации, хоть и редки, все же встречаются из-за отсутствия достаточного объема непрерывных блоков памяти в LOH, чтобы удовлетворить запрос на выделение памяти, даже если в целом памяти хватает.

При уплотнении LOH вы можете потребовать возврата памяти и объединения неиспользуемых малых блоков памяти, чтобы сделать их доступными для операций выделения более крупных объемов памяти; это повышает эффективность общего использования машинной памяти. Хотя эта идея звучит привлекательно, соответствующая функциональность не предназначена для рутинного использования. Уплотнение LOH — процесс дорогостоящий, он может вызывать длительные паузы в работе приложения, поэтому его следует применять в производственных средах только после тщательного анализа и тестирования.

Более удобное использование библиотек .NET Framework через NuGet

Мы намерены чаще поставлять версии .NET Framework, чтобы новые средства и исправления быстрее становились доступными. По сути, эта практика уже началась с выходом .NET Framework 4.5.1. Кроме того, мы используем NuGet как механизм доставки.

NuGet — сравнительно новый формат пакетов для .NET Framework. Он предоставляет стандартный формат упаковки библиотек, ориентированных на один или более .NET-профилей, и может согласованно использоваться средствами разработки, например Visual Studio. NuGet.org является основным репозитарием NuGet и единственным, используемым группой .NET. Visual Studio поставляется с интегрированным клиентом NuGet для ссылок и использования NuGet-пакетов в ваших проектах.

Мы поставляем .NET-библиотеки через NuGet в течение последних нескольких лет. По нашему мнению, NuGet — превосходное средство доставки библиотек большому количеству разработчиков на нескольких .NET-платформах. Мы улучшили NuGet UI в Visual Studio 2013 на основе множества отзывов, особенно для корпоративных сценариев применения.

Более эффективный поиск и официальная поддержка  Чтобы улучшить и ускорить поиск пакетов от Microsoft, был создан канал Microsoft и .NET NuGet. На NuGet.org размещены тысячи пакетов, что могло бы затруднить поиск среди них новых .NET-пакетов. Новый, официально курируемый канал обеспечивает специализированное представление об официальных пакетах Microsoft и .NET на NuGet.org. Мы намерены добавлять в этот канал лишь те пакеты, которые отвечают тем же требованиям качества и поддержки, что и .NET Framework. Поэтому вы можете использовать эти пакеты везде, где применяете .NET API. Мы также создали веб-представление этого канала на странице «Microsoft .NET Framework NuGet Packages» (bit.ly/19D5QLE), размещенной в блоге .NET Framework.

Группа NuGet помогла нам шире распространить этот опыт, обновив свой клиент в Visual Studio, который теперь включает фильтрацию по курируемым каналам. На рис. 8 показан клиент NuGet в Visual Studio 2013.

*
Рис. 8. Клиент NuGet в Visual Studio 2013

Обслуживание  Некоторые корпоративные клиенты сообщили нам, что они тянули с внедрением наших NuGet-пакетов до появления централизованного обслуживания этих библиотек через Microsoft Update. Мы добавили эту возможность обновления в .NET Framework 4.5.1, что позволяет приложениям использовать такую новую функциональность. Microsoft Update будет дополнительным механизмом выпуска .NET-библиотек, распространяемых через NuGet лишь в том маловероятном случае, если нам понадобится быстрое обновление для широкого круга клиентов какой-либо библиотеки с критически важным исправлением, касающимся безопасности. Даже при наличии этого нового варианта мы будем по-прежнему использовать NuGet как основной механизм доставки обновлений и исправлений библиотек.

Автоматическое разрешение конфликтов между разными версиями Приложения могут ссылаться более чем на одну версию NuGet-пакета. В случае настольных и веб-приложений вам нужно было вручную устранять конфликт между разными версиями, чтобы в период выполнения загружался согласованный набор библиотек; эта задача могла быть трудной и неудобной. Чтобы устранить эти неудобства, Visual Studio 2013 автоматически конфигурирует приложения на использование самой новой версии каждой библиотеки, что решает проблему простым и понятным способом. Кроме того, эта политика соответствует таковой в приложениях Windows Phone и Windows Store, где она применялась изначально.

Visual Studio 2013 будет автоматически генерировать перенаправления привязок (binding redirects) в app.config на этапе сборки, если в приложении обнаружится конфликт между разными версиями библиотек. Эти перенаправления привязок сопоставляют каждую версию, найденную для данной библиотеки, с самой новой версией. В период выполнения ваше приложение будет использовать единственную версию каждой библиотеки — самую новую среди всех ссылок. Главным стимулом создания этой функциональности было стремление обеспечить большее удобство в использовании NuGet-библиотек; однако такой вариант работает для любых других библиотек. В разделе «How to: Enable and Disable Automatic Binding Redirection» в MSDN Library (bit.ly/1eOi3zW) эта функциональность описывается подробнее.

И многое другое…

До этого момента я суммировала все то, что было предоставлено в выпуске .NET Framework 4.5.1. В тот же период времени мы распространили некоторые важные новые компоненты и средства и через другие механизмы доставки.

NuGet-пакет клиентских библиотек HTTP Клиентская библиотека HTTP предоставляет согласованный и современный сетевой .NET API. Она позволяет писать интуитивно понятный асинхронный код (с применением ключевого слова await) для доступа к сервисам по HTTP с именами методов, прямо соответствующими HTTP-примитивам, таким как GET, PUT, POST и DELETE. Кроме того, она обеспечивает прямой доступ к HTTP-заголовкам и телу ответа как к любому из следующих типов: String, Stream или Byte[].

Изначально HttpClient была доступна только для настольных приложений и приложений Windows Store, написанных для .NET Framework 4.5. Разработчикам портируемых библиотек и приложений Windows Phone приходилось использовать HttpWebRequest и HttpWebResponse с их моделью, отличной от асинхронного шаблона на основе задач (Task-based Asynchronous Pattern, TAP). В связи с большим количеством запросов на поддержку портируемой библиотеки и Windows Phone мы поставили портируемую версию библиотеки HttpClient через NuGet, чтобы заполнить этот пробел в платформе. В итоге у всех .NET-разработчиков теперь есть доступ к HttpClient с ее TAP-async API.

После выпуска первых нескольких версий NuGet-пакета HttpClient мы добавили функциональность автоматической декомпрессии (bit.ly/13xWATe) в ответ на пожелания клиентов. Автоматическая декомпрессия HTTP-ответов помогает свести к минимуму требования к данным, что не только полезно на мобильных устройствах, но и помогает повысить производительность настольных приложений.

Microsoft HTTP Client Libraries в NuGet (bit.ly/1a2DPNY) скачаны уже более 1,3 миллиона раз. Вы можете использовать этот пакет в приложениях, ориентированных на Windows Phone 7.5 и выше, Silverlight 4 и выше, .NET Framework 4 и выше, Windows Store и Portable Class Libraries (PCL).

NuGet-пакет Microsoft Immutable Collections Еще один популярный .NET-пакет, который предоставляет простые в использовании, высокопроизводительные неизменяемые наборы, такие как ImmutableList<T> и ImmutableDictionary<TKey, TValue>. Неизменяемые наборы нельзя модифицировать после конструирования. Это позволяет передавать неизменяемые типы через границы потоков или асинхронных контекстов, не беспокоясь о параллельных операциях. Даже исходный создатель набора не может добавить в него никакие элементы или что-то удалить.

В .NET Framework есть типы наборов только для чтения, например ReadOnlyCollection<T> и IReadOnlyList<T>. Эти типы гарантируют, что потребитель не сможет изменить данные. Однако для провайдера схожих гарантий нет. Это может привести к повреждению данных, если провайдер и потребитель одновременно манипулируют ими в разных потоках. В случае неизменяемых типов наборов вы получаете гарантию, что данный экземпляр никогда не изменится.

NuGet-пакет Microsoft Immutable Collections (bit.ly/18xhE5W) доступен как портируемая библиотека и может использоваться в настольных приложениях и в приложениях Windows Store, ориентированных на .NET Framework 4.5 и выше, в PCL и приложениях Windows Phone 8. За более подробными сведениями обращайтесь к публикации «Immutable collections ready for prime time» (bit.ly/18Y3xp8) в блоге .NET Framework и в документации MSDN по ссылке bit.ly/189XR9U.

Новый JIT-компилятор в .NET — RyuJIT JIT-компилятор является одним из ключевых компонентов, которые постоянно находятся в центре нашего внимания: мы стремимся к тому, чтобы они способствовали повышению производительности приложений. Группа .NET недавно объявила о выпуске CTP-версии следующего поколения JIT-компилятора для x64 под кодовым названием «RyuJIT». RyuJIT в два раза быстрее компилирует код по сравнению с существующей x64-версией JIT-компилятора, а это означает, что приложения, использующие RyuJIT, запускаются на 30% быстрее в зависимости от того, насколько велика доля JIT-компиляции в этот период. (Заметьте, что время, затрачиваемое на JIT-компиляцию, является лишь одной из частей общего времени запуска, поэтому приложение не стартует в два раза быстрее, хотя JIT-компиляция выполняется в два раза быстрее.) В то же время RyuJIT не в коей мере не приносит в жертву качество кода, и этот современный JIT-компилятор открывает простор для будущих оптимизаций кода.

Помимо выигрыша в производительности, RyuJIT отражает стремление группы .NET к максимальному учету мнений клиентов. Менее чем через месяц после появления CTP мы выпустили обновленную версию, где были учтены пожелания и отзывы корпоративных клиентов.

Мы начали работы над RyuJIT с акцентом на архитектуру x64 как над одной из частей облачной платформы. По мере продвижения работ мы ввели поддержку для других архитектур. Подробнее о проекте RyuJIT и о том, как скачать и использовать его CTP-версию, см. в статье «RyuJIT: The next-generation JIT compiler for .NET» по ссылке bit.ly/19RvBHf. Рекомендую опробовать эту версию и прислать нам свой отзыв.

Автор: Гэй Онкул Кок  •  Иcточник: MSDN Magazine  •  Опубликована: 25.04.2014
Нашли ошибку в тексте? Сообщите о ней автору: выделите мышкой и нажмите CTRL + ENTER
Теги:   .NET Framework 4.5.1.


Оценить статью:
Вверх
Комментарии посетителей
Комментарии отключены. С вопросами по статьям обращайтесь в форум.