Jquery работа с файлами: Работа с файлами в JavaScript, Часть 1: Основы – Файловая система и JavaScript. Обработка файлов в браузере

HTML5 Files API | Чтение файлов

60

Веб-программирование --- HTML5 --- Чтение файлов

Возможность веб-хранилища поддерживается в HTML5 на хорошем уровне. Но это не единственный способ получения информации веб-страницами. В эту область понемногу вводится несколько других стандартов, направленных на выполнение разных типов задач хранения данных. Одним из таких стандартов является File API, который технически не входит в HTML5, но имеет хороший уровень поддержки на всех современных браузерах.

Судя по расплывчатому названию этого стандарта, может показаться, что это всеохватывающий стандарт для чтения и записи файлов на жесткий диск клиента. Но этот стандарт не настолько амбициозный или мощный. Он просто разрешает посетителю веб-сайта выбрать файл на своем жестком диске и передать его непосредственно коду JavaScript, исполняющемуся на просматриваемой веб-странице. Код может открыть этот файл и работать с его данными, будто это простой текст или что-то более сложное. Здесь ключевым аспектом является то обстоятельство, что файл передается непосредственно коду JavaScript. В отличие от обычной выгрузки файла, он никогда не отправляется на веб-сервер.

Также важно знать, что File API не может делать. Самое важное, что он не может изменять файлы или создавать новые файлы. Чтобы сохранить какие-либо данные, нужно прибегать к другому механизму, например данные можно отправить на веб-сервер посредством запроса XMLHttpRequest или же поместить их в локальное хранилище.

Судя по этому, можно подумать, что интерфейс File API менее полезен, чем локальное хранилище, и для большинства веб-сайтов это будет правильный вывод. Но этот стандарт приоткрывает дверь в область, в которую HTML раньше не входил, по крайней мере без помощи модулей расширений.

В настоящее время интерфейс File API является необходимой функциональностью для определенных типов специализированных приложений, но в будущем его возможности могут быть расширены, и важность его значительно возрастет. Например, будущие версии интерфейса могут позволять веб-страницам сохранять файлы на жесткий диск клиента при условии, что пользователь контролирует имя файла и место его сохранения, используя диалоговое окно "Сохранить как". Модули расширения, наподобие Flash, уже оснащены такой способностью.

Поддержка браузерами интерфейса File API

Интерфейс File API не имеет такой широкой поддержки, как веб-хранилище. Текущая браузерная поддержка этого интерфейса приводится в таблице ниже:

Поддержка браузерами интерфейса File API
Браузер IE Firefox Chrome Safari Opera Safari iOS Android
Минимальная версия 10 3.6 8 6 11.1 - 3

Эти браузеры почти наверняка не реализуют все возможности File API, т.к. некоторые части стандарта (для работы с большими объемами двоичных данных и "вырезания" порций данных) все еще находятся в процессе разработки.

Получение файла

Прежде чем интерфейс File API сможет что-либо сделать с файлом, ему нужно этот файл получить. Эту задачу можно выполнить тремя разными способами, но все они одинаковые в одном ключевом аспекте — веб-страница может получить файл только в том случае, если посетитель явно выберет и предоставит его веб-странице.

Способы получения файла следующие:

Посредством элемента <input>

Присвоив атрибуту type значение file, мы получим стандартное окно для закачивания файла. Но с помощью небольшого сценария JavaScript и File API этот файл можно открыть локально.

Посредством скрытого элемента <input>

Элемент <input> очень непривлекательный. Чтобы не обезображивать им свою страницу, его можно скрыть и создать более прилично выглядящую кнопку. Нажатие этой кнопки активирует JavaScript-код, вызывающий метод click() скрытого элемента <input>, который открывает стандартное диалоговое окно выбора файла.

Посредством метода drag and drop

Если браузер поддерживает этот метод, файл можно перетащить с рабочего стола или окна браузера и отпустить его в определенной о

jQuery для начинающих. Часть 3. AJAX / Habr


Представляю Вам третью статью из серии jQuery для начинающих. В этот раз я постараюсь рассказать о реализации AJAX запросов...

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

Примечание: Во всех примерах используется сокращенный вариант вызова jQuery методов, используя функцию $ (знак доллара)

jQuery(..).load

Начнем с самого простого — загрузка HTML кода в необходимый нам DOM элемент на странице. Для этой цели нам подойдет метод load. Данный метод может принимать следующие параметры:

  1. url запрашиваемой страницы
  2. передаваемые данные (необязательный параметр)
  3. функция которой будет скормлен результат (необязательный параметр)

Приведу пример JavaScript кода:
// по окончанию загрузки страницы
$(document).ready(function(){              
    // вешаем на клик по элементу с id = example-1
    $('#example-1').click(function(){
        // загрузку HTML кода из файла example.html
        $(this).load('ajax/example.html');       
    }) 
}); 

Пример подгружаемых данных (содержимое файла
example.html
):
Example<br/>
Data Loaded By AJAX<br/>
Bye-Bye

Пример работы

jQuery.ajax


Это самый основной метод, а все последующие методы лишь обертки для метода jQuery.ajax. У данного метода лишь один входной параметр — объект включающий в себя все настройки (выделены параметры которые стоит запомнить):
  • async — асинхронность запроса, по умолчанию true
  • cache — вкл/выкл кэширование данных браузером, по умолчанию true
  • contentType — по умолчанию «application/x-www-form-urlencoded»
  • data — передаваемые данные — строка иль объект
  • dataFilter — фильтр для входных данных
  • dataType — тип данных возвращаемых в callback функцию (xml, html, script, json, text, _default)
  • global — тригер — отвечает за использование глобальных AJAX Event'ов, по умолчанию true
  • ifModified — тригер — проверяет были ли изменения в ответе сервера, дабы не слать еще запрос, по умолчанию false
  • jsonp — переустановить имя callback функции для работы с JSONP (по умолчанию генерируется на лету)
  • processData — по умолчанию отправляемые данный заворачиваются в объект, и отправляются как «application/x-www-form-urlencoded», если надо иначе — отключаем
  • scriptCharset — кодировочка — актуально для JSONP и подгрузки JavaScript'ов
  • timeout — время таймаут в миллисекундах
  • type — GET либо POST
  • url — url запрашиваемой страницы

Локальные AJAX Event'ы:
  • beforeSend — срабатывает перед отправкой запроса
  • error — если произошла ошибка
  • success — если ошибок не возникло
  • complete — срабатывает по окончанию запроса

Для организации HTTP авторизации (О_о):
  • username — логин
  • password — пароль

Пример javaScript'а:
$.ajax({
    url: '/ajax/example.html',             // указываем URL и
    dataType : "json",                     // тип загружаемых данных
    success: function (data, textStatus) { // вешаем свой обработчик на функцию success
        $.each(data, function(i, val) {    // обрабатываем полученные данные
            /* ... */
        });
    }
});

jQuery.get


Загружает страницу, используя для передачи данных GET запрос. Может принимать следующие параметры:
  1. url запрашиваемой страницы
  2. передаваемые данные (необязательный параметр)
  3. callback функция, которой будет скормлен результат (необязательный параметр)
  4. тип данных возвращаемых в callback функцию (xml, html, script, json, text, _default)

jQuery.post


Данный метод аналогичен предыдущему, лишь передаваемые данные уйдут на сервер посредством POST'а. Может принимать следующие параметры:
  1. url запрашиваемой страницы
  2. передаваемые данные (необязательный параметр)
  3. callback функция, которой будет скормлен результат (необязательный параметр)
  4. тип данных возвращаемых в callback функцию (xml, html, script, json, text, _default)

JavaScript:

$(document).ready(function(){                          // по завершению загрузки страницы
    $('#example-3').click(function(){                  // вешаем на клик по элементу с id = example-3
        $.post('ajax/example.xml', {}, function(xml){  // загрузку XML из файла example.xml   
            $('#example-3').html('');
            $(xml).find('note').each(function(){       // заполняем DOM элемент данными из XML
                $('#example-3').append('To: '   + $(this).find('to').text() + '<br/>')
                               .append('From: ' + $(this).find('from').text() + '<br/>')
                               .append('<b>'    + $(this).find('heading').text() + '</b><br/>')
                               .append(           $(this).find('body').text() + '<br/>');
            });
        }, 'xml');                                     // указываем явно тип данных
    })
});

Файл example.xml:
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

Пример работы

jQuery.getJSON


Загружает данные в формате JSON (удобней и быстрее нежели XML). Может принимать следующие параметры:
  1. url запрашиваемой страницы
  2. передаваемые данные (необязательный параметр)
  3. callback функция, которой будет скормлен результат (необязательный параметр)

JavaScript:

$(document).ready(function(){                            // по завершению загрузки страницы
    $('#example-4').click(function(){                    // вешаем на клик по элементу с id = example-4
        $.getJSON('ajax/example.json', {}, function(json){  // загрузку JSON данных из файла example.json   
            $('#example-4').html('');
                                                         // заполняем DOM элемент данными из JSON объекта
            $('#example-4').append('To: '   + json.note.to + '<br/>')
                           .append('From: ' + json.note.from + '<br/>')
                           .append('<b>'    + json.note.heading + '</b><br/>')
                           .append(           json.note.body + '<br/>');
        });                
    })
});

Файл example.json:
{
    note:{
        to:'Tove',
        from:'Jani',
        heading:'Reminder',
        body:'Don\'t forget me this weekend!'
    }
}

Пример работы

jQuery.getScript


данная функция загружает и выполняет локальный JavaScript. Может принимать следующие параметры:
  1. url запрашиваемого скрипта
  2. callback функция, которой будет скормлен результат (необязательный параметр)

JavaScript:

$(document).ready(function(){                          // по завершению загрузки страницы
    $('#example-5').click(function(){                  // вешаем на клик по элементу с id = example-5
        $.getScript('ajax/example.js', function(){     // загрузку JavaScript'а из файла example.js 
            testAjax();                                // выполняем загруженный JavaScript
        });                
    })
});

Файл
example.js
:
function testAjax() {
    $('#example-5').html('Test completed');  // изменяем элемент с id = example-5
}

Пример работы

Отправка Формы


Для отправки формы посредством jQuery можно использовать любой из перечисленных способов, а вот для удобства «сбора» данных из формы лучше использовать плагин jQuery Form

Отправка Файлов


Для отправки файлов посредством jQuery можно использовать плагин Ajax File Upload иль One Click Upload

Взаимодействие с PHP


Для организации работы с PHP использую бибилотеку jQuery-PHP, удобно если Вам нравится jQuery ;), подробней читаем в статье PHP библиотека для jQuery

Примеры использования JSONP


Отдельно стоит отметить использование JSONP — ибо это один из способов осуществления кросс-доменной загрузки данных. Если немного утрировать — то это подключение удаленного JavaScript'a, содержащего необходимую нам информациию в формате JSON, а так же вызов нашей локальной функции, имя которой мы указываем при обращении к удаленному серверу (обычно это параметр callback). Чуть более наглядно это можно продемонстрировать следующая диаграмма (кликабельно):


При работе с jQuery имя callback функции генерируется автоматически для каждого обращения к удаленному серверу, для этого достаточно использовать GET запрос ввида:

http://api.domain.com/?type=jsonp&query=test&callback=?

Вместо последнего знака вопроса (?) будет подставлено имя callback функции. Если же Вы не хотите использовать данный способ, то Вам необходимо будет явно указать имя callback функции, используя опцию jsonp при вызове метода jQuery.ajax().

Google Поиск


Пример получения и обработки результатов поиска используя Google, более подробную информацию найдете в статье "jQuery + AJAX + (Google Search API || Yahoo Search API)"

Yahoo Поиск


Пример получения и обработки результатов поиска используя Yahoo, более подробную информацию найдете в статье "jQuery + AJAX + (Google Search API || Yahoo Search API)"

JSONP API


Приведу так же небольшой список открытых API с поддержкой JSONP:
  • Google — поиск и большинство сервисов
  • Yahoo — поиск и большинство сервисов
  • Flickr
  • MediaWiki — соответственно и все производные — Wikipedia, Wiktionary и т.д.
  • Digg
  • CNET
  • aideRSS

События


Для удобства разработки, на AJAX запросах висит несколько event'ов, их можно задавать для каждого AJAX запроса в отдельности, либо глобально. На все event'ы можно повесить свою функцию.

Пример для отображения элемента с id=«loading» во время выполнения любого AJAX запроса:

$("#loading").bind("ajaxSend", function(){
    $(this).show(); // показываем элемент
}).bind("ajaxComplete", function(){
    $(this).hide(); // скрываем элемент
});

Для локальных событий — вносим изменения в опции метода ajax():
$.ajax({
    beforeSend: function(){
        // Handle the beforeSend event
    },
    complete: function(){
        // Handle the complete event
    }
    // ...
});

Для большей наглядности, приведу следующую диаграмму (кликабельно):

Ну и собственно список всех event'ов:

  • ajaxStart — Данный метод вызывается в случае когда побежал AJAX запрос, и при этом других запросов нету
  • beforeSend — Срабатывает до отправки запроса, позволяет редактировать XMLHttpRequest. Локальное событие
  • ajaxSend — Срабатывает до отправки запроса, аналогично beforeSend
  • success — Срабатывает по возвращению ответа, когда нет ошибок ни сервера, ни вернувшихся данных. Локальное событие
  • ajaxSuccess — Срабатывает по возвращению ответа, аналогично success
  • error — Срабатывает в случае ошибки. Локальное событие
  • ajaxError — Срабатывает в случае ошибки
  • complete — Срабатывает по завершению текущего AJAX запроса (с ошибкои или без — срабатывает всегда).Локальное событие
  • ajaxComplete — Глобальное событие, аналогичное complete
  • ajaxStop — Данный метод вызывается в случае когда больше нету активных запросов

Так же Вы можете скачать все примеры в одном архиве.

Цикл статей


  1. jQuery для начинающих
  2. jQuery для начинающих. Часть 2. JavaScript Меню
  3. jQuery для начинающих. Часть 3. AJAX

P.S. Для подсветки синтаксиса использовал мини-сервис http://highlight.hohli.com/

jquery работа с файлами | Все о Windows 10

На чтение 4 мин. Просмотров 1 Опубликовано

Объект File наследуется от объекта Blob и обладает возможностями по взаимодействию с файловой системой.

Есть два способа его получить.

Во-первых, есть конструктор, похожий на Blob :

  • fileParts – массив значений Blob / BufferSource /строки.
  • fileName – имя файла, строка.
  • options – необязательный объект со свойством:
    • lastModified – дата последнего изменения в формате таймстамп (целое число).

Во-вторых, чаще всего мы получаем файл из или через перетаскивание с помощью мыши, или из других интерфейсов браузера. В этом случае файл получает эту информацию из ОС.

Так как File наследует от Blob , у объектов File есть те же свойства плюс:

  • name – имя файла,
  • lastModified – таймстамп для даты последнего изменения.

В этом примере мы получаем объект File из :

Через можно выбрать несколько файлов, поэтому input.files – псевдомассив выбранных файлов. Здесь у нас только один файл, поэтому мы просто берём input.files[0] .

FileReader

FileReader объект, цель которого читать данные из Blob (и, следовательно, из File тоже).

Данные передаются при помощи событий, так как чтение с диска может занять время.

  • readAsArrayBuffer(blob) – считать данные как ArrayBuffer
  • readAsText(blob, [encoding]) – считать данные как строку (кодировка по умолчанию: utf-8 )
  • readAsDataURL(blob) – считать данные как base64-кодированный URL.
  • abort() – отменить операцию.

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

  • readAsArrayBuffer – для бинарных файлов, для низкоуровневой побайтовой работы с бинарными данными. Для высокоуровневых операций у File есть свои методы, унаследованные от Blob , например, slice , мы можем вызвать их напрямую.
  • readAsText – для текстовых файлов, когда мы хотим получить строку.
  • readAsDataURL – когда мы хотим использовать данные в src для img или другого тега. Есть альтернатива – можно не читать файл, а вызвать URL.createObjectURL(file) , детали в главе Blob.

В процессе чтения происходят следующие события:

  • loadstart – чтение начато.
  • progress – срабатывает во время чтения данных.
  • load – нет ошибок, чтение окончено.
  • abort – вызван abort() .
  • error – произошла ошибка.
  • loadend – чтение завершено (успешно или нет).

Когда чтение закончено, мы сможем получить доступ к его результату следующим образом:

  • reader.result результат чтения (если оно успешно)
  • reader.error объект ошибки (при неудаче).

Наиболее часто используемые события – это, конечно же, load и error .

Как загружать любые файлы, например, картинки на сервер с помощью AJAX и jQuery? Делается это довольно просто! И ниже мы все обстоятельно разберем.

В те «древние» времена, когда еще не было jQuery, а может он был, но браузеры были не так наворочены, загрузка файла на сайт с помощью AJAX была делом муторным: через всякие костыли вроде iframe. Я те время не застал, да и кому это теперь интересно. А интересно теперь другое — что сохранение файлов на сайт делается очень просто. Даже не обладающий опытом и пониманием, того как работает AJAX, вебмастер, сможет быстро разобраться что-куда. А эта статья ему в помощь. Если подкрепить эти возможности функциями WordPress, то безопасная обработка и загрузка файлов на сервер становится совсем плевым и даже интересным делом (пример с WordPress смотрите в конце статьи).

Однако, как бы все просто не было, нужно заметить, что минимальный опыт работы с файлами и базовые знания в Javascript, jQuery и PHP все же необходимы! Минимум, нужно представлять как загружаются файлы на сервер, как в общих чертах работает AJAX и хоть немного надо уметь читать и понимать код.

Описанный ниже метод довольно стабилен, и по сути опирается на Javascript объект new FormData() , базовая поддержка которого есть во всех браузерах.

Для более понятного восприятия материала, он разделен на шаги. На этом все, полетели.

AJAX Загрузка файлов: общий пример

Начинается все с наличия на сайте input поля типа file . Нет необходимости, чтобы это поле было частью формы (тега

У меня 5 текстовых полей, в которых лежат некие значения.

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

Поиск в Google не дал результатов, ибо решения я нашел только на PHP.

3 ответа 3

File System API — не стандартизированное и не утверждённое W3C API, которой будет работать только в браузерах на движке Blink. Этот вариант подойдёт Вам только в том случае, если Вы пишите дополнение для Chrome или веб-аппликацию под конкретный браузер.

Пример записи и чтения файла (или нескольких):

П.С. Не могу добавить в ответ больше двух ссылок (из-за ограничения по репутации) но поиск по «FileReader API» даст вам множество дополнительных подсказок и примеров 😉

17 бесплатных jQuery-скриптов для загрузки файлов

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

jQuery- библиотека для загрузки и управления графическим контентом. С помощью Closify можно загружать изображения, изменять размер, обрезать и сохранять их. После редактирования изображения будут сохранять соотношение сторон.

Эта библиотека предлагает более универсальный набор функций. Она поставляется с 5 различными стилями на выбор, включая нативный пользовательский интерфейс jQuery. А также с вариантом для разработчиков AngularJS, которым необходимо быстрое и надежное решение для загрузки файлов.

Функции jQuery File Upload включают в себя инструмент перетаскивания нескольких файлов с рабочего стола, индикатор выполнения для каждой загрузки. Библиотека работает с любой серверной платформой (PHP, Python, Ruby on Rails, Java, Node.js, Go и т. д.), которая поддерживает стандартную загрузку файлов через HTML-формы.

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

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

Скрипт на основе Bootstrap использует простой подход к загрузке файлов. Он предоставляет возможность выбора нескольких файлов и снабжен виджетом индикатора выполнения.

Этот плагин создан для современных браузеров, поэтому для его настройки потребуются знания JavaScript и AJAX.

Инструмент для загрузки файлов на сайт путем перетаскивания. Он поддерживает традиционную концепцию «кликнуть и загрузить» и редактирование изображений после загрузки файлов. Настройки путей и типов файлов выполняются в фоновом режиме, поэтому перед запуском скрипта на рабочем сервере необходимо поработать с файлами конфигурации. На официальной странице Dropzone есть вся документация, необходимая для начала работы.

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

Fine Uploader поддерживает управление файлами в облаке. То есть, позволяет загружать файлы в Amazon S3 или Microsoft Azure. Другие возможности библиотеки: управление правами на редактирование, удаление файлов по мере их загрузки. Это полноценное решение для любого сайта, которому требуется надежный скрипт для загрузки файлов.

Flow.js

Flow.js — это JavaScript- библиотека, поддерживающая несколько одновременных загрузок через HTML5 API. Она поддерживает такие функции, как приостановка и возобновление загрузки, восстановление прерванных загрузок и обработка ошибок в загрузчике.

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

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

Formstone – это набор инструментов, реализованных в рамках одного проекта. В нем есть компонент Upload, который является удобным решением для управления загрузкой файлов. Он имеет простой интерфейс перетаскивания, который позволяет загружать один или сразу несколько файлов. Это эффективное решение для сайтов, которым необходимы дополнительные компоненты без лишних функций. Formstone позволяет собрать несколько десятков компонентов и создать на их основе собственные веб-приложения.

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

Легкое компонентное решение для веб-дизайнеров. Его можно применять как виджет сайта для загрузки файлов, используя функции jQuery + HTML5.

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

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

Backbone может подключить его к приложениям через интерфейс RESTful JSON.

JavaScript библиотека с поддержкой пользовательских уведомлений, которая ориентирована на прямую загрузку файлов из браузера. Выберите или перетащите файлы, нажмите кнопку «Загрузить» и подождите, пока инструмент не уведомит вас об успешной загрузке.

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

Plupload — это API-интерфейс управления загрузкой файлов, который предоставляет целый ряд инструментов и функций для создания продвинутых загрузчиков.

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

Это полностью рабочий загрузчик файлов на основе HTML5,который использует jQuery для улучшения пользовательского опыта. Он также доступен в версии для Flash.

Данная публикация представляет собой перевод статьи «Top 17 Best Free jQuery File Upload Scripts For Multiple File Upload 2018» , подготовленной дружной командой проекта Интернет-технологии.ру

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *