NodeJS фреймворк с синтаксисом Laravel

 (и без лапши в коде)

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


Многие из нас за достаточно короткое время привыкли к Laravel, его изящный стиль, Artisan для консоли, Eloquent ORM, Middlewares, Providers и т.д. Так подумал и создатель фреймворка Adonis JS и полностью повторил все то, за что мы любим laravel но только на NodeJS — ну разве это не прекрасно? Давайте посмотрим поближе:


Структура приложения


├── app
│   ├── Commands
│   ├── Http
│   ├── Listeners
│   ├── Model
├── bootstrap
├── config
├── database
│   ├── migrations
│   └── seeds
├── providers
├── public
├── resources
│   └── views
├── storage

Поддерживаемые базы данных


  • PostgreSQL
  • SQLite
  • MySQL
  • MariaDB
  • Oracle
  • MSSQL

Мигации и консольная утилита Ace (Artisan)


#выполним в консоли
./ace make:migration users --create=users 

#откроем
database/migrations/1464437815620_users.js

Код миграции

'use strict'

const Schema = use('Schema')

class UsersSchema extends Schema {
  up () {
    this.create('users', (table) => {
      table.increments()
      table.string('email').unique()
      table.timestamps()
    })
  }

  down () {
    this.drop('users')
  }
}

module.exports = UsersSchema

Некоторые команды Ace


#запуск миграции
./ace migration:run

#статус миграций
./ace migration:status

#откатить последний шаг миграций
./ace migration:rollback

#сбросить и заново накатить миграции
./ace migration:refresh

Несколько интересных наблюдений


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


Роутинг


const Route = use('Route')
const User = use('App/Model/User')

Route.get('/', function * (request, response) {
  const users = yield User.all()
  response.json(users)
})

Route.get('users', 'UsersController.index')

База данных


Работа с БД в AdonisJS также прекрасна как и в Laravel 5, есть Gettters | Setters, Database Hooks позволяющие прослушивать события моделей и например в момент Save выполнять некоторые действия.


Query Builder


    const john = yield Database
      .table('users')
      .where('username', 'john')
      .limit(1)

Lucid (Eloquent)


yield User.all()
yield User.query().where('status', 'active').fetch()

Relations


class User extends Lucid {

  profile () {
    return this.hasOne('App/Model/Profile')
  }

  posts () {
    return this.hasMany('App/Model/Post')
  }

}

А зачем AdonisJS если есть Laravel?


Несмотря на то что php активно развивается, js во многом обогнал его. Достаточно взглянуть на фронтенд и его фреймворки. Один VueJS чего стоит. Пробегусь по пунктам:


Один и тот же синтаксис


Похожие языковые конструкции как на фронте, так и на бэке


Гигантский мир npm


Вам нужен хитрый функцинал поищите его на npm он ни чуть не меньше composer.


Асинхронность из коробки


В контроллере можно вернуть response в самом начале. А все трудоемкие и блокирующие операции выполнять после этого, на фоне:


Высокая производительность


Я провел несколько своих маленьких тестов, и NodeJS их все выиграл.


WebSocket


Очень удобно работать с ws используя Eloquent-подобную модель.


class SiteController {
  * save (request, response) {

    response.ok({success:true})

    const post = new SiteRequest()

    post.fill(
      request.all()
    )

    yield post.save() // SQL Update
    console.log(request.all())
  }

}

А как же быть с однопоточностью js?


Данный код это мое кастомное решение взятое из док NodeJS, позволяет распараллелить процессы:



const cluster = require('cluster');
const numCPUs = require('os').cpus().length
const http = require('./bootstrap/http')

if (process.env.NODE_ENV === 'production') {
  if (cluster.isMaster) {
    console.log(`Master ${process.pid} is running`);

    // Fork workers.
    for (let i = 0; i < numCPUs; i++) {
      cluster.fork();
    }

    cluster.on('exit', (worker, code, signal) => {
      console.log(`worker ${worker.process.pid} died`);
    });
  } else {
    // Workers can share any TCP connection
    // In this case it is an HTTP server

    runServer()

    console.log(`Worker ${process.pid} started`);
  }
}else{
  runServer()
}

function runServer() {
 const http = require('./bootstrap/http')
http(function () {
  use('Event').fire('Http.start')
})
}

Также есть


  • Мультитранспортная работа с Email.
  • Middlewares, для взаимодействия со входящими запросами HTTP.
  • Nunjucks шаблонизатор.
  • Поддержка событий всего приложения.
  • Встроенная поддержка Redis.
  • Безопасная загрузка файлов.
  • Средства защиты с поддержкой CORS, CSRF
  • И дружелюбное сообщество поддержки.

На этом я хочу звершить свой обзор и поделиться некоторыми ссылками:


Поделиться публикацией

Комментарии 42

    –1
    А что если к велосипеду прицепить кабину? Будет же как автомобиль
      +5
      Круто блин, хайп вокруг ноды и хайп вокруг ларавела встретились.
      Ну да, хипстеры, которым нравится и то и то будут довольны, а больше и не надо ничего.
        +3
        большой программный коллайдер сталкивает частицы сверхвысоких энергий
          +1
          Хрен с ней с нодой — неоднозначная вещь, в которой есть спорные моменты. Но ларавел вам чем не угодил? Отличный же фреймворк, причём тут хипстеры…
            –7
            Ой, не буду холиварить, а то прибегут хомячки Тейлора, ну нафиг.
            В двух словах из хорошего фреймворка выкинули сложные для изучения компоненты и заменили кривыми поделками, а потом еще развели хайпа.
              +1
              Да, но писать по всем Enterprise паттернам простые и средние приложения на фреймворке который нельзя называть Symfony — вам не кажется оверхедом? У каждого инструмента своя ниша и пустоту, которая была в мире PHP занял тот фреймворк — который больше подходил большинству разработчиков. Не больше не меньше. Не нужно фанатеть — это в корне разные инструменты для разного уровня задач.
                +3
                Ну все, началось.
                Оверхед на компонентном фреймворке, на котором есть minimal edition? Или под оверхедом вы подразумеваете использование библиотек? Или то что для простой задачи не придумывают простой велосипед, если уже есть решение которое справляется и с простой и со сложной задачей?

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

                Не нужно вам фанатеть по поводу ларавеля, раз уж не понимаете что это обычный хайп. Обычный средний фреймворк, со своими поделками и косяками. Какие у него плюсы простите, из-за которых он вдруг стал резко подходить большинству разработчиков?
                  +1
                  пустоту, которая была в мире PHP занял тот фреймворк

                  Даже интересно, где это такая пустота которую вдруг заполнил ларавел?
                    0
                    Где-то там, где раньше были CI и Kohana
            +3

            А кто такие "хипстеры" в вашем понимании? И почему вы это слово употребляете в негативном контексте?

              +3
              В моём понимании (да и не только в моём), хипстеры — это все эти люди с бородой, на гироскутерах, которые пишут код на новейшем фреймворке сразу после митапа, попивая при этом смузи. Это образно говоря. А по факту — люди которые гонятся за новинками просто потому что это новинки.
                0

                Интересно, сколько же лет должно пройти, чтобы Node.js непременно не ассоциировалась с этими "хипстерами"

                  0

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

                    +5

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


                    Надо чтобы все было на JSP и GWT, так еще наши деды писали и мы так будем.

                      +1

                      Работу тогда меняйте. Если коллеги не уважают ваше мнение, то все плохо.

                        0

                        А еще лучше — jQuery-only, а то кому-то из команды ничего понятно не будет, а разбираться долго и неохота)

                      0
                      Вопрос не в «сколько лет», а в зрелости технологии…
                        0

                        А чем, по-вашему, определяется зрелость?


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

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

                        То есть вы против:


                        1. Бород.
                        2. Гироскутеров.
                        3. Новых фреймворков.
                        4. Смузи.
                        5. Новинок в целом.

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

                          –1
                          [facepalm.jpg]
                          Мы против изпользования всякого г только потому что это разрекламированная шняга.

                          Ларавел это пример разрекламированной шняги, у которой есть куча недостатков и почти нету преймуществ, но вокруг которой развели хайп.

                          Какие у него плюсы простите, из-за которых он вдруг стал таким замечательным?
                            0
                            Ну раз стал таким популярным, значит свои плюсы определенно есть. Странно это отрицать
                              +2
                              Просто что бы начать им пользоваться почти ничего из ООП знать и не надо да как и самим PHP в принципе, отсюда популярность исходящая из банальной простоты. Если взять допустим программистов на Laravel и дать им Symfony, я думаю большинство просто не разберется (само собой с доступом к документации) как Bundle правильно сконфигурировать, написать CompilerPass, Форму создать, сделать фабрику, DataMapper и чистые модели без магии? Нормальный шаблонизатор, хотя бы Twig? Зачем, сделаем свой неполноценный Blade потому что опять нужна была сверх простота для создания расширений потому что люди не хотят разбираться в сложных библиотеках (фильтр или функцию в Twig объяявить проще простого, свои токены уже посложнее). Зачем, есть же Laravel! ООП неотъемлемая часть например в Symfony, Zend, в Laravel это все на втором плане т.к людям трудно в этом разобраться а делать сайты нужно уже сейчас! Тут уже упоминали что каких то супер преимуществ у Laravel нет, так и есть, кроме того что все проще простого (от сюда куча гемороя в сложных проектах). Проработал год над проектом не связанным с созданием простого блога на PHP, больше никогда такие проекты на Laravel делать не буду, only Symfony! Laravel вполне подходит для простых сайтов и каких нибудь средних монолитов, ИМХО. Просто те кто пишут на Larvael наверно еще не делали таких проектов где могут проявится его слабости и минусы, потому они и кричат что Laravel лучший + пиар :)) Все решает опыт разработчика, я бы даже визитку или блог делал на Symfony + MikroKernel, получаем все преимущества платформы + легковесность и возможность в будущем легко расширять свой блог без геморроя.
                                0

                                Ну, я бы сказал, что контейнер в Symfony — вещь не из простых. В Laravel гораздо проще его настроить. А Twig при желании можно и к Laravel прикрутить, с этим проблем нет. Что касается Blade, не считаю его ущербным)


                                А в чем был геморрой, связанный с Laravel?

                                  0
                                  Ну вобщем да, с контейнером еще можно жить, тут не спорю. Хотя на уровне ларавеля симфонийский контейнер не сложнее.
                                  Blade некорректно обрабатывает include — в нем нельзя изолировать контекст
                                  как пример — попробуйте в цикле вставить шаблон с переопределенными секциями.
                                  Основной геморрой был с фасадами и с orm.
                                    0
                                    franzose согласен на первый взгляд кажется сложно, но только на первый (все новое всегда кажется сложным). Вот вы можете привести конкретный пример сложности в контейнере Symfony или его понимания? Просто единственное что может показаться сложным на мой взгляд это описание структуры конфига (config.yml) через DI Configuration. И опять же, это только на первый взгляд. Все возможные и не возможные примеры описания структуры конфига есть в бандлах для Symfony (у каждого бандла есть Acme\DemoBundle\DependencyInjection\Configuration), нужно просто чуть чуть почитать документацию и залезть внутрь. Сложно говорите? Возьмите PhpStorm + Symfony plugin + конфиги сервисов в XML, вы получаете полноценный автокомплит по всем сервисам и параметрам контейнера в любом месте в вашем проекте! Даже есть в контекстном меню создать services.(xml|yml) за вас! IDE делает половину работы за вас.

                                    Что касается Blade, просто примитивный шаблонизатор. Никаких преимуществ, очередной свой велосипед, почему было не взять Twig, хотя бы Smarty? Многие дизайнеры с ним знакомы, он удобный и легко расширяем, проверен временем!!! Вопрос зачем? Я отвечу, никто не хочет разбираться как добавить какой то там Twig_Extension, можно ведь просто сделать в любом месте приложения (конечно нужно как минимум в ServiceContainer) Blade::extend() и получаем какой то простенький тег. Blade просто не умеет крутых штук, например множественное наследование на сколько знаю там хреново работает, получить весь контент предыдущих блоков не возможно (могу ошибаться, давно не проверял). Blade это просто красивая обертка для использования
                                    <?php echo ... ?>
                                    

                                    внутри шаблонов, ведь вы спокойно можете внутри Blade {{… }} вызвать любую PHP функцию или исполнить код. Какой это к черту шаблонизатор? PHP сам по себе изначально шаблонизатор, так чем Blade лучше? Согласен на примитивных задачах вполне подойдет, но я более чем уверен вы не разделяете логику и отображение нормально используя Blade. Вспомнил, там не нет даже тега {% spaceless.%}. Я всегда ставил Twig вместо Blade если была возможность.

                                    Да при желании вообще то к Larvael можно любой компонент или библиотеку прикрутить. Doctrine, Twig, FormBuilder, Yaml есть как пакет для Laravel. Можно запустить Laravel внутри Symfony (есть готовый Bundle), можно запустить Symfony внутри Laravel. Я даже хотел прикрутить Symfony Container в Laravel и настроить двухстороннюю связь между ними и вы не поверите получилось!!! Даже дошел до того что можно использовать любой бандл Symfony внутри Laravel, использовать его сервисы внутри Laravel как будто они зарегистрированы в его контейнере (ну допустим serializer или annotaion_reader). И знаете что? Я просто начал использовать Symfony :)

                                    Геморрой был связан:

                                    1. Для Api есть пакет DingoApi. Как только мы регистрируем провайдер для всего приложения он тупо перезаписывает стандартный ExceptionHandler который будет выводить ошибки как JSON ответ. Уже нужны какие то хаки что бы провайдер подключался только на определенный путь. Т.е в ServiceProvider что то вроде:

                                    if (Str::startsWith(Request::path(), 'api')) {
                                        $this->app->reg.....
                                    }
                                    


                                    Использование Request для определения необходимости подключения провайдера это уже какой то хак, можно конечно в на стороне веб сервера сделать ENV_VAR если путь начинается с /api/ и потом проверять по этому флагу, но по сути какая разница как, какие то хаки начинаются сразу. И да, если мы не подключаем DingoApiServiceProvider на все приложение, а где то в приложении вне /api/ используется что то из пакета DingoApi мы получаем ошибку.

                                    Symfony Serializer в сто раз удобней чем Transformer'ы в DingoApi, тут просто стоит попробовать и все понять самому :)

                                    2. ORM. Да она простая и для блога катит, но это тяжелейший класс который тянет за собой каждая модель. Допустим вам нужно добавить 1000 новых записей, вам что бы использовать их в связях с другими моделями нужно внимание сделать save() на каждой сущности (конечно можем обернуть в транзакцию и все же это не то что предоставляет нам Doctrine, делаем persist() и когда надо flush() при этом спокойно работаем с моделями как будто они в базе...).

                                    Во вторых, честно говоря уже не помню в чем именно было дело, но когда мы пытаемся сделать Translatable, Softdeletebale, Metable и еще что нибудь в одной модели это начинается ПРОСТО АД потому что они жуть как мешают друг другу, все завязаны на события внутри одной модели и т.д, в общем жуть. Конечно если вам надо просто вытащить или положить данные в базу несколько строк вполне подойдет :)

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

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

                                    Что бы собрать вместе все пакеты которые нужны для крупного проекта придется доставать бубен и плясать. Можно и самому написать все пакеты, так может сразу еще один свой фреймворк? :)
                                0

                                Не холивара ради интересуюсь.
                                Чем по вашему мнению плох ларавел?
                                Пс он же вроде не такой уж и новый

                                  0
                                  Тем что это простое решение для написания бложиков. Просто когда у вас бложик то вам вообще пофигу на чем писать. Как правильно заметил wendel в комментарии выше — сделаем свои неполноценные замены, чтобы только как можно проще для бложика.
                                  Год поработал с большим проектом на ларавеле — больше никогда не буду связываться.
                                  Почему многие кричат что ларавель лучше? Потому что эти многие клепают мелкие сайтики и просто не работали с крупным проектом, уровень среднего разработчика ларавеля — джуниор, уровень среднего разработчика симфони — он сам ларавель написать может, плюс еще разработчики ларавеля сравнивают свою икону со всякими вордпресами и кодеигнайтерами, разумеется он лучше их, все-таки не до конца испортили симфони.

                                  Еще такая забавная вещь — в ларавеле по сути два типа модулей/компонентов либо своя кривая поделка (элоквент, конфиг, blade) либо прибитый гвоздями компонент симфони (или либа) обернутый в самый базовый вариант использования (роутер, реквест, консольные команды)
                                    0

                                    Вы не конструктивно критикуете, а эмоционально. Хотелось бы о конкретных слабостях Laravel услышать, по вашему мнению.

                                      0
                                      franzose, в целом плюсую, это выглядит как-то так «Все что не Симфони — плохо». Хотелось увидеть нечто иное. И да, ларавел действительно прост, но я не уверен что это его минус. Тем не менееiborzenkov спасибо вам за вашу критику)
                                        0
                                        Я не говорю что «Все что не Симфони — плохо», я говорю что плохо брать компоненты мощного фреймворка и прикручивать их как в ларавеле. Разумеется я буду сравнивать ларавел с симфони потому что половина его компонентов это обертки над компонентами симфони, причем такие что до сложного функционала не добраться. И критики было бы меньше, если бы просто ларавел взял компоненты симфони и нормально их использовал не создавая такие обертки.

                                        Ларавел прост и это его огромный минус на хоть сколько больших проектах, просто на том что пишет 90% фанатов ларавела этот минус не заметен. Это именно та простота что выкинем функционал потому что для простых сайтов он не особо нужен.
                                        Вобщем если вы не планируете писать крупный проект, а уверены что будете делать сайты пачками в веб студии, то да, ларавел вам подойдет.

                                        Вот еще пачка минусов
                                        1) Очень слабая ORM — это свалка — в одной только model находится сама модель, выборки коллекций, построитель запросов, менеджер коннекшенов, работа с событиями, сериализация.
                                        Причем все это сделано так, что ломает автокомплит и вводит слишком много магии — всякие where(), scope, туда же еще прикрутили таймштамы и softDelete.
                                        2) blade — это по сути смарти — постая замена тегов на php в файле, больше ничего нету, да, для начала 2000-х было нормально, сейчас уже есть нормальные шаблонизаторы
                                        3) разработчик берет компоненты симфони и пишет для них свои обертки, причем только для самого базового использования — например роутер — только один вариант использования — через php в одном файле объявить сразу весь, причем под капотом используется симфоневый, который поддерживает разные форматы ресурсов, и достаточно мощный
                                        4) Фасады — кривейший паттерн, ломает нафиг автокомплит и работать хоть как-то можно с костылями ide_helper — при этом хомячки кричат что это не синглетон и можно подменять — какое блин счастье, подменять можно, а все другие минусы забыли — по сути это очень криво реализованный контейнер, в котором нужно прописывать каждый объект отдельным фасадом.

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

                                          1) Никто и не скрывает, что Eloquent реализует шаблон ActiveRecord.
                                          Это и есть объединение слоя бизнес-логики и слоя работы с БД. Применяется такой шаблон преимущественно в целях RAD.


                                          Doctrine же реализует шаблон DataMapper, UnitOfWork и многое другое, что очень полезно для Domain Driven Development. Но, думаю, Вы согласитесь что для проектов малого и среднего уровня это просто из пушки по воробьям.


                                          2) Я сталкивался с некоторыми проблемами в Blade (в Laravel 4), связанными в основном с наследованием и подключением файлов. Но в целом он достаточно удобен.
                                          Цель — сделать синтаксис шаблонов более читаемым по сравнению со стандартным PHP (по-сути синтаксический сахар).


                                          Кроме того, в Blade вы можете сразу вызывать любой PHP код используя тот же самый синтаксис, в отличие от Twig, который заставляет добавлять собственные функции/конструкции, если требуется что-то новое.


                                          Причина такого подхода, опять же, указана в первом пункте (RAD).


                                          3) То что Laravel базируется на некоторых компонентах Symfony, говорит лишь о том, что эти компоненты написаны хорошо и грех их не использовать, для того чтобы написать более простую и удобную обертку.


                                          4) Фасады в Laravel — точно такой же синтаксический сахар для разработчика, как и шаблонизатор Blade. Исторически в PHP разработчики привыкли использовать статические классы, потому что этот подход был реализован во многих фреймворках, но используя этот подход приложение тяжело тестировать.


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


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


                                          В заключении можно сказать что Laravel — это developer-centric фреймворк (именно так) в котором огромное внимание уделяется красоте и лаконичности кода, удобству использования, а также скорости написания приложений.


                                          Поэтому, ИМХО, Laravel'у быть, и никакой это не "хайп", в отличие, например, от Angular 1, который Google поматросил и бросил.


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


                                          Laravel — The PHP framework for web artisans

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

                                            0
                                            Если большой проект, реально большой, аля фейсбук или гугл. То лучше уж писать не на фреймворке, а с нуля условно говоря свой фреймворк.
                                +5
                                Ну ладно гироскутеры, ладно смузи, но бороды то за что?
                                  0

                                  Да вот только node.js и laravel уже давно не новинки, а зрелые и устоявшиеся технологии… ну по меркам веба.
                                  А приложений с их помощью написано много по любым меркам.

                                0
                                А не позволите поинтересоваться а чем так плох laravel? Может статьи есть какие на эту тему?
                                П.С. Просто сейчас присматриваюсь к миру разработки после долгого перерыва.
                                –2
                                Нынче модны только те фреймворки, которые от корпораций. У них есть средства хайп поднять, и все дружным хороводом идут за ними, даже если это полное ггг.
                                  +3
                                  осталось теперь переписать с генераторов на родные с v7.6 async / await.
                                    –1
                                    Порт Yii на js помёр, надеюсь с этимм портом будет другая учесть
                                      0
                                      Недавно наткнулся на аналогичный фреймворк для ноды, только в духе Symfony: nodefony
                                        +1
                                        Несмотря на то что php активно развивается, js во многом обогнал его. Достаточно взглянуть на фронтенд и его фреймворки. Один VueJS чего стоит.

                                        Голословное утверждение.

                                        Высокая производительность

                                        Я провел несколько своих маленьких тестов, и NodeJS их все выиграл.


                                        Опять мимо. Какого рода тесты? Может быть это узконаправленные тесты чтобы показать превосходство NodeJS

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

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