Шаблонизация на стороне клиента — уже реальность

    Предыстория


    Я занимаюсь разработкой IFrame приложений для социальной сети ВКонтакте. Самый удобный способ навигации по приложению — это динамическая подгрузка данных, без перезагрузки всей страницы. Раньше я генерил html код который нужно отобразить на сервере, пока не встретил EJS — JavaScript Templates…

    EJS — Embedded JavaScript


    EJS оказался одним из самых удобных и подходящих мне шаблонизаторов. Он работает, как с одиночными переменными, так и с массивами (читай объектами), присутствует логика (if...else...).

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

    Шаблон — /templates/question.ejs:
    <div>
      <% if(question) { %>
       <h2><%= author %>: <%= question %></h2>
       <div><textarea name="answer" id="answer"></textarea></div>
       <ul class="nNav btnList">
         <li>
          <a href="" onclick="ACT.question.answer('index'); return false;">Ответить</a>
         </li>
       </ul>
      <% } else { %>
       <h2>Нет вопросов, на которые можно ответить!</h2>
      <% } %>
    </div>

    * This source code was highlighted with Source Code Highlighter.


    Данные — /data/question.php:
    {"id":"98","question":"What are you doing now?","author":"Mihalich88"}

    * This source code was highlighted with Source Code Highlighter.


    Результат:
    $.ajax({
      type: "POST",
      url: "/data/question.php",
      dataType: "json",
      data: data,
      success: function(ans){
       var html = new EJS({url: ' /templates/question.ejs'}).render(ans);
      }
    });


    * This source code was highlighted with Source Code Highlighter.


    В итоге


    + «плюсы»
    1. Экономия траффика, т.к. передаются только данные ввиде json-объекта, шаблон кэшируется и берется из кэша
    2. Снижение нагрузки на сервер, т.к. шаблонизация происходит в браузере
    3. MVC структура, с выводом «V» за пределы сервера
    4. Работает даже на Opera Mobile 10

    — «минусы»
    1. Не индексируется, но зато идеально подходит для RIA

    Пример приложения, использующего EJS: http://formspring.vk-app.ru
    Подводный камень: шаблонизатор работает только с файлами у которых расширение *.ejs. Хотел, чтобы шаблоны имели расширение *.tpl, но не получилось — виснит на рендеринге… Возможно, если поковырять, то все заработет.
    Поделиться публикацией
    Комментарии 183
      +1
      Давно присматриваюсь к js-шаблонам, в веб-приложениях сервер-сайт решения уже потеряли логический смысл.

      Интересен вопрос производительности. Как себя старые машины чувствуют, что со всеми любимым 6-м ie?

      Проблема в том, что в сервер планку памяти добавить можно, а с клиентскими машинами сложнее…
        0
        *сервер-сайт = сервер-side
          +1
          Все превосходно. Задачи-то там тривиальные решаются при рендеринге шаблонов. Не один проект реализовал с использованием шаблонизаторов. Разные решения пробовал. ejs — самый простой и удобный. Все остальные обладают неоправданным излишеством.
          Хочу, кстати, заметить, что вдохновителем ejs является erb — стандартный шаблонизатор в RubyOnRails.
            +3
            Что значит server-side потеряло логический смысл?
              +1
              Да, я не совсем понятно высказался. Я имею в виду, что в случае использования шаблонов на сервере, в веб-приложениях частично дублируется код, в моем случае, javascripte и php делают одно и то же. Может быть, конечно, я просто не нашел красивых решений, но шаблон в js вполне может быть этим красивым решением.
                0
                Вы посмотрите на вышеупомянутый Ruby on Rails
              0
              а как же проверка прав, вы её тоже хотите на клиенте делать?
                +2
                Пардон, а какое отношение view имеет к ACL?
                  +3
                  в зависимости от прав некоторые части шаблона могут не показываться. либо делать практически одинаковые шаблоны?
                    0
                    ну значит не везде применимо, и все.
                      +3
                      угу, просто нужно дублировать, а значит синтаксис шаблонов должен быть совместим клиентский и серверсайд. а всё это уже есть для xslt, а здесь велосипед.
                        0
                        А вот здесь вы правы, про дублирование — ведь состояние сохраняется на сервере, а это значит, что в один момент нужно будет вывести измененный шаблон.

                        Однако, все же бывают ситуации, когда нужно как-то оформить пришедшие в JSON данные — шаблонизация тут не помешает.

                        Плюс это актуально для тех приложений, UI которых формируется на клиенте. Такие приложения больше напоминают десктопные, просто работают в браузере. Например, приложения на ExtJS используют XTemplate.
                          0
                          А вы можете показывать лишь те части которые пришли в шаблон, а на сервере уже отдавать не все подряд, а лишь то что нужно
                        +4
                        ну и какая разница, на клиенте это или на сервере?

                        я себе с трудом представляю приватные данные в самом коде шаблона. а все остальное идентично классическому mvc получается.
                          0
                          Серверов всегда меньше чем клиентов. Отдавая работу на клиент, мы снижаем нагрузку на сервер.
                            –1
                            Человек, в среднем, воспринимает уровни вложенности от 5 до 8. Обезьяна — 2-3. Попробуйте вникнуть в дискуссию хотя бы на уровне обезьяны. :)
                              +10
                              Я отвечал не на этот комментарий, но тот уже найти не могу. И да, сходите нахуй со своей надменностью.
                            0
                            в MVC, V — обозначает View, а не кастрированный шаблон. Вью, в котором можно дёргать логику отображения, проверять права на показ, дёргать хелперы и даже обращаться к модели.
                            А самое главное, нужно писать не «на клиенте это или на сервере», а «на клиенте это _и_ на сервере», есть пользователи и клиенты с отключёнными js, или плохо поддерживаемым, есть «фишки» браузеров или конкретных версий, есть seo, есть вывод на печать…
                            +3
                            В зависимости от прав показываются/не показываются данные. Шаблонизация этих данных — отдельный процесс.
                              +6
                              Проще сделать шаблон с расчетом на полные права, и в зависимости от переданных json параметров — показать или не показать блок данных или элемент управления.

                              Например (блок авторизации):
                              <div id="authbox">
                              <% if(user.name) { %>
                                <div>здравствуйте, <%= user.name %>!</div>
                                <div><a href="/cabinet/">Войти в личный кабинет</a></div>
                              <% } else { %>   
                                <div>Пожалуйста авторизуйтесь!</div>
                                <div>Логин: <input type="text" id="login"></div>
                                <div>Пароль: <input type="text" id="passwd"></div>
                              <% } %>
                              </div>


                              * This source code was highlighted with Source Code Highlighter.


                              В зависимости от того, какий объект с данными мы передадим при рендеринге, будет выведена либо форма авторизации, либо приветствие пользователя!
                                0
                                var htmlForAuthBox= user.name? $make.authBox( $make.authHello({ name: user.name }) ): $make.authBox( $make.authForm() )

                                var htmlForAuthPage= $make.authForm()
                                  0
                                  $html = $this->view->display('auth');

                                  И че? Зачем приводить дурацкий код, если вам показывают шаблон?
                                    0
                                    чтобы показать, что таким шаблоном не сделать оба хтмл-а без дублирования. или что логика вывода тех или иных блоков ничего не забыла в шаблоне. или что представленный код — это и есть view из которого вёрстка вынесена в шаблоны. выбирай любое.
                                      0
                                      Вы заблуждаетесь.
                                      $username = ( $user->isLoggedIn() )? $user->getName(): null;
                                      $this->view->assign('username', $username);
                                      $html = $this->view->display('auth');
                                      У меня одна форма в любом случае
                                        0
                                        на странице авторизации форма вставляется вместо контента, а он остальных — как попап окно с затенением страницы. формы одинаковые, но обёртки у них разные. как ты это сделаешь? нарисуешь 2 шаблона с дублированием? или 2 шаблона с подключением третьего?
                                          0
                                          Второе.
                                            0
                                            ок. идём дальше: в попапе нужно показывать не только форму авторизации, но и, например, форму регистрации. обёртка одинаковая, содержимое разное. как ты изменишь упомянутые ранее 3 шаблона?
                                              0
                                              попап один, контент другой.
                                +4
                                Не добавляйте лишних данных (на которые у юзера нет прав) в клиентский JSON, а в шаблоне проверяйте их наличие перед выводом блока. В чем сложность?
                                0
                                AmdY спалился в написании спагетти :)
                                  +1
                                  у меня было 12 групп, из них ~4 могут видеть одну и ту же страницу, но с разными данными. ао существовании некоторых данных и некоторых возможностей другие пользователи не должны догадываться. во первых, это понижает секъёрность, т.к. мы открываем часть внутренней реализации. во вторых бури поднимаются даже из-за комментированного кода. в третьих isAllow во вьюхе значительно уменьшает сложность модели, лучше извлечь все нужные данные и показать нужную их часть, чем городить свои запросы для каждого чиха, вот где настоящий спагетти код. Из двух зол приходится выбирать меньшую.
                                0
                                Сразу же подумал о том же.
                                  –1
                                  Там много хороших ответов, в краци: шаблону пофигу на регистрацию, он просто показывает то что от него просит сервер.
                                  0
                                  что-то я не понимаю какое отношения проверка прав имеет к шаблону. права проверяются на сервере, после чего генерируются данные. на основании данных строится страница. если в данных свойство showMeTits == true, то показываете сиськи и т.д. я не думаю, что наличие в шаблоне скрытого куска как-то навредит.
                                +2
                                А как быть с пользователями, которые заходят на сайт с выключенным Javascript?
                                  +33
                                  Либо сбрасывать со скалы, либо делать pda-версию.
                                    +2
                                    Да их сейчас очень немного, можно с чистой совестью пренебречь. Крайне ограниченную версию им показывать, с яркой плашкой о выключенном js + что они при этом теряют, да и ладно.
                                      +8
                                      а если война?
                                        +1
                                        Таким пользователям не доступно добрая половина интернета теперь, так что чем больше будет игнор таких пользователей, тем быстрее они вымрут как динозавры.
                                        Да и если рассуждать трезво RIA бывает 2х видов:
                                        — игрушки-развлекушки;
                                        — корп. решения;

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

                                        Из этого следуя мы получаем, что мы просто отсекаем тех, кто не хочет работать, а сидит и бьет баклуши на рабочем месте. Т.е. делаем добро! ;)
                                        +1
                                        Я пользуюсь шаблонизатором TrimPath, он удобный, простой и легкий.
                                          0
                                          По описанию вроде хороший, единственное, что настораживает, что последняя версия от 2005 года.
                                          Я прежде, чем выбрать EJS перепробовал 5 разных шаблонизаторов, и у всех были какие-то свои глюки в разных браузерах.
                                          +7
                                          >Шаблонизация на стороне клиента
                                          у вас у всей JQuery головного мозга!
                                            +1
                                            А причем тут jQuery? Или теперь jQuery и Javascript это синонимы?
                                            0
                                            непомешало бы более подробное описание для нубов
                                              0
                                              Для нубов есть ссылка на офф сайт.
                                              +1
                                              в Ruby On Rails встроен по умолчанию=)
                                                0
                                                В FF4 нижняя строчка обрезается пополам, там где «Разработка и поддержка приложения Носов Михаил»
                                                  0
                                                  Спасибо, проверю… Но это явно не из-за шаблонизатора )))
                                                    0
                                                    Исправил, приложение проходит бета-тестирование — возможны мелкие ошибки, в том числе и в верстке )
                                                  0
                                                  В чём смысл «снижения нагрузки на сервер» и в чём плюс этого? Клиент-серверная архитектура и призвана разгрузить тонкие клиенты в ущерб «толстым» серверам. В итоге всем хорошо.

                                                  Остальные перечисленные «плюсы» тоже неочевидные совсем, типа «V» за пределами сервера — как плюсы, так и минусы можно найти. Но у этого есть, конечно, и свои сферы применения. Но если в целом смотреть, то идея шаблонизации на стороне клиента далеко не нова. Мы ещё хз в каком бородатом году использовали возможности браузерной XSLT-трансформации в некоторых случаях.
                                                    +2
                                                    > Клиент-серверная архитектура и призвана разгрузить тонкие клиенты в ущерб «толстым» серверам
                                                    Это в конституции что-ли написано? Зачем мыслить шаблонами?
                                                      0
                                                      Нет, не в конституции, а в концепции всего веба, как любой какой-никакой клиент-серверной технологии.
                                                      А что плохого в шаблонах, если они общепризнанно правильные? Зачем делать что-то непонятное, что не даёт фактически никаких ощутимых плюсов (не считая экономии трафика, что с каждым днём всё менее актуально), не считая разных специфических применений, при том, что явные минусы действительно есть.
                                                        0
                                                        Не понимаю, какие концепции? Какого веба? Какой клиент-серверной технологии? Если мыслить концепциями и пытаться вписаться, то перестаёшь изобретать.

                                                        В шаблонах нет ничего плохого. В передаче с сервера только данных есть плюс, в его разгрузке, сервер работает быстрее обслуживает больше клиентов на единицу времени и экономически более эффективен (эксплуатационные расходы, электричество и т.д.). Сейчас уже даже на телефонах можно выполнять серёзный JS, так что я верю в перенос нагрузки с сервера на клиент.
                                                          0
                                                          так что я верю в перенос нагрузки с сервера на клиент.
                                                          Да я тоже верю, но главный вопрос — ЗАЧЕМ? Пока я понимаю только небольшую экономию трафика, больше ни одного плюса не вижу вообще. Изобретение — круто, да. Но в любой работе, связанной с разработкой, изобретением (начиная с диплома, диссертации) помимо новизны есть также обязательные требования актуальности и практической полезности.
                                                      +1
                                                      Плюсы в итоге имеет сам клиент: по сети передаются только данные json. Отсюда следует более высокая скорость и меньшее потребление трафика.
                                                        0
                                                        гм… а вот тут вот некоторые предлагают вытягивать все данные, а шаблоном уже решать какие из них показывать. а ведь так и будут делать в большинстве случаев. вместо создания просто механизма создания серверных ручек, зачастую делают одну толстую ручку, а потом уже шаблоном обрезают лишнее.
                                                          0
                                                          Вытягивать шаблоны всех данных можно(например, показывать блок статистики по балансу или форму логина), но сами данные в нормально построенном приложении просто не должны иметь шанса туда попасть например, без валидной сессии аутентификации.
                                                          0
                                                          Откуда следует более высокая скорость? От разницы в размере текстового (картинки то всё равно отдельно идут) контента в пару (пусть десятков) килобайт? Это мизерная разница при современных скоростях, а вот разница в скорости между обработкой всего этого хозяйства на клиенте и на сервере есть. Не говоря уж о всяких мобильных девайсах. Но тут странное дело — предложено пренебречь всеми у кого Javascript отсутствуют (или урезанный или очень медленный), но при этом говорится о экономии трафика, которая как раз и актуальна для них. Это не говоря уж и о том, что и поисковики такие же ущербные в плане разных там скриптов.
                                                            0
                                                            Тут разница в трафике геометрическая(если можно так сказать) — не на сколько-то килобайт, а в несколько раз. И это очень существенно и ощутимо в RIA. Тот же gmail — даже в нем раньше было ощутимо время задержки при переходе по пунктам меню.
                                                            Сейчас же все происходит очень быстро — там отдается json(довольно своеобразный — почему-то в начале файла с данными стоит while(1);). Если бы каждый элемент списка был обернут в div'ы, p и span, времени на загрузку данных было бы потрачено в несколько раз больше. Да и просто подумать: зачем грузить данные, которые уже были загружены? (html-шаблон)
                                                        +3
                                                        Только осторожно с этим, когда делаете индексируемые поисковиками странички…
                                                          0
                                                          Да, это огромный минус, который меня останавливает от применения подхода на практике.
                                                            +1
                                                            Движков полно, мне понравился beebole.com/pure в свое время. Но вот ума не приложу, зачем все же эти шаблонизаторы нужны еще где-то, кроме как в RIA, где необходимо как-то строить интерфейс на клиентской стороне, и то с оговоркой, что обмениваемся с сервером чистым JSON? В случае RIA можно не волноваться по поводу поисковой оптимизации. Во всех других случаях у server-side шаблонизаторов множество преимуществ перед client-side. Зачем на обычном сайте такие движки?
                                                              +1
                                                              Ну я просто в основном RIA занимаюсь, для меня это актуально. Но и RIA тоже хотят находиться в поиске.
                                                                +1
                                                                Да вы правы, обмен с сервером чистым json, больше ничего!
                                                                Я в начале топика писал, что занимаюсь разработкой приложений, для обычных сайтов может быть и не так удобно!

                                                                По поводу индексации — полностью согласен — большой минус, добавлю в минусы…
                                                                  0
                                                                  некоторые сайты делают дублирование. например, ссылки на странице ведут в некие разделы в варианте для поисков/отключенного javascript, и на эти же ссылки потом навешиваются хэндлеры (на то же jquery к примеру), чтобы гонять json данные.
                                                                +2
                                                                Поисковикам можно отдавать отдельные данные для индексации.
                                                                Например, перенаправлять json на подобие серверного шаблонизатора (написать простейший парсер, или использовать какой-либо готовый серверный json-шаблонизатор, в зависимости от целей оптимизации).

                                                                Вот, issuu, например, просто отдает поисковику простыню текста, вместо флешки.
                                                                Кеш Google: j.mp/9cb6Bz
                                                                Страница сайта: issuu.com/gulfscapes/docs/gulfscapes-magazine-spring-2010
                                                                  0
                                                                  Не подскажите, как это реализовано?
                                                                    0
                                                                    Это уже вопрос к разработчикам issuu =)

                                                                    Похоже, что они просто выдергивают весь текст из pdf, который загружает пользователь, и хранят его в базе данных, отдавая поисковику для индексации.
                                                                      0
                                                                      Либо гугл окольными путями сам дёргает текст из pdf.
                                                                      Получается, что issuu используют клоакинг?
                                                                        +1
                                                                        issuu отдает не pdf, а flash (в этом весь смысл сервиса).

                                                                        А гугл достаточно хорошо берет данные из pdf.
                                                                      +1
                                                                      Смотрим, кто зашел на страницу — если поисковик, то используем серверную шаблонизацию: передаем серверу массив json, он его отрисовывает сразу в html.
                                                                        0
                                                                        После двоеточия я написал ерунду, можно зачеркнуть )) Просто используем серверную шаблонизацию.
                                                                        0
                                                                        У гугла свой user agent «Googlebot»
                                                                          0
                                                                          Я понял, но получается, что issuu используют клоакинг, так?
                                                                            0
                                                                            Ну, на сколько я понял, клоакинг это когда Вы заходите на страничку а там инфа о автомобилях ауди, а когда гугл на нее же заходит, вместо тех же текстов о ауди он видит перечисления всех видов автомобилей + цены по ним + еще уйма различных ключевых слов. Другое дело когда страничка показывает те же данные что и Вы видели но удобным для парсера методом.
                                                                              0
                                                                              А как гуглбот узнает какие там данные были, и какие вы ему показываете? В этом же и суть клоакинга.

                                                                              И, кстати, на issuu так и получается — они пихают гуглу ключевики (статью из распознанных слов), в то время как юзеру показывается некая флешка (которая может быть совсем не статья).

                                                                              Вот на странице руководства для веб-мастеров в разделе про качество сайта Гугл явно пишет:
                                                                              Don't use cloaking or sneaky redirects.

                                                                              А вот в статье Сайт удален из индекса Гугла есть фраза:
                                                                              However, certain actions such as cloaking, writing text in such a way that it can be 
                                                                              seen by search engines but not by users, or setting up pages/links with the sole purpose 
                                                                              of fooling search engines may result in removal from our index.
                                                                              
                                                                              Однако, такие действия как клоакинг, написание текста таким способом, чтобы он мог быть 
                                                                              виден поисковыми машинами, но не пользователями, или установка страниц/ссылок с 
                                                                              единственной целью одурачить поисковую машину, могут привести к удалению из нашего 
                                                                              индекса.
                                                                          0
                                                                          У Google есть специальное предложение для AJAX сайтов. Если сайт поддерживает это предложение, то их паук будет делать дополнительные запросы к серверу с просьбой отдать HTML. Тут подробнее.
                                                                      0
                                                                      Не далек тот день когда поисковики будут отрабатывать js
                                                                        0
                                                                        Тогда се будут писать на GWT и других подобных вещах ))
                                                                          0
                                                                          Так Гугл уже.
                                                                            0
                                                                            Гугл всех обманул. Не индексирует он сайт с его же шаблонизатором closure-template.
                                                                        –1
                                                                        Снижение нагрузки на сервер, т.к. шаблонизация происходит в браузере

                                                                        Из этого вытекает минус:
                                                                        возрастает нагрузка на браузер (вернее процессор пользователя).
                                                                          +2
                                                                          Рассчет производится на то, что у пользователя хотябы Pentium-3. Хочу заметить, что при использовании flash приложений, нагрузка на браузер (процессор) уж точно не ниже.
                                                                            0
                                                                            Возможно, но данный минус все-таки игнорировать нельзя. При использовании технологии по назначение, конечно, плюсов больше чем минусов.
                                                                              –1
                                                                              Если я хочу просто показать диалог то пользователю от этого уж точно не станет хуже. На крайняк показать бегунок пока данные грузятся. В любом случае без этого браузер бы грузил страничку и пользователь ждал бы.
                                                                                0
                                                                                Я не говорил, что станет хуже. Просто снять задачу с одного «исполнителя», переложив на другого это сомнительное достоинство. Тем более, как вы говорите, пользователю придется ждать в обоих случаях.
                                                                                  0
                                                                                  Я не буду ждать у белого экрана, и меня то устраивает больше чем ожидание неизвестно чего. В данном случае я буду знать что щас загрузится формочка логина и я смогу пойти дальше, или камент добавляется. В ином случае я буду ждать у белой страницы пока появится малюсенькая формочка логина… помоему шаблонизатор на стороне клиента лучше.
                                                                                    0
                                                                                    Приведенный функционал можно сделать и без шаблонизатора на стороне клиента. Достаточно переслать ему готовый кусочек HTML кода.
                                                                                      0
                                                                                      Да, можно и так, а если данные зависят от того что я тут наклацал или ввел? Гонять данные туда-сюда?
                                                                                        +1
                                                                                        Вы хотите услышать какой ответ?
                                                                                        Да, данные нужно гонять в любом случае, что с JS-шаблонизацией, что без нее.
                                                                                        Нет. Данные гонять не нужно, вы их все равно получили, неважно в виде JSONа или в виде HTML.
                                                                                      0
                                                                                      При использовании Ajax не обязательно использовать шаблонизатор на стороне клиента, поэтому пример с белым экраном не катит)
                                                                                        0
                                                                                        Я там чуть выше написал. А если структура или логика зависит от того что я наклацал? Гонять данные туда-сюда?
                                                                                          0
                                                                                          Данные можно проверять на клиенте или на сервере. При чем тут шаблонизатор?
                                                                                            0
                                                                                            Я наклацал на клиенте чего-то и взависимости от этого мне в шаблоне надо либо показать что-то либо нет.
                                                                                              0
                                                                                              Не вижу проблемы) Может вам стоит продолжить мысль?)
                                                                                                0
                                                                                                И я не вижу никаких проблем. Что-то taliban не договаривает
                                                                                                  0
                                                                                                  Данные гонять туда сюда с сервера на клиент? Сервер не знает что я наклацал, соотвественно мне надо ему это сообщить чтоб он рендер сделал шаблона в html, а если я выбрал 50 чекбоксов? а если я камент написал и превью хочу посмотреть, а если этот камент большой? смысл все это гонять на сервер и обратно? Не проще ли взять только один раз шаблон и все сделать на клиенте?
                                                                                                    0
                                                                                                    И при чем тут JS шаблонизация?
                                                                                                      +1
                                                                                                      Кстати, не надо забывать, что клиент (процессор пользователя) кроме «рендеринга» сайтов может быть ещё много чем загружен (проигрывание музыки, загрузка контента из Интернет, куча программ висящих в «фоне» и т.п.).
                                                                                                      Каждая технология должна использоваться по назначению. JS-шаблонизатор следует использовать только в случая, подобных описанному в данной статье ИМХО.
                                                                                                        0
                                                                                                        От пары ифов ему хуже не будет. От того что я проверю есть ли в системе его имя, и если нет, покажу формочку логина, тоже хуже не будет. Если я ему покажу попапчик с введенным им текстом и еще парочкой элементов, тоже хуже ему не будет, я не собираюсь выводить математические расчеты. Вы слишком преувеличиваете затраты на этот рендеринг, я эксперементировал с подобными шаблонами (у меня есть велосипед) небольшой рендеринг занимает около 10 мс. Всю страницу никто не собирается рендерить, это безусловно глупо. Это не основной инструмент, это помошник.
                                                                                                          0
                                                                                                          Вы преуменьшаете затраты на рендеринг, потому что вы берете всего один случай.
                                                                                                            0
                                                                                                            Да, потому как я не буду одновременно рендерить много шаблонов, только один.
                                                                                                              0
                                                                                                              Вы может и не будете, а вот пользователь может нагрузить задачами систему очень быстро. И в соседних табах тоже.
                                                                                                                0
                                                                                                                Для этого я имею мозг. 20 табов с одним сайтом = 10 мс * 20 табов = 200 мс.
                                                                                                                а если у вас зашло 1000 клиентов? 200 мс * 1000 чел = 200000 мс — это нагрузка на ваш сервак. Естественно она преувеличена, просто показал на сколько число возрастет.
                                                                                                                Я повторю: я не говорю что надо эту штуку везде пихать, но это очень удобная штука, и помогает сэкономить и время и нагрузку, и клиенту с медленным соединением не надо ждать пока Ваш html пройдет по его модему…
                                                                                                                Кстати 20 мс это очень завышенное число, простые шаблоны рендрятся от 2мс. Так что нагрузка на клиента не существенна.
                                                                                                                  0
                                                                                                                  Скажите, а вы применяли в своих проектах данную систему?
                                                                                                                    0
                                                                                                                    Нет, я только эксперементировал, я использовал чистый JS + DOM для создания элементов, и это затратно. Ваш вариант я не применял тоже, мне он не нравится, слишком много данных гоняются, я поклонник минимализма.
                                                                                                                      0
                                                                                                                      А я года 4 назад пытался немного переходить на данную систему. Очень дорого по стоимости разработки получается. Минимизировать не данные нужно, а скорость разработки и затраты на последующие изменения.
                                                                                                                        0
                                                                                                                        Судя по моим тестам это более эфективно. И я буду использовать данную систему на текущем проекте. Мне статья как раз пришлась на руку, иначе бы использовал велосипед.
                                                                                                                          0
                                                                                                                          Напишите потом про это статью?
                                                                                                                            0
                                                                                                                            Нет, не напишу. Как-то мне статьи с некоторых пор перехотелось писать.
                                                                                                                              0
                                                                                                                              Тогда поделитесь в привате результатами? Мне реально интересно, без приколов.
                                                                                                                                0
                                                                                                                                habrahabr.ru/blogs/javascript/82615/ — это мой велосипед, я его переделал, сейчас он похож на описанный в статье. В двух словах банальный рендер того что в статье занимал 2мс. Тоесть Формочка логина или показ небольшой таблицы на +- 20-50 строк выходит молниеносно, а усилий прилогать совершенно не нужно, можно на сервере сделать страничка которая просто будет отдавать шаблоны, и брать их оттуда по небоходимости, либо вообще клиентские шаблоны кинуть в отдельную папку и тягать их оттуда самостоятельно, что на сервере практически не скажется. Учитывая что у меня был простенький шаблонизатор я увеличил время на 10, но я думаю что эта цифра будет уменьшена раза в 3 на самом деле.
                                                                                          0
                                                                                          А теперь представьте, что вы приехали на заправку, отдали деньги кассиру, она взяла деньги, дала вам сдачу, затем встали из со своего места, закрыла всё, пошла к вашей колонке, заправила вам машину, пожелала счастливого пути, и вернулась на свое место, что бы обслуживать следующего клиента, который 5 смотрел на закрытую кассу.

                                                                                          Вы всё еще думаете, что снять задачу с одного «исполнителя», переложив на другого это сомнительное достоинство?
                                                                                            0
                                                                                            Смотря для кого. Мне бы было удобно, что кассир всё сделал за меня, а я в это время мог бы заняться чем-то другим (выпить чашечку кофе например). Заправит кассир или я сам, время пройдет одинаковое. Да и не надо сравнивать человека с компьютером :). Компьютер (сервер) может выполнять несколько задач одновременно.
                                                                                            Я не говорил, что снять задачу с одного исполнителя, переложив на другого это совсем плохо. Я только сказал, что из этого вытекает минус, но плюс, возможно, будет на много жирнее этого минуса. Всё зависит от ситуации.
                                                                                  +3
                                                                                  подобная практика очень необходима, когда мы просто не имеем доступу к серверу. Например, я получаю данные с facebook с помощью API и хочу отобразить эти данные у себя на сайте. В таком случае созадавать шаблон остается только остается на клиенте.
                                                                                  почему столько скептизма=)
                                                                                    +1
                                                                                    судя по синтаксису в нем нет ничего нового. Всегда пользуюсь Javascript Micro-Templating от Ризинга.
                                                                                    +1
                                                                                    Минус — СЕО.
                                                                                    Для формочек, админок, пр. — хорошо :)
                                                                                    Целиком сайт, большие странички — плохо :(
                                                                                      0
                                                                                      Безусловно целиком сайт на нем никто не делает, основной контент передается нормальным путем…
                                                                                      0
                                                                                      У нас используется на нескольких RIA проектах, только я исходник перекатал чутка (вместо <%= variable %> использую %(variable)% ). Производительность устраивает вполне. В связке с методами получения HTML (уже отрендеренный html), HTMLFragments (отрендеренный html помещенный в document fragment, который можно вставить куда потребуется), HTMLParser (ф-ия выдающая отрендеренный html) такой шаблонизатор крайне удобен
                                                                                        0
                                                                                        А шаблоны подгружаются сразу заранее? или берутся с сервера по мере необходимости?
                                                                                          0
                                                                                          Берутся с сервера, по мере необходимости, кэшируются, и при повторном запросе беруться из кэша.
                                                                                          0
                                                                                          code.google.com/p/google-jstemplate/ — аналогично, но, похоже, еще более простой вариант.

                                                                                          Конечно, больше подходит, всё-таки для веб-приложений.
                                                                                          Хотя, мне кажется, что со временем такой способ обмена данными станет основным.

                                                                                          Если им правильно пользоваться — есть возможность подгружать достаточно тяжелые страницы клиенту.

                                                                                          Или догружать не запрошенные еще данные в фоновом режиме, постепенно. Тогда можно будет сделать отдачу страниц гораздо более быстрой.
                                                                                            0
                                                                                            «Или догружать не запрошенные еще данные в фоновом режиме» — ну это больше относится к ajax, нежели к шаблонизации.
                                                                                              0
                                                                                              ajax, как правило, содержит динамические данные, поэтому нужно будет проверять их актуальность, отдавая пользователю, после того как загрузили в фоне.
                                                                                              Поэтому некоторые данные могут оказаться загруженными зря (кроме случаев с редко меняющимися данными, как в различных архивах записей и т.п.).

                                                                                              А вот по-тихому подгрузить пару (тяжёлых, возможно) шаблонов — почему бы и нет, всегда полезно =)

                                                                                                0
                                                                                                Возможно, я с тобой соглашусь, можно сразу же загрузить все шаблоны в кэш.
                                                                                                Скорость работы немного возрастет. У меня по весу больше 50 кб шаблонов пока не было.
                                                                                                  0
                                                                                                  Уже потихоньку начинается экономия на спичках, да.
                                                                                            0
                                                                                            … ещё один интересный шаблонизатор Mustache
                                                                                            Здесь net.tutsplus.com/tutorials/javascript-ajax/quick-tip-using-the-mustache-template-library/ можно посмотреть пяти минутный ролик с его использованием.
                                                                                            А вот плагин от мелкомягких (видео ролик)
                                                                                            net.tutsplus.com/tutorials/javascript-ajax/quick-tip-an-introduction-to-jquery-templating/
                                                                                            Последние сразу палятся по наличию {%… %}
                                                                                              +2
                                                                                              Применяю tmpl от John Resig. Правда в текущем проекте (электронная коммерция) только в админке для вывода виджетов, наследованных от jQuery.UI. Например, при помощи таких вот шаблонов очень удобно делать grid с различными типами полей. А до этого был проект с динамическим поиском товаров и объявлений — там все это уже применялось на front-end.
                                                                                              Я, честно говоря, не понимаю комментаторов, которые боятся нагрузки на процессор пользователя. На мой взгляд это наиболее очевидный плюс данного подхода, так как он дает нам возможность использовать мощности клиентских машин для выполнения части работы по выводу страниц. Напомню, что, к примеру, в PHP 5.1 по умолчанию включено расширение json, следовательно кодирование json будет очень сильно быстрее вывода HTML напрямую.
                                                                                                0
                                                                                                Опять же — это большой плюс для начинающих разработчиков! Не у всех есть возможность сразу купить и поставить свой сервер! Я тоже не вижу ничего страшного в переносе шаблонизации на клиента.
                                                                                                • НЛО прилетело и опубликовало эту надпись здесь
                                                                                                  –2
                                                                                                  Перекладывая на клиента процесс шаблонизации, замедляется работа браузера. А это может стать причиной недовольствия со стороны клиента, так как снижается юзабилити продукта. Процессорное время сервере в десятки раз дешевле, чем процессорное время клиента. Зачем ему дополнительная нагрузка, если его цель быстро и качественно получать контент?
                                                                                                    0
                                                                                                    Мы вспомнили 90-е…
                                                                                                      0
                                                                                                      Не считаю, что сейчас у браузера единственная цель — качественно получать контент!
                                                                                                      Есть еще 2-я — его обработка, и 3-я — вывод.
                                                                                                        +1
                                                                                                        Есть возможности, а есть целесообразность. Так вот, целесообразность перенесения шаблонизации на сторону клиента есть не всегда.

                                                                                                        Давайте вам дам хороший пример. Вы получаете результат некого запроса. Это, например, балансовый отчет предприятия. Чтобы его читать нормально, его нужно правильно стилизовать. Там половина строчек имеет какую-то свою стилистику, не базовая таблица с одинаковыми ячейками. Добавляем небольшой интерактив, который будет коллапсировать блоки. Я вам скажу, что темплейтирование и отрисовка данного шаблона займет больше времени, чем передача данных. Клиент будет все это время ждать, а не работать с данными. А если он откроет несколько вкладок, то ждать клиент будет еще больше. Он же работать хочет, а не на курсор в виде часиков смотреть.
                                                                                                          0
                                                                                                          Не преувеличивайте, это инструмент для помощи, никто на нем не делает полный сайт с нуля. Основная масса данных подгружается обычным путем, то что подадобится позже подгружается уже при помощи этой библиотечки именно и только когда понадобится.
                                                                                                            0
                                                                                                            Тогда встречный вопрос, зачем использовать две технологии темплейтирования данных? Чтобы жизнь малиной не казалась?
                                                                                                              0
                                                                                                              Вот, по-моему, хороший пример Он прост, но показывает зачем вообще шаблонизатор.
                                                                                                                0
                                                                                                                Я задавал вопрос не о том, что нужен или не нужен шаблонизатор, а о том, зачем использовать две технологии вместо одной?
                                                                                                                  0
                                                                                                                  Чтоб не ждать у белого экрана загрузки формы логина или отправки камента.
                                                                                                                    0
                                                                                                                    Я тоже не очень понял зачем нужно использовать серверный шаблонизатор…

                                                                                                                    В RIA просто рисуется страничка с разметкой, стилями, скриптами, а затем при помощи js шаблонизатора заполняется данными…
                                                                                                                      0
                                                                                                                      Потому что серверный шаблонизатор снимает много-много геморроя с плеч клиента, да и разработчика тоже. Серверное процессорное время в разы дешевле клиентского.

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

                                                                                                                      На сервере скрипты выбрали данные и превратили их в JSON. Далее JSON скармливается темпейт-системе на сервере, как результат получаем HTML. Этот HTML передаем клиенту, и отобразили его. Теперь самое интересное. Если клиенту рассказать, что полученный им HTML на самом деле является частью, и что эту часть страницы нужно вставить вот в это место, то вы легким движением JS можете построить описанную выше функциональность. Теперь плюсы — одна технология темплейтированя для целых страниц и их частичек. Данные гоняются в строго-типизированном формате — HTML, на визуализацию которых клиентскому ПО не требуется дополнительное время.
                                                                                                                        0
                                                                                                                        Мне больше всего понравилось создание на сервере JSON и только после этого передача на шаблонизатор — который должен обратно из JSON представления преобразовать во внутреннее.

                                                                                                                        Шаблоны на стороне клиента банально переносят разработку с сервера на клиентскую сторону, сразу появляются плюсы из-за более простой организации серверной части и соответственно упрощается её отладка и уменьшается пространство для ошибок.
                                                                                                                          0
                                                                                                                          Но общее количество ошибок не уменьшается. Применяя тот же ACL, мультиязычность, вы получаете все те же проблемы
                                                                                                      0
                                                                                                      хорошая штука EJS, его кстати можно применять для шаблонизации и на серверной стороне, один из примеров
                                                                                                        +1
                                                                                                        Давно пользуемся jTemplates.

                                                                                                        Самое главное, на мой взгляд, преимущество таких шаблонизаторов:
                                                                                                        HTML в одном месте.

                                                                                                        Генерить HTML на сервере — значит смешивать логику и представление.
                                                                                                          0
                                                                                                          > Генерить HTML на сервере — значит смешивать логику и представление.
                                                                                                          Новый виток холивара?
                                                                                                            –1
                                                                                                            Нет, ни в коем случае.

                                                                                                            Просто оно ведь на самом деле так ;)
                                                                                                              0
                                                                                                              Мне правда интересно, почему?
                                                                                                                –1
                                                                                                                Как, к примеру, происходит работа у нас.

                                                                                                                Есть верстальщик, он же частично понимает яваскрипт/jquery.

                                                                                                                Есть программист.

                                                                                                                Итак, программист написал на c# серверный код, который отдает созданный объект клиенту,
                                                                                                                ответ на аяксный запрос.

                                                                                                                Когда отдается html: верстальщику надо копаться в сишарпном коде,
                                                                                                                есть вероятность что-то сломать, кроме того он видит кусок кода в изоляции от всего остального.

                                                                                                                Также неудобно дописывать html — вижуал студия не комплитит html в сишарпном коде.

                                                                                                                Также нет комплита и автозакрытия тегов, а также подстановки стилей и т.п. в такой конструкции:

                                                                                                                
                                                                                                                var code = String.Format("<li><a href\"={0}\">Ссылка на продукт {1}</a></li>", Obj.Link, Obj.Text);
                                                                                                                


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

                                                                                                                Который явно больше, чем Json того же объекта для подстановки.

                                                                                                                Если весь код на клиенте, то:
                                                                                                                1) верстальщик копает только в одном месте
                                                                                                                2) сломать труднее: синтаксис шаблонизаторов достаточно прост даже для непрограммиста
                                                                                                                3) нет нужды каждый раз грузить громоздкий код с сервера, json компактнее
                                                                                                                4) править представление можно даже в том случае, если нет доступа к серверному коду
                                                                                                                или же там был произведен рефакторинг/изменение, которое повлияло на принцип создания объекта

                                                                                                                Немного сумбурно, может, но вот, проиллюстрирую кодом с phpMyAdmin.

                                                                                                                Хотя тут не про яваскрипт речь, но все же.

                                                                                                                
                                                                                                                 echo '<form action="./server_databases.php" method="post" name="dbStatsForm" id="dbStatsForm">' . "\n"
                                                                                                                       . PMA_generate_common_hidden_inputs($_url_params);
                                                                                                                
                                                                                                                    $_url_params['sort_by'] = 'SCHEMA_NAME';
                                                                                                                    $_url_params['sort_order'] = ($sort_by == 'SCHEMA_NAME' && $sort_order == 'asc') ? 'desc' : 'asc';
                                                                                                                
                                                                                                                    echo '<table id="tabledatabases" class="data">' . "\n"
                                                                                                                       . '<thead>' . "\n"
                                                                                                                       . '<tr>' . "\n"
                                                                                                                       . ($is_superuser || $cfg['AllowUserDropDatabase'] ? '        <th> </th>' . "\n" : '')
                                                                                                                       . '    <th><a href="./server_databases.php' . PMA_generate_common_url($_url_params) . '">' . "\n"
                                                                                                                       . '            ' . $strDatabase . "\n"
                                                                                                                       . ($sort_by == 'SCHEMA_NAME' ? '                <img class="icon" src="' . $pmaThemeImage . 's_' . $sort_order . '.png" width="11" height="9"  alt="' . ($sort_order == 'asc' ? $strAscending : $strDescending) . '" />' . "\n" : '')
                                                                                                                       . '        </a></th>' . "\n";
                                                                                                                    $table_columns = 3;
                                                                                                                    foreach ($column_order as $stat_name => $stat) {
                                                                                                                        if (array_key_exists($stat_name, $first_database)) {
                                                                                                                            if ($stat['format'] === 'byte') {
                                                                                                                                $table_columns += 2;
                                                                                                                                $colspan = ' colspan="2"';
                                                                                                                            } else {
                                                                                                                                $table_columns++;
                                                                                                                                $colspan = '';
                                                                                                                            }
                                                                                                                            $_url_params['sort_by'] = $stat_name;
                                                                                                                            $_url_params['sort_order'] = ($sort_by == $stat_name && $sort_order == 'desc') ? 'asc' : 'desc';
                                                                                                                            echo '    <th' . $colspan . '>'
                                                                                                                                .'<a href="./server_databases.php' . PMA_generate_common_url($_url_params) . '">' . "\n"
                                                                                                                                .'            ' . $stat['disp_name'] . "\n"
                                                                                                                                .($sort_by == $stat_name ? '            <img class="icon" src="' . $pmaThemeImage . 's_' . $sort_order . '.png" width="11" height="9"  alt="' . ($sort_order == 'asc' ? $strAscending : $strDescending) . '" />' . "\n" : '')
                                                                                                                                .'        </a></th>' . "\n";
                                                                                                                        }
                                                                                                                    }
                                                                                                                
                                                                                                                  +1
                                                                                                                  Могу вам только посочувствовать, если для C# нет вменяемого server-side шаблонизатора. Конечно же, верстальщик не должен копаться в коде модели.

                                                                                                                  Вот только из этого совершено не вытекает, что генерировать из данных HTML на сервере — плохо. HTML, кстати, при этом не начинает быть «в двух местах».
                                                                                                                    0
                                                                                                                    Серверный шаблонизатор там есть, фактически это ASP.NET.

                                                                                                                    Но мы же говорим о яваскрипте и об аяксе, вот тут-то и возникает момент,
                                                                                                                    что генерить html на сервере и передавать клиенту, по-моему, неудобно.
                                                                                                                      0
                                                                                                                      А я уж почти поверил в холивар. Удобно бывает, не спорю, если вышеописанные минусы не важны.
                                                                                                                        0
                                                                                                                        s0rr0w ниже хорошо уточнил, что меня удивило.
                                                                                                                      0
                                                                                                                      >если для C# нет вменяемого server-side шаблонизатора
                                                                                                                      единственный вменяемый шаблонизатор — XSLT
                                                                                                                      В .NET он был с самого начала.
                                                                                                                      0
                                                                                                                      верстальщик, что не понимает js не верстальщик. ученик средней школы
                                                                                                                        +1
                                                                                                                        У нас есть отличный дизайнер-верстальщик который не понимает js, и он отнюдь не ученик средней школы, он делает красивые дизайны, но вот програмить он, увы, не может. И что теперь его надо уволить и взять другого? У нас каждый программист знает JS.
                                                                                                                          0
                                                                                                                          это моё личное имхо, что человек, верстающий визуальное оформление страницы обязан владеть js дабы создавать эффекты, выводить меню и тд

                                                                                                                          но я разделяю дизайнеров и верстальщиков.
                                                                                                                          0
                                                                                                                          По вашему, программист=верстальщик?

                                                                                                                          Или под «понимать js» имелось ввиду что-то другое?
                                                                                                                            0
                                                                                                                            программист — не верстальщик, хотя вполне может знать его работу и справляться с ней. Это, скорее, уже обычное дело, что программист умеет верстать. Именно грамотно и хорошо верстать, а не лепить чёрти что. А обычный верстальщик, что знаешь лишь html и css, я считаю не пригоден к полноценной работе. без js сейчас ничего не делается. Если для клиентской части ещё использовать двух человек, то это через чур накладно
                                                                                                                              0
                                                                                                                              «через чур» -> ученик средней школы, имхо :)

                                                                                                                              >Это, скорее, уже обычное дело, что программист умеет верстать.
                                                                                                                              >… то это через чур накладно

                                                                                                                              Вы фрилансер?
                                                                                                                0
                                                                                                                Генерить HTML на сервере без шаблонизатора — значит смешивать логику и представление
                                                                                                              • НЛО прилетело и опубликовало эту надпись здесь
                                                                                                                  0
                                                                                                                  1) Смущает, но не особо, т.к. все быстро и хорошо работает в отличие от других шаблонизаторов, которые я пробовал.

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

                                                                                                                  3) А почему нет? И javascript, и style могут быть в шаблоне
                                                                                                                  • НЛО прилетело и опубликовало эту надпись здесь
                                                                                                                      0
                                                                                                                      А браузеры, в большинстве случаев, не грузят больше чем в 10 потоков.
                                                                                                                      И да, асинхронность будет бичом божим. Придется наворачивать контроллер завершения загрузки, чтобы не пытаться выполнять код до завершения загрузки всех запчастей.
                                                                                                                        0
                                                                                                                        Извините, в 6 потоков.
                                                                                                                  +1
                                                                                                                  шаблонизация на стороне клиента реальность уже давно и называется она XSLT
                                                                                                                    0
                                                                                                                    Я XSLT — не понимать ))
                                                                                                                      0
                                                                                                                      это его не отменяет :)
                                                                                                                        0
                                                                                                                        а очередной велосипед понимать?
                                                                                                                      +2
                                                                                                                      Да все хорошо, шаблонизаторы есть, есть и XSLT на клиенте, и в IE при костылях. Просто надо чтобы разработчики помнили, что в Javascript шаблонизация ради шаблонизации — ненужная трата времени.
                                                                                                                        0
                                                                                                                        А ещё очень нужна многоязычность — как её реализовать?
                                                                                                                        Была бы она, было бы вообще идеально
                                                                                                                          0
                                                                                                                          Тайтлы, тексты и прочий языко-зависимый контент можно присылать отдельной порцией данных.
                                                                                                                          +2
                                                                                                                          совсем не понял почему «уже» реальность?
                                                                                                                          jtemplate, mustache.js — проекты, которые не вчера придумали. это не инновация ведь.
                                                                                                                            0
                                                                                                                            Просто о них никто особо не писал… Я же привел пример, работующего приложения полностью с использованием шаблонизатора!
                                                                                                                            0
                                                                                                                            Использую beebole.com/pure, вцелом всем доволен. С сервера шлю только json данные, которые потом форматируются в UI списки на клиенте. Раздражают библиотеки, которые юзают jsp style типа <% %>, неужели ничего своего придумать нельзя.
                                                                                                                              +1
                                                                                                                              По мне так читаемость ужасная. Код перемешанный с разметкой. Особенно забавно смотрится <% } %>.

                                                                                                                              Лучше как пример так:
                                                                                                                              <div>
                                                                                                                                %? question:
                                                                                                                                 <h2>%author%: %question%</h2>
                                                                                                                                 <div><textarea name="answer" id="answer"></textarea></div> 
                                                                                                                                 <ul class="nNav btnList">
                                                                                                                                   <li>
                                                                                                                                    <a href="" onclick="ACT.question.answer('index'); return false;">Ответить</a>
                                                                                                                                   </li>
                                                                                                                                 </ul>
                                                                                                                                ?%?
                                                                                                                                 <h2>Нет вопросов, на которые можно ответить!</h2>
                                                                                                                                ?%
                                                                                                                              </div>


                                                                                                                              Идея в том, чтобы параметры для постановки в шаблоне не терялись среди тегов, т.е. не использовать < и > для обрамления переменных.
                                                                                                                                +1
                                                                                                                                угу, пусть они теряются среди текста. хорошее решение х)
                                                                                                                                  0
                                                                                                                                  Я не хотел чтобы они терялись среди текста, я хотел чтобы они не терялись среди тегов. Можно выделять двумя %% или {{}}, но не < и >.
                                                                                                                                    0
                                                                                                                                    м… дай догадаюсь, ты пользуешься блокнотом с примитивной подсветкой синтаксиса, где одинаково подсвечивается всё, что между угловых скобок? %-)

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

                                                                                                                              Самое читаемое