Главная страница

Ссылки на материал для ревью. 1 Ревью. Примитивные типы


Скачать 72.95 Kb.
Название1 Ревью. Примитивные типы
АнкорСсылки на материал для ревью
Дата20.04.2022
Размер72.95 Kb.
Формат файлаdocx
Имя файлаSsylki_na_material_dlya_revyu.docx
ТипДокументы
#487632
страница2 из 4
1   2   3   4


4 Ревью. Ввод-вывод, доступ к файловой системе

Ввод-вывод, доступ к файловой системе

1) Какие существуют виды потоков ввода/вывода? - Разделяют два вида потоков ввода/вывода: байтовые и символьные. Система ввода/вывода: http://developer.alexanderklimov.ru/android/java/io.php

2) Назовите основные предки потоков ввода/вывода - Байтовые: java.io.InputStream, java.io.OutputStream; Символьные: java.io.Reader, java.io.Writer;

3) Что общего и чем отличаются следующие потоки: InputStream, OutputStream, Reader, Writer? – Базовый класс InputStream представляет классы, которые получают данные из различных источников:- массив байтов- строка (String)- файл- канал (pipe): данные помещаются с одного конца и извлекаются с другого- последовательность различных потоков, которые можно объединить в одном потоке- другие источники (например, подключение к интернету). Класс OutputStream - это абстрактный класс, определяющий потоковый байтовый вывод. В этой категории находятся классы, определяющие, куда направляются ваши данные: в массив байтов (но не напрямую в String; предполагается что вы сможете создать их из массива байтов), в файл или канал. Символьные потоки имеют два основных абстрактных класса Reader и Writer, управляющие потоками символов Unicode. Класс Reader - абстрактный класс, определяющий символьный потоковый ввод. Класс Writer - абстрактный класс, определяющий символьный потоковый вывод. В случае ошибок все методы класса передают исключение IOException.

4) Что вы знаете о RandomAccessFile? - Класс RandomAccessFile наследуется напрямую от Object и не наследуется от вышеприведенных базовых классов ввода\вывода. Предназначен для работы с файлами, поддерживая произвольный доступ к их содержимому. Работа с классом RandomAccessFile напоминает использование совмещенных в одном классе потоков DataInputStream и DataOutputStream (они реализуют те же интерфейсы DataInput и DataOutput). Кроме того, метод seek() позволяет переместиться к определенной позиции и изменить хранящееся там значение. При использовании RandomAccessFile необходимо знать структуру файла. Класс RandomAccessFile содержит методы для чтения и записи примитивов и строк UTF-8.

5) Какие есть режимы доступа к файлу? - RandomAccessFile может открываться в режиме чтения ("r") или чтения/записи ("rw"). Также есть режим "rws", когда файл открывается для операций чтения-записи и каждое изменение данных файла немедленно записывается на физическое устройство.

6) В каких пакетах лежат классы-потоки? -Классы потоков ввода\вывода лежат в java.io; С JDK 7 добавлен более современный способ работы с потоками - Java NIO. Классы лежат в java.nio. Для работы с архивами используются классы из пакета java.util.

7) Что вы знаете о классах-надстройках? - Классы-надстройки наделяют существующий поток дополнительными свойствами. Примеры классов: BufferedOutputStream, BufferedInputStream, BufferedWriter - буферизируют поток и повышают производительность.

8) Какой класс-надстройка позволяет читать данные из входного байтового потока в формате примитивных типов данных? - Для чтения байтовых данных (не строк) применяется класс DataInputStream. В этом случае необходимо использовать классы из группы InputStream. Для преобразования строки в массив байтов, пригодный для помещения в поток ByteArrayInputStream, в классе String предусмотрен метод getBytes(). Полученный ByteArrayInputStream представляет собой поток InputStream, подходящий для передачи DataInputStream. При побайтовом чтении символов из форматированного потока DataInputStream методом readByte() любое полученное значение будет считаться действительным, поэтому возвращаемое значение неприменимо для идентификации конца потока. Вместо этого можно использовать метод available(), который сообщает, сколько еще осталось символов. Класс DataInputStream позволяет читать элементарные данные из потока через интерфейс DataInput, который определяет методы, преобразующие элементарные значения в форму последовательности байтов. Такие потоки облегчают сохранение в файле двоичных данных. Конструктор: DataInputStream(InputStream stream)Методы: readDouble(), readBoolean(), readInt()

9) Какой класс-надстройка позволяет ускорить чтение/запись за счет использования буфера? - Для этого используются классы, позволяющие буферизировать поток: BufferedInputStream(InputStream in) BufferedInputStream(InputStream in, int size) BufferedOutputStream(OutputStream out) BufferedOutputStream(OutputStream out, int size) BufferedReader(Reader r) BufferedReader(Reader in, int sz),java.io.BufferedWriter(Writer out) BufferedWriter(Writer out, int sz)

10) Какие классы позволяют преобразовать байтовые потоки в символьные и обратно? – 1) OutputStreamWriter - мост между классом OutputStream и классом Writer. Символы, записанные в поток, преобразовываются в байты. 2) InputStreamReader - аналог для чтения. При помощи методов класса Reader читаются байты из потока InputStream и далее преобразуются в символы. 2) Какой класс предназначен для работы с элементами файловой системы (ЭФС)? - В отличие от большинства классов ввода/вывода, класс File работает не с потоками, а непосредственно с файлами. Данный класс позволяет получить информацию о файле: права доступа, время и дата создания, путь к каталогу. А также осуществлять навигацию по иерархиям подкаталогов. Класс java.io.File может представлять имя определённого файла, а также имена группы файлов, находящихся в каталоге. Если класс представляет каталог, то его метод list() возвращает массив строк с именами всех файлов. Для создания объектов класса File можно использовать один из следующих конструкторов: File(File dir, String name) - указывается объект класса File (каталог) и имя файла File(String path) - указывается путь к файлу без указания имени файла File(String dirPath, String name) - указывается путь к файлу и имя файла File(URI uri) - указывается объекта URI, описывающий файл

12) Какой символ является разделителем при указании пути к ЭФС? - Для различных систем символ разделителя различается. Вытащить его можно используя file.separator, а так же в статическом поле File.separator. Для Windows это '\'.*На stackoverflow встречал утверждение со ссылкой на документацию, что можно безопасно использовать слэш '/' для всех систем. В комментарии читатель подтвердил это.

13) Что вы знаете об интерфейсе FilenameFilter? - Интерфейс FilenameFilter применяется для проверки попадает ли объект File под некоторое условие. Этот интерфейс содержит единственный метод boolean accept(File pathName). Этот метод необходимо переопределить и реализовать.

14) Что такое сериализация? - Сериализация это процесс сохранения состояния объекта в последовательность байт; десериализация это процесс восстановления объекта, из этих байт. Java Serialization API предоставляет стандартный механизм для создания сериализуемых объектов. Сериализация в Java: http://habrahabr.ru/post/60317/ Изучите секреты Java Serialization API: http://www.ccfit.nsu.ru/

deviv/courses/oop/java_ser_rus.html Как работает сериализация в Java (info.javarush.ru): http://goo.gl/K8GzJl

15) Какие условия "благополучной" сериализации объекта? - Чтобы обладать способностью к сериализации, класс должен реализовывать интерфейс-метку Serializable. Так же все атрибуты и подтипы сериализуемого класса должны быть сериализуемы. Если класс предок был несереализуемым, то этот суперкласс должен содержать доступный (public, protected) конструктор без параметров для инициализации полей.

16) Какие классы позволяют архивировать объекты? - DeflaterOutputStream, InflaterInputStream, ZipInputStream, ZipOutputStream, GZIPInputStream, GZIPOutputStream. Пример из http://www.concretepage.com/java/how_to_zip_file_java

17) Основные отличия между Java IO и Java NIO – IO 1) Блокирующий ввод-вывод Потоки ввода/вывода (streams) в Java IO являются блокирующими. Это значит, что когда в потоке выполнения (tread) вызывается read() или write() метод любого класса из пакета java.io.*, происходит блокировка до тех пор, пока данные не будут считаны или записаны. Поток выполнения в данный момент не может делать ничего другого. 2) Потокоориентированный ввод-вывод. Потокоориентированный ввод/вывод подразумевает чтение/запись из потока/в поток одного или нескольких байт в единицу времени поочередно. Данная информация нигде не кэшируются. Таким образом, невозможно произвольно двигаться по потоку данных вперед или назад. Если вы хотите произвести подобные манипуляции, вам придется сначала кэшировать данные в буфере. NIO 1) Неблокирующий ввод-вывод Неблокирующий режим Java NIO позволяет запрашивать считанные данные из канала (channel) и получать только то, что доступно на данный момент, или вообще ничего, если доступных данных пока нет. Вместо того, чтобы оставаться заблокированным пока данные не станут доступными для считывания, поток выполнения может заняться чем-то другим. 2) Буфероориентированный ввод-вывод. Селекторы Селекторы в Java NIO позволяют одному потоку выполнения мониторить несколько каналов ввода. Вы можете зарегистрировать несколько каналов с селектором, а потом использовать один поток выполнения для обслуживания каналов, имеющих доступные для обработки данные, или для выбора каналов, готовых для записи.

18) В чем отличие Scanner от BufferedReader? - Scanner позволяет разобрать строку на составляющие (токены), с помощью различных разделителей. Он не синхронизирован и, также не выбрасывает исключения. BufferedReader предназначен для чтения потока символов с буферизацией.

19) Что делать, если одно из полей сериализовывать не нужно. - Это поле нужно пометить ключевым словом transient. И оно не будет сериализовано.

20) Как сериализовать объект класса? - Нужно пометить его маркерным классом Serializable

21) Какие форматы сериализации существуют?- 1. JSON 2. JavaScript Object Notation 3. XML 4. BinarySON - тот же JSON только в двоичном представлении. 5. YAML - Yet Another Markup Language

22) Cтандартные потоки ввода/вывода? - В языке Java стандартный поток ввода представлен переменной System.in. Эта переменная (объект) имеет тип InputStream. Класс InputStream есть абстрактный и размещается в вершине иерархии классов ввода. Стандартный поток вывода ассоциируется с переменной (объектом) System.out, тип которой PrintStream. Класс PrintStream содержит методы вывода на консоль print() и println().

23) Классы байтовых потоков ввода и что они делают? – Классы, которые реализуют байтовые потоки ввода унаследованы от абстрактного класса InputStream: InputStream - абстрактный класс, который описывает поток ввода. Данный класс есть базовым для всех других классов системы ввода; BufferedInputStream - класс, который описывает буферизованные поток ввода; ByteArrayInputStream - класс, который описывает поток ввода, читающий байты из массива; DataInputStream -класс, который реализует методы для чтения данных стандартных типов, определенных в Java (int, double, float и т.д.); FileInputStream - класс, который реализует поток ввода, который читает данные из файла; FilterInputStream - это реализация абстрактного класса InputStream; ObjectInputStream - класс, реализующий поток ввода объектов; PipedInputStream - класс, соответствующий каналу ввода; PushbackInputStream - класс, соответствующий потоку ввода, который поддерживает возврат одного байта обратно в поток ввода; SequenceInputStream - класс, который реализует поток ввода, состоящий из двух или более потоков ввода, данные из которых читаются поочередно.

24) Классы байтовых потоков вывода и что они делают?- Классы, которые реализуют байтовые потоки вывода унаследованы от абстрактного класса OutputStream: OutputStream - абстрактный класс, который описывает поток вывода. Все другие классы системы вывода есть подклассами класса OutputStream; BufferedOutputStream - класс, который имплементирует буферизованный поток вывода; ByteArrayOutputStream - класс, который реализует поток вывода, записывающий байты в массив; DataOutputStream - класс, который реализует поток вывода, содержащий методы для чтения данных стандартных типов, определенных в Java (int, float, double и т.п.); FileOutputStream - класс, который соответствует потоку вывода записывающему данные в файл; FilterOutputStream - класс, реализующий абстрактный класс OutputStream; ObjectOutputStream - класс, соответствующий потоку вывода объектов; PipedOutputStream - класс, который ассоциируется с каналом вывода; PrintStream - класс, который представляет собой поток вывода, содержащий методы print() и println().

25) Классы символьных потоков ввода и что они делают? – Reader - абстрактный класс, описывающий поток ввода символов. Этот класс есть суперклассом для всех нижеследующих подклассов; BufferedReader - класс, который описывает буферизованный поток ввода символов; CharArrayReader - класс, который реализует поток ввода, читающий символы из массива; FileReader - класс, который описывает поток ввода связанный с символьным файлом; FilterReader - класс, представляющий фильтрованный поток чтения; InputStreamReader - класс, который представляет собой поток ввода, превращающий байты в символы; LineNumberReader - класс, соответствующий потоку ввода, который подсчитывает строки; PipedReader - класс, который ассоциируется с каналом ввода; PushbackReader - класс, соответствующий потоку ввода, который позволяет возвращать символы обратно в поток ввода; StringReader - класс, который реализует поток ввода, читающий символы из строки.

26) Классы символьных потоков вывода и что они делают? – Writer - абстрактный класс, описывающий поток вывода символов. Все нижеследующие классы являются подклассами класса Writer; BufferedWriter - класс, который описывает буферизованный поток вывода символов; CharArrayWriter - класс, который соответствует потоку вывода, записывающему символы в массив; FileWriter - класс, который соответствует потоку вывода, записывающему символы в файл; FilterWriter - класс, реализующий фильтрованный поток записи; OutputStreamWriter - класс, реализующий средства преобразования символов в байты; PipedWriter - класс, который ассоциируется с каналом вывода; StringWriter - класс, который реализует поток вывода, записывающий символы в строку.

27) На каком паттерне основана иерархия потоков ввода/вывода? – Объекты классов Java, которые используются для ввода/вывода, для обеспечения необходимой функциональности наслаиваются друг на друга. Такая модель взаимодействия объектов поддерживается в паттерне «Декоратор». В этом паттерне при создании потока нужно использовать несколько объектов.

28) Как работает метод read()? – Метод read() - возвращает значение целого типа очередного символа, доступного во входном потоке; Метод read(byte arr) - метод для массового считывания данных, который считывает максимум байтов (не более arr.length) из потока, входящих данных в аргумент массива arr и возвращает фактическое количество байтов, считанных из потока;

29) Как сериализовать объект класса. – Класс должен имплементировать маркерный интерфейс Serializable. Создаем ObjectOutputStream и передаем ему OutputStream/

30) Как сериализовать статическое поле? – При стандартной сериализации поля, имеющие модификатор static, не сериализуются. Соответственно, после десериализации это поле значения не меняет. При использовании реализации Externalizable сериализовать и десериализовать статическое поле можно, но не рекомендуется этого делать, т.к. это может сопровождаться трудноуловимыми ошибками.

31) Можно ли сериализовать final поле? – Поля с модификатором final сериализуются как и обычные. За одним исключением - их невозможно десериализовать при использовании Externalizable, поскольку final-поля должны быть инициализированы в конструкторе, а после этого в readExternal изменить значение этого поля будет невозможно. Соответственно, если необходимо сериализовать объект с final-полем неоходимо использовать только стандартную сериализацию.

32) Клонирование Java – Java поддерживает два типа клонирования — поверхностное клонирование и глубокое клонирование. 1) В случае поверхностного клонирования создается новый объект, который имеет точную копию значений в исходном объекте. Метод clone () объекта обеспечивает поверхностное клонирование. В этом механизме клонирования объект копируется без содержащихся в нем объектов. Клон копирует только структуру верхнего уровня объекта, а не нижние уровни. 2) Существует так же второй вид клонирования объекта, который называется глубокое клонирование. Его используют в тех случаях, когда в клонируемом классе есть изменяемые объекты.

33) Что такое «каналы»? – Каналы (channels) - это логические (не физические) порталы, абстракции объектов более низкого уровня файловой системы (например, отображенные в памяти файлы и блокировки файлов), через которые осуществляется ввод/вывод данных, а буферы являются источниками или приёмниками этих переданных данных. При организации вывода, данные, которые необходимо отправить, помещаются в буфер, который затем передается в канал. При вводе, данные из канала помещаются в заранее предоставленный буфер. Каналы напоминают трубопроводы, по которым эффективно транспортируются данные между буферами байтов и сущностями по ту сторону каналов. Каналы - это шлюзы, которые позволяют получить доступ к сервисам ввода/вывода операционной системы с минимальными накладными расходами, а буферы - внутренние конечные точки этих шлюзов, используемые для передачи и приема данных. Потоки (streams) применительно к вводу/выводу и работе с файлами. – Абстракция, которая используется для чтения или записи информации (файлов, сокетов, текста консоли и т.д.).

34) Что делает метод read? Почему он возвращает int а не byte? Почему он не может возвращать byte? – Метод читает следующий байт из входящего потока. Когда метод ничего не может считать (конец потока), возвращается -1. Потому что нужно нужен такой тип, который может вместить 1 байт, плюс одно служебное значение -1 (обозначающее конец потока). Диапазон byte в Java лежит от -128 до 127, а возвращаемое значение метода read() лежит в диапазоне от 0 до 255.

35) Что вернет метод read(), если он считывает файл и ему встречается байт равный -1? - 255

36) Что такое клонирование? Как реализовано клонирование в Java? – В первую очередь необходимо реализовать интерфейс Cloneable. Если этого не сделать, при вызове метода clone() выбросится исключение CloneNotSupportedException. Интерфейс Cloneable является маркерным, то есть не имеет ни одного метода. Он показывает что объекты класса могут быть клонированы. Метод clone() является protected, поэтому класс может клонировать только собственные объекты. Для того, чтобы клонировать другие объекты, метод clone() нужно расширить до public. Пример клонирования: public User clone() { return (User) super.clone();}

37) Поверхностное и глубокое клонирование. – Поверхностное клонирование применяется только с примитивными полями. Глубокое с примитивными и ссылочными.

38) Чем отличается копирование от клонирования. Можно ли клонировать String, массив String. https://www.youtube.com/watch?v=TER05K_JGG8">https://www.youtube.com/watch?v=TER05K_JGG8 https://www.youtube.com/watch?v=mH1EJuyHvrQ">https://www.youtube.com/watch?v=mH1EJuyHvrQ

39) Как преобразовать считанные байты в символы? Какой класс для этого используется? – InputStreamReader; Массив.можно преобразовать обратно в строку с помощью конструктора «new String(byte[]) Метод «getBytes(charsetName)» класса String – преобразование char в byte

40) В чём отличие File от Path? Path, по большому счету, — это переработанный аналог класса File. Работать с ним значительно проще, чем с File. Во-первых, из него убрали многие утилитные (статические) методы, и перенесли их в класс Files. Во-вторых, в Path были упорядочены возвращаемые значения методов. В классе File методы возвращали то String, то boolean, то File — разобраться было непросто. Полезные методы Path getFileName() — возвращает имя файла из пути; getParent() — возвращает «родительскую» директорию по отношению к текущему пути (то есть ту директорию, которая находится выше по дереву каталогов); getRoot() — возвращает «корневую» директорию; то есть ту, которая находится на вершине дерева каталогов;

41) Почему важно закрывать потоки? Какие потоки можно не закрывать (не вызывать метод close())? - При закрытии потока освобождаются все выделенные для него ресурсы, например, файл. В случае, если поток окажется не закрыт, может происходить утечка памяти. Можно не закрывать промежуточные потоки, а закрыть только главные. Потоки имеют метод BaseStream. close() и реализуют AutoCloseable , но почти все экземпляры потока на самом деле не нужно закрывать после использования. Как правило, только потоки, источником которых является канал ввода-вывода

42) Что делает метод available()? - int available() - возвращает количество байтов ввода, доступные в данный момент для чтения

43) Можно ли использовать flush() для небуферизированного потока и что будет. Гарантируется ли запись данных в файл при вызове flush()? - вызов метода flush() гарантирует только то, что байты, ранее записанные в поток, передаются операционной системе для записи, но не гарантирует записи на диск. По идее ничего случиться не должно. https://qastack.ru/programming/2340106/what-is-the-purpose-of-flush-in-java-streams

44) На каком паттерне основана иерархия потоков ввода/вывода? – на паттерне Декоратор (англ. Decorator) — структурный шаблон проектирования, предназначенный для динамического подключения дополнительного поведения к объекту

45) Что возвращает перегруженный read. Какаое максимальное значение вернет? - int read() возвращает целочисленное представление следующего байта в потоке. Когда в потоке не останется доступных для чтения байтов, данный метод возвратит число -1. Максимальное значение 255

46) Для чего нужен Scanner? Что такое токен в Scanner? Отличие Scanner’a от BufferedReader’a? Есть ли у сканера буфер? – Класс Scanner используется для получения (считывания) данных введенных пользователем в виде String, byte, short, int, long, float, double. Сканер выполняет поиск токенов во входной строке. Токен (или маркер) представляет собой серию цифровых или буквенно-цифровых символов, которая заканчивается разделителем. Разделителем может быть символ табуляции, возврат каретки (перевод строки или же просто ‘Enter’), конец файла или пробел.Сканер неявно создает буфер, т.к. основан на интерфейсе Readable - и единственный метод в этом интерфейсе основан на буфере. Scanner работает медленно, но зато предоставляет очень широкий API с кучей удобных методов, а BufferedReader работает быстрее, потому что читает часть входных данных в буфер, откуда они быстрее читаются по частям, то есть обращение к консоли происходит реже.

47) Методы класса File? Как создать файл на компьютере с помощью java? Как удалить директорию с файлами. Что если в ней есть вложенные директории ? В чём отличие File от Path? – https://metanit.com/java/tutorial/6.11.php

48) Какие поля не сериализуются? При стандартной сериализации поля, имеющие модификатор static, не сериализуются. Соответственно, после десериализации это поле значения не меняет.

49) Что будет при сериализации объекта у которого есть поле и оно не Serializable? – 1) В таком случае код скомпилируется. 2) Но в рантайме при попытке сериализации , когда мы дойдем до этого поля и объекта, мы получим NotSerializableException.

50) Externalizable vs Serializable? - При записи Serializable класса весь контроль над сериализацией достается JVM. С помощью определения специальных методов можно кастомизировать его части. Метод readObject при этом обычно начинается с вызова стандартной части сериализации – ObjectInputStream.defaultReadObject(). Интерфейс Externalizable расширяет Serializable и добавляет методы записи и чтения writeExternal и readExternal. Входной и выходной потоки-аргументы в них представлены более абстрактно чем в специальных методах – интерфейсами ObjectInput и ObjectOutput. Этот интерфейс позволяет реализовать полностью свой механизм сериализации, стандартно запишется только идентификатор класса. Никакой автоматической работы с классом-родителем также не предусмотрено. Методы readObject и writeObject игнорируются. Ключевое слово transient эффекта на Externalizable не имеет. Externalizable объект в отличие от Serializable десерализуется не в обход конструктора, так что должен иметь конструктор без аргументов.

51) Какие интерфейсы реализует InputStream/ OutputStream/ Reader/ Writer? - Closeable, AutoCloseable

52) Пример адаптера и декоратора из IO? https://www.youtube.com/watch?v=iR0mHInZWM8&ab_channel=%D0%A3%D1%80%D0%BE%D0%BA%D0%B8Java">https://www.youtube.com/watch?v=iR0mHInZWM8&ab_channel=%D0%A3%D1%80%D0%BE%D0%BA%D0%B8Java Видео по вопросам выше: https://www.youtube.com/watch?v=6xDBbYe11HQ&ab_channel=ExtremeCode https://www.youtube.com/watch?v=PIQTi9pc6Eo&ab_channel=SourceCode https://www.youtube.com/watch?v=IWcVI1LVBZg&ab_channel=DmitryAfanasyev https://www.youtube.com/watch?v=j3I-jLGW8yU https://www.youtube.com/watch?v=Y2iB_DwdyfM https://www.youtube.com/watch?v=UGKG_GnvKgk&ab_channel=ITVDN https://www.youtube.com/watch?v=FWAQ3AW9vQM&ab_channel=Followthewhiterabbit https://www.youtube.com/watch?v=Kta6v6AqAWk&ab_channel=Followthewhiterabbit https://www.youtube.com/watch?v=hbEFNczpTyg&ab_channel=Java%D0%B4%D0%BB%D1%8F%D0%BD%D0%B0%D1%87%D0%B8%D0%BD%D0%B0%D1%8E%D1%89%D0%B8%D1%85 https://www.youtube.com/watch?v=VBpAdF3JATE https://www.youtube.com/watch?v=fiUS7cbfE_8&ab_channel=%D0%A3%D1%80%D0%BE%D0%BA%D0%B8Java https://www.youtube.com/watch?v=SYat2qqPtZQ https://www.youtube.com/watch?v=TER05K_JGG8 https://www.youtube.com/watch?v=mH1EJuyHvrQ https://www.youtube.com/watch?v=aHO60SmsfJA https://www.youtube.com/watch?v=rbbs8F3N0Wg https://www.youtube.com/watch?v=iR0mHInZWM8 https://www.youtube.com/watch?v=tUSohR-wIRI
1   2   3   4


написать администратору сайта