Участок обработки исключений что это

Обновлено: 05.10.2024

Пример скриншотов для доказательства

Вот одно из адекватных обьяснений статуса POD (вручение ) Некоторые сервисы отслеживания так интерпритируют статусы служб доставки, хотя там по факту имеется ввиду совсем другое.
Например, одна служба доставки передаёт другой, у другой так себе отслеживание или нет вообще. Первая ставит что-то на китайском типа "Передана перевозчику", а трекер интерпретирует это Proof of Delivery (POD) - Подтверждение доставки.
В общем это перевод статусов, связанных с последней милей настоящего перевозчика. По опыту это обычно статусы у коммерческих перевозчиков последней мили, т.е. перевозчиков в стране назначения.

Надо открывать обоснованный спор, почта здесь не причем, консолидацией занимается сам AliExpress. Приложите вес и фотографии посылок. Продавец конечно будет писать, что спор открывать не нужно, ему тогда деньги переведут.

Спасибо за информацию. У меня скриншот практически точная копия скрина из примера. Мне и в голову не пришло, что это посылка могла назад вернуться. Буду писать письма для начала, а то посмотрим.
Еще раз спасибо

Exception parcel handling in sorting center, на другом сайте об отслеживании тот же статус но с пометкой "Return". На третьем сайте написано "Посылка возвращена". Кому верить? Возврат я не просил, продавец пишет что не волнуйтесь, будьте терпеливы, информация о логистике в данный момент обновляется долго и все в этом роде. Хз что делать, возвращать деньги? Если да то как грамотно это сделать? Трек: LC181421785CN

Руслан У меня тоже самое, только заказ был сделан 12.07, последний раз трекнулась 15.07 - Отправление покинуло офис Yanwen.

Так же продавец пишет что проблема с логистикой.

Я жду а что делать - продавец отправил.

А по поводу возвратов - Вы всё одно не сможете ничего сделать пока не пройдёт 90 дней - сейчас они увеличили в связи с Covid.

Если быть точнее - кнопка открыть спор есть, при нажатии или Вы выбираете (получил) - но Вы же не получали, или не получил - но тогда других действий не предусмотрено - предлагают ждать пока не пройдёт энное количество дней.

Так что терпеливо ждём.

Руслан Тоже посылка была развернута доставкой. Тоже мучился открывать спор или нет. Правда у меня посылка сразу в день отправления получила статус "Exception parcel handling in sorting center". Потом через некоторое время "Parcel is returning to sender, please contact the carrier." С момента отправки продавцом прошло всего неделя. Всю эту неделю питался договорится с продавцом. Система мне спокойно позволила открыть спор. Открыл спор, Причина спора: Транспортная компания вернула заказ. Решение было принято сразу, так как сразу был привлечен Али и спор сразу обострен. Это автоматом срабатывает если служба доставки сам Али.

Я бы вам посоветовал дождаться следующего статуса или недельку.

Romadobrii Посылка вернулась обратно к продавану, договорился с ним чтобы он отправил еще раз. Сам он ссылался на то что была проблема с проверкой авиационной безопасности, хз верить ему или нет, но суть в том что он отправил сейчас(или не отправил) повторно но уже доставкой Yanwen и дал трек код: VR339382975YP. Так вот сейчас Тип отправления обозначается как письмо с объявленной ценностью. До этого было - регистрируемое почтовое отправление. Кто может объяснить в чем разница?

Ищите ответ на этот вопрос? Знаете кого-нибудь, кто может ответить на него? Поделитесь ссылкой на этот вопрос в Facebook, Twitter, ВКонтакте, по электронной почте и т.д.

Обработка исключений в Java - непростая тема. Новичкам сложно понять, и даже опытные разработчики могут часами обсуждать, как и какие исключения следует создавать или обрабатывать.

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

Тем не менее, есть несколько передовых практик, которые используются большинством команд. Вот 9 самых важных из них, которые помогут вам начать работу или улучшить обработку исключений.

1. Освободите ресурсы в блоке finally или используйте инструкцию "Try-With-Resource"

Довольно часто вы используете ресурс в своем блоке try, например InputStream, который вам нужно закрыть позже. Распространенной ошибкой в ​​таких ситуациях является закрытие ресурса в конце блока try.

Проблема в том, что этот подход работает отлично до тех пор, пока не генерируется исключение. Все операторы в блоке try будут выполнены, и ресурс будет закрыт.

Но вы не зря добавили блок try. Вы вызываете один или несколько методов, которые могут вызвать исключение, или, может быть, вы сами вызываете исключение. Это означает, что вы можете не дойти до конца блока try. И как следствие, вы не закроете ресурсы.

Поэтому вам следует поместить весь код очистки в блок finally или использовать оператор try-with-resource.

Используйте блок Finally

В отличие от последних нескольких строк вашего блока try, блок finally всегда выполняется. Это происходит либо после успешного выполнения блока try, либо после обработки исключения в блоке catch. Благодаря этому вы можете быть уверены, что освободите все захваченные ресурсы.

Оператор Java 7 "Try-With-Resource"

Другой вариант - это оператор try-with-resource, который я объяснил более подробно во введении в обработку исключений Java.

Вы можете использовать его, если ваш ресурс реализует интерфейс AutoCloseable. Это то, что делает большинство стандартных ресурсов Java. Когда вы открываете ресурс в предложении try, он автоматически закрывается после выполнения блока try или обработки исключения.

2. Конкретные исключения предпочтительнее

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

Поэтому постарайтесь предоставить им как можно больше информации. Это упрощает понимание вашего API. В результате вызывающий ваш метод сможет лучше обработать исключение или избежать его с помощью дополнительной проверки.

Поэтому всегда старайтесь найти класс, который лучше всего подходит для вашего исключительного события, например, генерируйте NumberFormatException вместо IllegalArgumentException. И избегайте создания неспецифического исключения.

3. Документируйте определенные вами исключения

Каждый раз, когда вы определяете исключение в сигнатуре вашего метода, вы также должны задокументировать его в своем Javadoc. Это преследует ту же цель, что и предыдущая передовая практика: предоставить вызывающему как можно больше информации, чтобы он мог избежать или обработать исключение.

Итак, не забудьте добавить объявление @throws в свой Javadoc и описать ситуации, которые могут вызвать исключение.

Следовательно, он должен как можно точнее описать проблему и предоставить наиболее актуальную информацию для понимания исключительного события.

Не поймите меня неправильно; вы не должны писать абзац текста. Но вам следует объяснить причину исключения в 1-2 коротких предложениях. Это помогает вашей группе эксплуатации понять серьезность проблемы, а также упрощает анализ любых инцидентов, связанных с обслуживанием.

Если вы выберете конкретное исключение, его имя класса, скорее всего, уже будет описывать тип ошибки. Таким образом, вам не нужно предоставлять много дополнительной информации. Хорошим примером этого является NumberFormatException. Оно вызывается конструктором класса java.lang.Long, когда вы предоставляете String в неправильном формате.

5. Сначала перехватите наиболее конкретное исключение

Большинство IDE помогут вам в этой лучшей практике. Они сообщают о недостижимом блоке кода, когда вы сначала пытаетесь перехватить менее конкретное исключение.

Проблема в том, что выполняется только первый блок catch, соответствующий исключению. Итак, если вы сначала поймаете IllegalArgumentException, вы никогда не достигнете блока catch, который должен обрабатывать более конкретное NumberFormatException, потому что это подкласс IllegalArgumentException.

Всегда сначала перехватывайте наиболее конкретный класс исключения и добавляйте менее конкретные блоки перехвата в конец вашего списка.

Пример такого оператора try-catch представлен в следующем фрагменте кода. Первый блок catch обрабатывает все NumberFormatException, а второй - все IllegalArgumentException, которые не являются NumberFormatException.

6. Не перехватывайте Throwable

Throwable - это суперкласс всех исключений и ошибок. Вы можете использовать его в предложении catch, но никогда не должны этого делать!

Если вы используете Throwable в предложении catch, он не только перехватит все исключения; он также перехватит все ошибки. JVM выдает ошибки, чтобы указать на серьезные проблемы, которые не предназначены для обработки приложением. Типичными примерами этого являются OutOfMemoryError или StackOverflowError. И то, и другое вызвано ситуациями, которые находятся вне контроля приложения и не могут быть обработаны.

Итак, лучше не перехватывайте Throwable, если вы не абсолютно уверены, что находитесь в исключительной ситуации, в которой вы можете или обязаны обрабатывать ошибку.

7. Не игнорируйте исключения

Вы когда-нибудь анализировали отчет об ошибке, в котором выполнялась только первая часть вашего сценария использования?

Что ж, возможно, вы анализируете проблему, в которой произошло невозможное.

Поэтому, пожалуйста, никогда не игнорируйте исключения. Вы не знаете, как код изменится в будущем. Кто-то может удалить проверку, которая предотвратила исключительное событие, не осознавая, что это создает проблему. Или код, который генерирует исключение, изменяется и теперь генерирует несколько исключений одного и того же класса, а вызывающий код не предотвращает их все.

8. Не пишите в лог сгенерированные исключения

Это, вероятно, наиболее часто игнорируемая передовая практика в списке. Вы можете найти множество фрагментов кода и даже библиотек, в которых исключение перехватывается, регистрируется и повторно генерируется.

Если вам нужно добавить дополнительную информацию, вы должны перехватить исключение и обернуть его в пользовательское. Но обязательно следуйте передовой практике номер 9.

Итак, перехватывайте исключение, только если вы хотите его обработать. В противном случае укажите это в сигнатуре метода и позвольте вызывающей стороне позаботиться об этом.

9. Оберните исключение, не обрабатывая его

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

Резюме

Как вы видели, есть много разных вещей, которые вы должны учитывать, когда генерируете или перехватываете исключение. Большинство из них имеют цель улучшить читаемость вашего кода или удобство использования вашего API.

Чаще всего исключения являются одновременно механизмом обработки ошибок и средством связи. Поэтому вам следует обязательно обсудить передовые практики и правила, которые вы хотите применять, со своими коллегами, чтобы все понимали общие концепции и использовали их одинаково.

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

Библиотека Microsoft Foundation Class использует схему обработки исключений, которая моделируется в тесном соответствии с предложенным Комитетом по стандартам ANSI для C++. Перед вызовом функции, которая может столкнуться с аномальной ситуацией, необходимо настроить обработчик исключений. Если функция обнаруживает аномальное состояние, она вызывает исключение, и управление передается обработчику исключений.

Несколько макросов, входящих в библиотека Microsoft Foundation Class, настроили обработчики исключений. Ряд других глобальных функций помогает создавать специализированные исключения и завершать программы при необходимости. Эти макросы и глобальные функции делятся на следующие категории:

Макросы исключений, которые представляют собой структуру обработчика исключений.

Функции, создающие исключения), которые создают исключения конкретных типов.

Функции завершения, которые вызывают завершение программы.

Примеры и дополнительные сведения см. в статье исключения.

Макросы исключений

name Описание
Повторите Обозначает блок кода для обработки исключений.
CATCH Обозначает блок кода для перехвата исключения из предыдущего блока try .
CATCH_ALL Обозначает блок кода для перехвата всех исключений из предыдущего блока try .
AND_CATCH Обозначает блок кода для перехвата дополнительных типов исключений из предыдущего блока try .
AND_CATCH_ALL Обозначает блок кода для перехвата всех других дополнительных типов исключений, созданных в предыдущем блоке try .
END_CATCH Завершает последний блок кода catch или AND_CATCH .
END_CATCH_ALL Завершает последний блок кода CATCH_ALL .
THROW Создает указанное исключение.
THROW_LAST Создает текущее обработанное исключение для следующего внешнего обработчика.

Функции Exception-Throwing

name Описание
AfxThrowArchiveException Создает исключение архива.
AfxThrowFileException Вызывает исключение файла.
AfxThrowInvalidArgException Вызывает исключение недопустимого аргумента.
AfxThrowMemoryException Вызывает исключение памяти.
AfxThrowNotSupportedException Вызывает исключение "не поддерживается".
AfxThrowResourceException вызывает исключение Windows ресурс — не найдено.
AfxThrowUserException Создает исключение в действии, инициированном пользователем.

MFC предоставляет две функции генерации исключений, специально предназначенные для исключений OLE:

Функции исключений OLE

name Описание
AfxThrowOleDispatchException Создает исключение в функции OLE Automation.
AfxThrowOleException Вызывает исключение OLE.

Для поддержки исключений баз данных классы баз данных предоставляют два класса исключений, CDBException и и CDaoException глобальные функции для поддержки типов исключений:

Функции исключений DAO

name Описание
афкссровдаоексцептион Создает исключение кдаоексцептион из собственного кода.
AfxThrowDBException Создает исключение кдбексцептион из собственного кода.

MFC предоставляет следующую функцию завершения:

Функции завершения

name Описание
AfxAbort Вызывается для завершения работы приложения при возникновении неустранимой ошибки.

Настраивает блок try .

Комментарии

Блок try определяет блок кода, который может вызывать исключения. Эти исключения обрабатываются в следующих блоках catch и AND_CATCH . Рекурсия разрешена: исключения могут передаваться во внешний блок try либо путем их пропуска, либо с помощью макроса THROW_LAST. Завершите блок try с помощью макроса END_CATCH или END_CATCH_ALL.

Дополнительные сведения см. в статье исключения.

Пример

Требования

CATCH

Определяет блок кода, который перехватывает первый тип исключения, вызванный в предыдущем блоке try .

Параметры

exception_class
Указывает тип исключения для проверки. Список стандартных классов исключений см. в разделе Class CException.

exception_object_pointer_name
Задает имя для указателя на объект Exception, который будет создан с помощью макроса. Для доступа к объекту исключения в блоке catch можно использовать имя указателя. Эта переменная объявлена для вас.

Комментарии

Код обработки исключений может опрашивать объект исключения, если это уместно, чтобы получить дополнительные сведения о конкретной причине исключения. Вызов макроса THROW_LAST для сдвига обработки на следующий внешний кадр исключения. Завершите блок try с помощью макроса END_CATCH.

Если exception_class является классом , будут перехвачены все типы исключений. Чтобы определить, какое конкретное исключение было создано, можно использовать функцию члена CObject:: IsKindOf . Более эффективным способом перехвата нескольких видов исключений является использование последовательных AND_CATCH инструкций, каждый из которых имеет свой тип исключения.

Указатель объекта исключения создается с помощью макроса. Вам не нужно объявлять его самостоятельно.

Блок catch определяется как область C++, разделенная фигурными скобками. Если объявить переменные в этой области, они будут доступны только в пределах этой области. Это также относится к exception_object_pointer_name.

Дополнительные сведения об исключениях и макросе CATCH см. в статье исключения.

Пример

CATCH_ALL

Определяет блок кода, который перехватывает все типы исключений, созданные в предыдущем блоке try .

Параметры

exception_object_pointer_name
Задает имя для указателя на объект Exception, который будет создан с помощью макроса. Для доступа к объекту исключения в блоке можно использовать имя указателя CATCH_ALL . Эта переменная объявлена для вас.

Комментарии

Код обработки исключений может опрашивать объект исключения, если это уместно, чтобы получить дополнительные сведения о конкретной причине исключения. Вызов THROW_LAST макроса для сдвига обработки на следующий внешний кадр исключения. Если вы используете CATCH_ALL, завершите блок try с помощью макроса END_CATCH_ALL.

Блок CATCH_ALL определяется как область C++, разделенная фигурными скобками. Если объявить переменные в этой области, они будут доступны только в пределах этой области.

Дополнительные сведения об исключениях см. в статье исключения.

Пример

Требования

Заголовок AFX. h

AND_CATCH

Определяет блок кода для перехвата дополнительных типов исключений, создаваемых в предыдущем блоке try .

Параметры

exception_class
Указывает тип исключения для проверки. Список стандартных классов исключений см. в разделе Class CException.

exception_object_pointer_name
Имя для указателя на объект Exception, который будет создан с помощью макроса. Для доступа к объекту исключения в блоке AND_CATCH можно использовать имя указателя. Эта переменная объявлена для вас.

Комментарии

Используйте макрос CATCH для перехвата одного типа исключения, а затем макрос AND_CATCH для перехвата каждого последующего типа. Завершите блок try с помощью макроса END_CATCH.

Код обработки исключений может опрашивать объект исключения, если это уместно, чтобы получить дополнительные сведения о конкретной причине исключения. Вызовите макрос THROW_LAST в блоке AND_CATCH , чтобы сдвинуть обработку на следующий внешний кадр исключения. AND_CATCH помечает конец предыдущего блока catch или AND_CATCH .

Блок AND_CATCH определяется как область C++ (разделенная фигурными скобками). При объявлении переменных в этой области Помните, что они доступны только в пределах этой области. Это также относится к переменной exception_object_pointer_name .

Пример

Требования

Заголовок AFX. h

AND_CATCH_ALL

Определяет блок кода для перехвата дополнительных типов исключений, создаваемых в предыдущем блоке try .

Параметры

exception_object_pointer_name
Имя для указателя на объект Exception, который будет создан с помощью макроса. Для доступа к объекту исключения в блоке AND_CATCH_ALL можно использовать имя указателя. Эта переменная объявлена для вас.

Комментарии

Используйте макрос catch для перехвата одного типа исключения, а затем макрос AND_CATCH_ALL для перехвата всех остальных последующих типов. Если вы используете AND_CATCH_ALL, завершите блок try с помощью макроса END_CATCH_ALL.

Код обработки исключений может опрашивать объект исключения, если это уместно, чтобы получить дополнительные сведения о конкретной причине исключения. Вызовите макрос THROW_LAST в блоке AND_CATCH_ALL , чтобы сдвинуть обработку на следующий внешний кадр исключения. AND_CATCH_ALL помечает конец предыдущего блока catch или AND_CATCH_ALL .

Блок AND_CATCH_ALL определяется как область C++ (разделенная фигурными скобками). При объявлении переменных в этой области Помните, что они доступны только в пределах этой области.

Требования

Заголовок AFX. h

END_CATCH

Помечает конец последнего блока catch или AND_CATCH .

Комментарии

Дополнительные сведения о макросе END_CATCH см. в статье исключения.

Требования

Заголовок AFX. h

END_CATCH_ALL

Помечает конец последнего CATCH_ALL88 или AND_CATCH_ALL блока.

Требования

Заголовок AFX. h

THROW (MFC)

Создает указанное исключение.

Параметры

exception_object_pointer
Указывает на объект исключения, производный от CException .

Комментарии

Дополнительные сведения см. в статье исключения.

Требования

Заголовок AFX. h

THROW_LAST

Вызывает исключение обратно в следующий внешний блок catch .

Комментарии

Этот макрос позволяет создавать локально созданное исключение. При попытке вызвать исключение, которое было только что перехвачено, оно обычно выходит из области и удаляется. При использовании THROW_LASTисключение передается правильно в следующий обработчик catch .

Дополнительные сведения см. в статье исключения.

Пример

Требования

Заголовок AFX. h

AfxThrowArchiveException

Создает исключение архива.

Параметры

cause
Задает целое число, указывающее причину исключения. Список возможных значений см. в разделе карчивиксцептион:: m_cause.

лпсзарчивенаме
Указывает на строку, содержащую имя CArchive объекта, вызвавшего исключение (если доступно).

Требования

Заголовок AFX. h

AfxThrowFileException

Вызывает исключение файла.

Параметры

cause
Задает целое число, указывающее причину исключения. Список возможных значений см. в разделе кфиликсцептион:: m_cause.

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

лпсзфиленаме
Указывает на строку, содержащую имя файла, вызвавшего исключение (если доступно).

Комментарии

Вы несете ответственность за определение причины на основе кода ошибки операционной системы.

Требования

Заголовок AFX. h

AfxThrowInvalidArgException

Вызывает исключение недопустимого аргумента.

Синтаксис

Примечания

Эта функция вызывается, когда используются недопустимые аргументы.

Требования

Заголовок: AFX. h

AfxThrowMemoryException

Вызывает исключение памяти.

Комментарии

вызывайте эту функцию, если вызовы к базовым распределителям памяти системы (например, malloc и функция GlobalAlloc Windows) завершаются сбоем. Вам не нужно вызывать его для, new так как new в случае сбоя выделения памяти будет автоматически вызывать исключение памяти.

Требования

Заголовок AFX. h

AfxThrowNotSupportedException

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

Требования

Заголовок AFX. h

AfxThrowResourceException

Вызывает исключение ресурса.

Комментарии

эта функция обычно вызывается, когда не удается загрузить Windows ресурс.

Требования

Заголовок AFX. h

AfxThrowUserException

Создает исключение для завершения операции пользователя.

Комментарии

Эта функция обычно вызывается сразу после того, как AfxMessageBox пользователь сообщил об ошибке.

Требования

Заголовок AFX. h

AfxThrowOleDispatchException

Эта функция используется для создания исключения в функции OLE Automation.

Параметры

wCode
Код ошибки, относящийся к вашему приложению.

лпсздескриптион
Описание ошибки текстовом.

ндескриптионид
Идентификатор ресурса для описания ошибки текстовом.

нхелпид
Контекст справки для справки вашего приложения (. Файл HLP).

Комментарии

сведения, предоставленные этой функции, могут отображаться в приложении, управляющем приложением (Microsoft Visual Basic или другом клиентском приложении OLE-автоматизации).

Пример

Требования

Заголовок AFX. h

AfxThrowOleException

Создает объект типа COleException и создает исключение.

Параметры

SC
Код состояния OLE, указывающий причину исключения.

ч
Обрабатывает код результата, указывающий причину исключения.

Комментарии

Версия, принимающая HRESULT в качестве аргумента, преобразует этот код результата в соответствующий SCODE. дополнительные сведения о HRESULT и SCODE см. в разделе структура кодов ошибок COM в Windows SDK.

Требования

Заголовок афксдао. h

AfxThrowDaoException

Вызовите эту функцию, чтобы вызвать исключение типа кдаоексцептион из собственного кода.

Параметры

нафксдаоеррор
Целочисленное значение, представляющее расширенный код ошибки DAO, который может быть одним из значений, перечисленных в разделе кдаоексцептион:: m_nAfxDaoError.

SCODE
Код ошибки OLE из DAO типа SCODE. Дополнительные сведения см. в разделе кдаоексцептион:: m_scode.

Комментарии

Платформа также вызывает AfxThrowDaoException . В вызове можно передать один из параметров или оба. Например, если вы хотите вызвать одну из ошибок, определенных в кдаоексцептион:: нафксдаоеррор , но не волнует параметр SCODE , передайте допустимый код в параметр нафксдаоеррор и примите значение по умолчанию для SCODE.

Сведения об исключениях, связанных с классами MFC DAO, см CDaoException . в разделе класс в этой книге, а в статье CDaoException .

Требования

Заголовок афксдб. h

AfxThrowDBException

Вызовите эту функцию, чтобы создать исключение типа CDBException из собственного кода.

Параметры

нреткоде
Значение типа РЕТКОДЕ, определяющее тип ошибки, вызвавшей исключение.

файле
Указатель на CDatabase объект, представляющий соединение с источником данных, с которым связано исключение.

hstmt
Обработчик ODBC ХСТМТ, указывающий маркер инструкции, с которым связано исключение.

Комментарии

Платформа вызывается AfxThrowDBException при получении РЕТКОДЕ ODBC из вызова функции API ODBC и ИНТЕРПРЕТИРУЕТ реткоде как исключительную ситуацию, а не как предполагаемую ошибку. Например, операция доступа к данным может завершиться ошибкой из-за ошибки чтения с диска.

Требования

Заголовок AFX. h

AfxAbort

Функция завершения по умолчанию, предоставляемая MFC.

Комментарии

AfxAbort вызывается внутренне функциями-членами MFC при возникновении неустранимой ошибки, например неперехваченного исключения, которое не может быть обработано. Можно вызвать AfxAbort в редких случаях, когда возникает фатальная ошибка, из-за которой невозможно выполнить восстановление.

Читайте также: