...

суббота, 19 сентября 2015 г.

Управление сложностью в проектах на ruby on rails. Часть 2

В предыдущей части я рассказал про представления. Теперь поговорим про контроллеры.
В этой части я расскажу про:
  • REST
  • gem responders
  • иерархию контроллеров
  • хлебные крошки

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

Контроллер содержит только логику взаимодействия с пользователем:
  • выбор view для отображения данных
  • вызов процедур обработки данных
  • отображение уведомлений
  • управление сессиями

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

REST


Я не буду углубляться в теорию REST, а расскажу вещи, имеющие отношение к rails.

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

resources :projects do
  member do
    get :create_act
    get :create_article_waybill
    get :print_packing_slips
    get :print_distributions
  end

  collection do
    get :print_packing_slips
    get :print_distributions
  end
end

resources :buildings do
  [:act, :waybill].each do |item|
    post :"create_#{item}"
    delete :"remove_#{item}"
  end
end


Иногда случается, что программисты не понимают назначение и разницу методов GET и POST. Подробнее об этом написано в статье «15 тривиальных фактов о правильной работе с протоколом HTTP».

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

  • открыть форму входа
  • отправить данные формы и войти в систему
  • выйти из системы
  • если пользователь является администратором, то он может подменить свою сессию на сессию другого пользователя

Для реализации этого функционала создаем одиночный ресурс session, соответственно, со следующими экшенами: new, create, destroy, update. Таким образом, у нас есть один контроллер, который отвечает только за сессии.

Рассмотрим пример сложнее. Есть сущность проект и контроллер, реализующий crud операции.
Проект может быть активным или завершенным. При завершении проекта нужно указать дату фактического завершения и причину задержки. Соответственно, нам нужно 2 экшена: для отображения формы и обработки данных из формы. Первое очевидное и неверное решение — добавить 2 новых метода в ProjectsController. Правильное решение — создать вложенный ресурс «завершение проекта».

resources :projects do
  scope module: :projects do
    resource :finish
    # GET /projects/1/finish/new
    # POST /projects/1/finish
  end
end


В этом контроллере мы добавим проверку статуса: а можем ли мы вообще завершать проект?
class Web::Projects::FinishesController < Web::Projects::ApplicationController
  before_action :check_availability

  def new
  end

  def create
  end

  private
  def check_availability
    redirect_to resource_project unless resource_project.can_finish?
  end
end


Аналогично можно поступать с пошаговыми формами: каждый шаг — это отдельный вложенный ресурс.

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

Responders


Gem respongers помогает убрать повторяющуюся логику из контроллеров.
  • делает код экшенов линейным
  • автоматически проставляет flash при редиректах из локалей
  • можно вынести общую логику, например, выбор версии сериалайзера, проставлять заголовки.
class Web::ApplicationController < ApplicationController
  self.responder = WebResponder # потомок ActionController::Responder
  respond_to :html
end

class Web::UsersController < Web::ApplicationController
  def update
    @user = User.find params[:id]
    @user.update user_params
    respond_with @user
  end
end 


Иерархия контроллеров


Подробное описание есть в статье Кирилла Мокевнина.
Что-то подобное я видел в англоязычном блоге, но ссылку не приведу. Цель этой методики — организовать контроллеры.

Сначала приложение рендерит только html. Потом появляется ajax, те же html, только без layout.
Потом появляется api и вторая версия api, первую версию оставляем для обратной совместимости. Api использует для аутентификации токен в заголовке, а не cookie. Потом появляются rss ленты, для гостей и зарегистрированных, причем rss клиенты не умеют работать с cookies. В ссылку на rss feed нужно включать токен пользователя. После требуется использовать js фреймворк, и написать json api для этого с аутентификацией через текущую сессию. Затем появляется раздел сайта с отдельным layout и аутентификацией. Так же у нас появляются логически вложенные сущности с вложенными url.

Как это решается.
Все контроллеры раскладываются по неймспейсам: web, ajax, api/v1, api/v2, feed, web_api, promo.
И для вложенных ресурсов используются вложенные роуты и вложенные контроллеры.

Пример кода:

Rails.application.routes.draw do
  scope module: :web do
    resources :tasks do
      scope module: :tasks do
        resources :comments
      end
    end
  end

  namespace :api do
    namespace :v1, defaults: { format: :json } do
      resources :some_resources
     end
   end
end

class Web::ApplicationController < ApplicationController
  include UserAuthentication # подключаем специфичную для web аутентификацию
  include Breadcrumbs # подключаем хлебные крошки, зачем они нужны в api?

  self.responder = WebResponder
  respond_to :html  # отвечаем всегда в html

  add_breadcrumb {{ url: root_path }}

  # в случае отказа в доступе
  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

  private

  def user_not_authorized
    flash[:alert] = "You are not authorized to perform this action."
    redirect_to(request.referrer || root_path)
  end
end

# базовый класс для ресурсов, вложенных в ресурс task
class Web::Tasks::ApplicationController < Web::ApplicationController
  # базовый ресурс доступен во view
  helper_method :resource_task

  add_breadcrumb {{ url: tasks_path }}
  add_breadcrumb {{ title: resource_task, url: task_path(resource_task) }}

  private

  # используем этот метод для получения базового ресурса
  def resource_task
    @resource_task ||= Task.find params[:task_id]
  end
end

# вложенный ресурс
class Web::Tasks::CommentsController < Web::Tasks::ApplicationController
  add_breadcrumb

  def new
    @comment = resource_task.comments.build
    authorize @comment
    add_breadcrumb
  end

  def create
    @comment = resource_task.comments.build
    authorize @comment
    add_breadcrumb
    attrs = comment_params.merge(user: current_user)
    @comment.update attrs
    CommentNotificationService.on_create(@comment)
    respond_with @comment, location: resource_task
  end
end


Понятно, что глубокая вложенность — это плохо. Но это касается только ресурсов, а не неймспейсов. Т.е. допустимо иметь такую вложенность: Api::V1::Users::PostsController#create, POST /api/v1/users/1/posts. Вложенность ресурсов необходимо ограничивать только 2-мя уровнями: родительский ресурс и вложенный ресурс. Так же те экшены, которые не зависят от базового ресурса, можно вынести на уровень выше. В случае с users и posts: /api/v1/users/1/posts и /api/v1/posts/1

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

Хлебные крошки


Я перепробовал несколько библиотек для формирования хлебных крошек, но ни одна не подошла. В итоге сделал свою реализацию, которая использует иерархическую организацию контроллеров.
class Web::ApplicationController < ApplicationController
  include Breadcrumbs
  # Добавляем хлебную крошку для главной страницы, первая ссылка в списке
  # Заголовок подставляется из локали, ключ основан на класса контроллера
  # {{}} означает блок, возвращающий хэш
  add_breadcrumb {{ url: root_path }}
end

class Web::TasksController < Web::ApplicationController
  # добавляем вторую хлебную крошку
  add_breadcrumb {{ url: tasks_path }}

  def show
    @task = Task.find params[:id]
    # добавляем крошку для конкретного ресурса
    add_breadcrumb model: @task
    respond_with @task
  end
end

class Web::Tasks::ApplicationController < Web::ApplicationController
  # крошки для вложенных ресурсов
  add_breadcrumb {{ url: tasks_path }}
  add_breadcrumb {{ title: resource_task, url: task_path(resource_task) }}

  def resource_task; end # опустим
end

class Web::Tasks::CommentsController < Web::Tasks::ApplicationController
  # т.к. не указали url, то будет выведен только заголовок
  add_breadcrumb

  def new
    @comment = resource_task.comments.build
    authorize @comment
    add_breadcrumb # добавит крошку "Создание новой записи"
  end
end

# ru.yml
ru:
  breadcrumbs:
    defaults:
      show: "%{model}"
      new: Создание новой записи
      edit: "Редактирование: %{model}"
    web:
      application:
        scope: Главная
      tasks:
        scope: Задачи
        application:
          scope: Задачи
        comments:
          scope: Комментарии


Реализация
# app/helpers/application_helper.rb
# Хэлпер, отображающий крошки
def render_breadcrumbs
  return if breadcrumbs.blank? || breadcrumbs.one?
  items = breadcrumbs.map do |breadcrumb|
    title, url = breadcrumb.values_at :title, :url

    item_class = []
    item_class << :active if breadcrumb == breadcrumbs.last

    content_tag :li, class: item_class do
      if url
        link_to title, url
      else
        title
      end
    end
  end

  content_tag :ul, class: :breadcrumb do
    items.join.html_safe
  end
end

# app/controllers/concerns/breadcrumbs.rb
module Breadcrumbs
  extend ActiveSupport::Concern

  included do
    helper_method :breadcrumbs
  end

  class_methods do
    def add_breadcrumb(&block)
      controller_class = self
      before_action do
        options = block ? instance_exec(&block) : {}
        title = options.fetch(:title) { controller_class.breadcrumbs_i18n_title :scope, options }
        breadcrumbs << { title: title, url: options[:url] }
      end
    end

    def breadcrumbs_i18n_scope
      [:breadcrumbs] | name.underscore.gsub('_controller', '').split('/')
    end

    def breadcrumbs_i18n_title(key, locals = {})
      default_key = "breadcrumbs.defaults.#{key}"
      if I18n.exists? default_key
        default = I18n.t default_key
      end

      I18n.t key, locals.merge(scope: breadcrumbs_i18n_scope, default: default)
    end
  end

  def breadcrumbs
    @_breadcrumbs ||= []
  end

  # используется внутри экшена контроллера
  def add_breadcrumb(locals = {})
    key =
        case action_name
        when 'update' then 'edit'
        when 'create' then 'new'
        else action_name
        end
    title = self.class.breadcrumbs_i18n_title key, locals
    breadcrumbs << { title: title }
  end
end


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

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

Моя работа на конкурс Mail.Ru

Сегодня в блоге Mail.ru были опубликованы результаты конкурса на «дизайн околопочтового приложения», в котором и я принял участие.

Места в конкурсе я никакого не занял и не заслужил упоминания в статье. Я даже так и не дождался обещанного инвайта на Dribbble… Ну ладно. Видимо моя работа была сочтена «откровенно провальной в плане визуала»…

Шут с ним, с визуалом, но я все же считаю что идеи заложенные мной в проект стоят того чтобы их увидело больше 4 человек (столько просмотров моей работы на behance). Дело в том что сами идеи я развиваю достаточно давно, а конкурсная задача позволяет продемонстрировать их в реальной задаче.

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

Позволю себе цитату из упомянутого поста, я с ней полностью согласен, и в какой-то мере именно такими мыслями я руководствовался во время работы:

Артем Тройной: Очень жаль, что некоторые дизайнеры не старались придумать что-то совершенно новое, а лишь добавляли категории для сортировки. Это же не тестовое задание при приёме на работу. В таких конкурсах есть возможность придумать, что-то совершенно уникальное, а не то что будет внедрено после конкурса.

Итак. Если вы еще не передумали читать дальше — добро пожаловать под кат)


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

Кнопка становится «ассоциативным элементом» (как я это называю:) — ее теперь можно «применить» к любому элементу на экране и получить логичный ответ.

Перетаскиваем кнопку поиска на имя адресата — получаем все письма от него (и все вложения).
Перетаскиваем на дату — получаем письма за этот день. И так далее.

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

Многие типичные задачи сведутся к всего одному действию, например пожелав найти все фотографии во вложениях — достаточно перетащить значок поиска на любую фотографию. Классический подход потребует как минимум перейти к разделу вложений, выбрать поиск по типу файла, указать тип файла «изображения»…

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

Все проще. Для начала нужно позволить объединять запросы вместе. Перетащив кнопку поиска на нужного адресата, а потом на любую картинку в выдаче — мы сформируем нужный запрос.

Как быть если «образца» нет? Нужно добавить понимание «связей» между критериями поиска.

Например, если мы ищем по имени адресата, а он в основном присылает счета — логично не заставлять пользователя искать подходящий счет, а сразу предложить такой запрос в виде возможного уточнения.

Или посложнее. Пользователь ищет все письма присланные одним адресатом. Но результатов конечно очень много. Мы можем кластеризировать результат и выделить значимые группы. Например, оказалось, что было много уведомления о заказе билетов и документов в различных форматах. А вот фотографий и уведомлений — не было.
Мы предлагаем «документы» и «билеты» в качестве уточнения. И если пользователь выберет «документы» — возможно новыми дополнениями станут «счета» или «сметы»…

Суть в том что мы не пытаемся решить за пользователя, «что ему нужно» — как делают многочисленные «интеллектуальные помощники». Но и не заставляем его бродить по меню и спискам в поисках нужного пункта.

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

Процитирую свою работу:
Представьте, что у вас есть список фильтров по которым вы можете искать. Например: «фото», «документы», «счета», «покупки», «архивы», «задачи», «даты»,… и т.п.

Фильтров может быть очень много, все адресаты могут быть фильтрами, диапазоны дат могут быть фильтрами («последняя неделя», «зима 2014-го») и т.п. С обновлениями программа может научиться определять новые фильтры, например «авиабилеты» или «3D-модели».

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

Но вот пользоваться списком из сотен фильтров было бы крайне неудобно.
Решение в том чтобы связать фильтры друг с другом ассоциативными связями. Тогда «счета» будут связаны с «документы» и «покупки». «2014» — будет связан с «календарь», а «весна» — с «2014», «2015», «2016» и так далее…

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

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

Если от admin@ebay.com — в основном приходят новости и счета, то этот контакт будет связан с фильтрами «новости» и «счета».
Фильтр «фотографии» связан с контактом «Андрей» правда чтобы увидеть больше контактов придется немного вытянуть список фильтров.

В заключение скажу, что идеи 1 и 2 — дополняют друг друга. Вместе они образуют интерфейс управления данными, построенный на ассоциациях.
Вместо изучения нескольких экранов, меню, фильтров, настроек и т.п., Пользователь получает всего два интуитивных действия: перетянуть значок поиска на похожий элемент, и воспользоваться «умными» фильтрами для уточнения запроса.

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

Сам ассоциативный подход я разрабатываю давно, и здесь просто старался показать некоторые наработки на «живом примере».
Если этот подход вас заинтересует — пишите мне на daniil.bakalin@gmail.com, сейчас идет разработка похожего решения для управления файлами на обычных компьютерах.

Спасибо за то что дочитали)

Даниил Бакалин. 09.2015.

upd.
В комментариях многие написали, что по внешнему виду кнопки не ясно, что ее можно перетаскивать.
Согласен, взять стандартную кнопку, в этом случае, было моим упущением. Просто я старался донести саму концепцию, о превращении кнопки во что-то совсем другое. По сути это вообще не кнопка, а самостоятельный объект. с которым можно взаимодействовать сложнее чем просто «нажать».

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

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

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

Представьте что вы пытаетесь объяснить, что такое меню человеку всю жизнь пользовавшемуся только командной строкой. А он придирается что цвет курсора ему напоминает о командной строке, и вообще двигать куском мыла по столу пытаясь попасть в двигающиеся строчки на экране — странно и неудобно…

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

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

Скажем вам нужно разработать сайт. Сколько времени займет объяснить как он должен выглядеть другому человеку (по сути написать ТЗ)? А сколько мелочей останется «за кадром»? И на сколько проще создать сайт в режиме диалога, и имея возможность воздействовать на любой элемент при создании? Что проще, сказать «увеличь логотип на 8% и сдвинь влево до пересечения с направляющей объединяющей отступы текста основного контентного блока» — или просто подвинуть логотип?

Что проще, найти нужного адресата путаясь надиктовать правильный запрос (типичный голосовой помощник), или просто увеличить рукой объект «контакты», который при этом разобьётся на кластеры по типу переписки, и просмотрев нужный — выбрать адрес (объекты + ассоциации + голосовой помощник)?.. В общем это тема отдельной статьи. Хочу просто сказать что просто голосом управлять чем-то не так просто. Но и типичные интерфейсы неудобны. Нужно что-то между ними, работающее по принципам человека, но предоставляющего ему новые возможности.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

О безопасности UEFI, часть третья

Продолжаем разговор о безопасности UEFI.
На этот раз речь пойдет об опубликованной в конце 2014 года серьезной уязвимости в реализации ACPI S3 (Sleep Mode), ее эксплуатации и последствиях. Основная «фишка» этой уязвимости в том, что она вскрыла целый класс проблем безопасности UEFI, вообще не считавшихся до этого проблемами, и потому и заслуживает отдельной статьи.
Тем, кто не читал предыдущие статьи цикла — раз и два, предлагаю прочесть сначала их, остальных жду под катом.

Часть третья. ACPI S3


Еще немножечко ликбеза
В отличие от SMM, о котором обычный пользователь чаще всего даже не подозревает, про ACPI S3, т.е. режим сна, знает любой обладатель ноутбука или ПК, выпущенного в последние 10 лет.
Стандарт ACPI, об изменениях в последней версии которого я недавно писал, определяет набор т.н. состояний сна, в одном из которых может находиться система, следующим образом:
  • S0 — Working, т.е. обычная работа, все устройства включены. Внутри этого состояния производители систем имеют право определять кучу других состояний: P-states, C-states, T-states и т.п., расскажу о них как-нибудь в другой раз.
  • S1 — Sleeping with Processor Context Maintained, оно же Power on Suspend, т.е. все ядра процессора выполнили команду HLT и стоят, но все кэши и RAM валидны и обновляются, питание со всех все линий S0-only снято. Возврат из этого состояния занимает приблизительно 10 мс, из которых ~90% — ожидание установившихся режимов после подачи питания на линии S0-only. Никакие регистры ни у CPU, ни у чипсета, ни у устройств в этом состоянии не сбрасываются, так что нас в этой статье оно интересовать не будет.
  • S2/S3 — Suspend to RAM, т.е. содержимое памяти остается валидным и обновляется, а процессор и часть чипсета отключаются полностью с потерей контекста и содержимого практически всех регистров. Разница между S2 и S3 минимальная, и чаще всего S2 вообще не выделяют в отдельное состояние. После пробуждения из S3 процессор начинает выполнять код с ResetVector'а, т.е. чтобы правильно «проснуться», ему нужно восстановить весь контекст для себя и чипсета. Вот на этом этапе разработчиков прошивки и подстерегает несколько подводных граблей, о которых мы и поговорим в этой статье.
  • S4 — Suspend to Disk, т.е. содержимое памяти сбрасывается на диск и система отключает все устройства и подачу питания. После включения система стартует как обычно, и с точки зрения UEFI между S4 и S5 разницы практически нет (а если отключить FastBoot, то совсем нет).
  • S5 — Soft-Off, т.е. система отключена, но дежурное питание присутствует. Из S4/S5 система может быть выведена по сигналу RTC, либо по Wake-сигналу от устройства, либо по нажатию кнопки питания.

Как реализован S3 в UEFI
Чтобы восстановить контекст при «просыпании», сначала его нужно где-то сохранить. При этом желательно не слишком привязываться к конкретным особенностям архитектуры процессора и чипсета, а таже сделать хранение и восстановление контекста максимально прозрачным, чтобы не умереть потом в отладке. Т.к. работоспособность S3 — очень важная характеристика практически любого современного ПК, за исключением серверов с годами аптайма, то технология сохранения и восстановления контекста была разработана инженерами Intel очень рано, в 2004 году, и получила название EFI S3 BootScript. С тех пор спецификация многократно дорабатывалась, последняя версия теперь находится в томе 6 спецификации UEFI PI.
Суть ее такова: после исполнения фазы PEI, в которой происходит инициализация базовых устройств, т.е. процессора, кэшей и оперативной памяти, система определяет текущий режим загрузки.
1. Если этот режим отличается от S3 Resume, загрузка продолжается как обычно, PEI заканчивается запуском диспетчера DXE, который создает новый пустой S3 BootScript и запускает все доступные DXE-драйверы. Каждый такой драйвер выполняет финальную инициализацию того устройства, за которое он отвечает, и затем добавляет в S3 BootScript команды, которые необходимо выполнить, чтобы повторить инициализацию устройства при возврате из S3. Команды могут быть примерно такими (список взят из спецификации PI 1.4, но в конкретных реализациях могут встречаются и нестандартные):
  • IO_WRITE — записать указанное значение в указанный CPU IO-порт
  • IO_READ_WRITE — изменить значение в указанном CPU IO-порту согласно указанной маске
  • IO_POLL — выполнять чтение из указанного IO-порта, пока не будет выполнено указанное условие, но не дольше указанного времени ожидания
  • MEM_WRITE — записать указанное значение по указанному физическому адресу
  • MEM_READ_WRITE — изменить значение по указанному физическому адресу согласно указанной маске
  • MEM_POLL — выполнять чтение по указанному адресу, пока не будет выполнено указанное условие, но не дольше указанного времени ожидания
  • PCI_CONFIG_WRITE — записать указанное значение по указанному адресу в конфигурационном пространстве указанного PCI-устройства
  • PCI_CONFIG_READ_WRITE — изменить значение по указанному адресу в конфигурационном пространстве указанного PCI-устройства согласно указанной маске
  • PCI_CONFIG_POLL — выполнять чтение по указанному адресу в конфигурационном пространстве указанного PCI-устройства, пока не будет выполнено указанное условие, но не дольше указанного времени ожидания
  • SMBUS_EXECUTE — передать указанную команду указанному устройству на шине SMBus
  • STALL — подождать указанное число микросекунд
  • DISPATCH — выполнить код по указанному адресу
Вышеуказанных команд вполне достаточно, чтобы повторно инициализировать любое устройство, особенно с учетом последней команды, просто передающей управление PEI-драйверу, который и выполняет всю инициализацию, но нужно это только для особо сложных случаев, когда остальными командами обойтись не получилось.
После окончания фазы DXE диспетчер сохраняет получившийся S3 BootScript в памяти типа AcpiNVS, в которой находятся ACPI-таблицы и другие данные, необходимые ОС для правильной работы ACPI в ней.
2. Если же при загрузке выяснилось, что система находится в S3 Resume, вместо диспетчера DXE запускается PEI-модуль с красивым именем BootScriptExecutor, который выполняет BootScript, бережно хранящийся в памяти со времен прошлой нормальной загрузки, а затем передает управление на ОС, которая успешно стартует и радует пользователя.
Словами, вроде бы, пояснил, теперь тоже самое — картинкой из спецификации:
Подводные грабли
Это все успешно работало около 10 лет, и практически никто не видел подвоха, пока в конце 2014 года широко известные в узких кругах товарищи Rafal Wojtczuk and Corey Kallenberg не представили атаку, которая оказалась одновременно очевидной и крайне опасной. Оказалось, что область памяти (типа AcpiNVS), которой хранится S3 BootScript, никак не защищена от модификации. Да, ОС воспринимает ее как служебную и не испортит содержимое самостоятельно, а вот атакующий с правами администратора — еще как.
Модификации могут быть весьма различными, но т.к. большая часть защитных механизмов, обеспечивающих защиту как от прошивки произвольно кода в микросхему SPI, так и от несанкционированного доступа в SMM, настраиваются через регистры процессора и чипсета, то для успешного обхода этих механизмов достаточно найти BootScript в памяти (это нетрудно), найти в нем нужный нам регистр (тоже никаких сложностей) и изменить его так, чтобы при следующем S3 Resume защита не смогла включиться. Меняем, засыпаем, просыпаемся — оп, а король-то голый! Чем грозит снятие защиты с микросхемы SPI и с SMM — я уже писал в прошлых частях, повторяться не буду, но ничем хорошим это определенно не закончится.
Интересно, что инженеры Intel предвидели эту атаку и заранее реализовали защиту от нее — т.н. SmmLockBox. Защита очень простая — после того, как составление скрипта закончится, он копируется целиком в SMRAM, при этом оригинальный BootScript не удаляется. При восстановлении из S3 вызывается обработчик SMI, который проверяет, что оригинальный BootScript совпадает с копией в SMRAM, а если нет — либо переписывает измененный BootScript копией, либо перезагружает машину (это безопаснее, но пользователь теряет все данные из RAM). Проблема оказалась в том, что SmmLockBox просто не успели вовремя внедрить, и когда Rafal и Corey тестировали найденную уязвимость, оказалось, что единственная неуязвимая к атаке плата — Intel'овский UEFI Development Kit.
После обнародования атаки IBV начали в спешке внедрять либо оригинальный SmmLockBox, либо свои аналоги, основанные на той же идее, но это внедрение часто буксовало по разным причинам. К примеру, на системах с процессором AMD инициализация SMM проводилась в фазе DXE, и потому вызов обработчика SMI из PEI при S3 Resume заканчивался неудачей и S3 переставал работать вообще.
Тем не менее, на данный момент все вендоры, слышавшие о безопасности хотя бы краем уха, уже решили проблему защиты содержимого S3 BootScript каким-либо способом, и если ваша прошивка новее июня 2015 года, а производитель вашей системы не мудак — скорее всего, ваша система прямой атаке на изменение S3 BootScript'а уже не подвержена.
Свинья от производителей платформ
После того, как паника немного улеглась, и BootScript успешно затолкали в SMRAM (понятно, что теперь надо хранить его как зеницу ока, но я об этом уже в прошлой части писал), неожиданно выяснилось, что инженеры Intel и AMD, сами того не зная, подложили обладателям своих платформ порядочную свинью в лице нескольких PEI-модулей, которые а) копировались в память прямо рядом с BootScript'ом, б) вызывались из него командой DISPATCH десятки раз и в) были достаточно большими, чтобы в SMRAM на их копии места не хватало.
Таким образом, выполнение произвольного кода можно было организовать без модификации самого BootScript'а вообще, вместо этого модифицировав точку входа одного из таких модулей. Удалить такие модули без нарушения работы S3 не получалось, но решение нашлось — вместо копирования в память их перенесли на неупакованную часть DXE-тома, и исправили команды DISPATCH так, чтобы код вызывался прямо с микросхемы SPI. Это оказалось немного медленнее, чем из RAM, зато свинью удалось таки выгнать. Я не знаю, сколько сейчас систем, которые можно атаковать этим способом, но подозреваю, что очень много.
Господа забывчивые
Человек не застрахован от ошибок, и разработчики DXE-драйверов — тоже человеки, и иногда могут банально забыть написать добавление какого-нибудь важного регистра в BootScript, и после S3 в этом регистре окажется его оригинальное значение. Чаще всего такая забывчивость приводит только к мелким глюкам после S3, но законы Мерфи говорят нам, что если какой-либо важный регистр может быть забыт — он обязательно будет забыт, что и происходит. Последний громкий пример забывчивости — опубликованная в конце мая этого года уязвимость в прошивках ноутбуков Apple, где инженеры забыли добавить в S3 BootScript запись в PR-регистры, и после S3 защита микросхемы SPI от прошивки снималась самостоятельно. Очень удобно ведь, закрыл-открыл крышку — и можно доставать flashrom и писать свой код в BIOS, Apple вновь радует простой и юзабилити. Если вы думаете, что случай единичный — советую запустить на своем ПК утилиту Chipsec и сравнить отчеты, сделанные до и после S3. Заодно и сюрприз может получиться.
Отключу S3 и трава не расти
Примерно это, только более экспрессивно и немного более матом, я воскликнул, когда столкнулся с проблемой впервые. К сожалению, этот вариант не всегда возможен (хотя S4 на SSD мало отличается по скорости, зато сильно отличается по надежности, никаких танцев со скриптами и экзекуторами не нужно), более того, если вы не отключили S3 намертво путем модификации прошивки, атакующий, способный запустить на вашей системе UEFI Shell, банально включит S3 обратно. В следующей части я постараюсь рассказать, как избежать такой незавидной судьбы, но коротко — включайте и пользуйтесь SecureBoot, он вовсе не зло, если уметь его готовить.
Кризис доверия
Вся эта история с S3 BootScript вскрыла одну интересную проблему, которую после 10 беззаботных лет разработки в UEFI серьезно начали решать только сейчас. Проблема состоит в том, что «безопасная» прошивка не может доверять ничему, к чему имеет или имела доступ ОС. Устройства нужно сбросить и инициализировать самостоятельно, память очистить и ничего из нее не использовать (не дай рандом вызывать оттуда код!), свои же Runtime-сервисы после события ReadyToBoot компонентам прошивки использовать нельзя (их уже хукнул атакующий, иногда по нескольку раз), в общем, сплошное минное поле, чуть оступился — и вот у тебя уже полный BIOS чужого кода, бэкдор на бэкдоре, честным драйверам в SMRAM места нет. Поэтому производители платформ ищут спасения в аппаратных решениях, кто-то внедряет validated boot, кто-то хранит S3 BootScript в Security Coprocessor'е, кто-то разрабатывает свой собственный крипточип, кто-то просто забил и ждет, пока ему решение UEFI Forum сверху спустит.
Вот и Intel добавила в Skylake интересную технологию SGX, которую можно использовать для изоляции отдельных кусков кода и данных от всего остального в системе, такой себе аналог SMM, только всем и даром, чтобы никто не ушел обиженным. Технология выглядит достаточно вкусно, но, во-первых, сложна в программировании, а во-вторых — есть только у Intel и только на Skylake.
Со стороны «безопасной» ОС — такой же точно уровень недоверия к прошивке, и тут может пригодиться технология STM, о которой разговоры велись с 2009 года, но представили ее официально только недавно, и «в бою» она еще не опробована. Когда дойдут руки попробовать обе — постараюсь про это написать.

Заключение


Ну вот, проблемы с S3 BootScript позади, в следующей части поговорим об атаках на NVRAM и SecureBoot, а также о том, почему пароль на BIOS — от честных людей.
По доброй традиции, посоветую знатокам английского языка вот эту статью тов. d_olex на ту же тему. Там серьезность, глубина, код, и картинки, не то что мое словоблудие тут.
Спасибо тебе за внимание, читатель, безопасных тебе прошивок.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

DoS эксплойт Chrome и некоторых других браузеров

сегодня в 04:45

Помните пост про эксплойт скайпа?
Сегодня обнаружился похожий эксплойт для браузера Chrome и некоторых браузеров на его движке, который приводит к падению браузеров целиком или только отдельной страницы.
В чем суть:
Если браузер увидит ссылку вида:
http://ift.tt/1JfREaj

(то есть в конце адреса любого сайта дописать "%%30%30")
то вот что происходит:

Chrome
При вставке ссылки в адресную строку и нажатии Enter — браузер падает полностью.

Скриншот
image

А если где-то на странице встречается такая ссылка, то при наведении мыши на не падает эта страница браузера
Скриншот
image

Opera
Также при наведении мыши падает

Скриншот
image

IE
Сообщение об ошибке, но браузер не падает.

Скриншот
image

Firefox
Ошибок от браузера нет, не падает. (Версия браузера: 40.0.2)

Steam
Если такую ссылку вставить в ленту активности, то клиент «подвисает» на этой странице. То есть вы можете, например, открыть библиотеку игр, играть, общаться с друзьями, но перейти в магазин или свой профиль не сможете. В браузере стима останется открытой лента активности. Помогает перезапуск клиента. Удалить ссылку после тестирования из ленты можно с помощью Firefox.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

[Перевод] JetBrains: переосмысление подписки и поиск стабильности

Перевод публикуется с разрешения автора, оригинал на Voxxed.

Когда 3 сентября JetBrains анонсировали изменения в своей лицензионной политике предложив подписочную модель для своих инструментов [IDE — при. пер.], они предполагали, что будут какие-то отзывы. В действительности на них обрушился настоящий поток, реакции были от умеренно возмущенных до откровенно апоплексических. В ответ компания опубликовала пост: мы действительно слушаем своих пользователей. Сегодня, в третий и последний раз, они опубликовали результаты пересмотра предложенной модели. Вот официальное tl;dr от авторов IntelliJ IDEA:

  1. Подписка остается, но с существенными изменениями.
  2. Вы получите резервную бессрочную лицензию как только оплатите годовую подписку: разом или последовательно (в течение 12 месяцев).
  3. Вы получите скидку до 40% за непрерывную подписку.
  4. У вас будет возможность использовать программное обеспечение без подключения к Интернету.
  5. Текущие пользователи с действующей или недавно истекшей подпиской на обновления получат первые два года подписки по цене одного.
  6. Мы все же рекомендуем вам прочитать статью целиком, чтобы ознакомится со всеми деталями.

В этом интервью Hadi Hariri, лидер команды Developer Advocacy, объясняет, почему компания была так ошеломлена первой реакцией сообщества, почему они не вернут все как было и почему эти изменения так важны для компании и ее будущего.
Voxxed: Будет честным отметить, что JetBrains устроили переполох своим первоначальным анонсом. Ожидали ли вы, что получите ту реакцию, которую получили?

Hariri: Мы ожидали некоторое количество отрицательных отзывов. Мы знали, что не всем это понравится. Есть такое выражение: люди не любят перемен, особенно тогда, когда они их затрагивают. Это и произошло, многие именно это и почувствовали.

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

Что, по вашему мнению, были причиной такой острой реакции?

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

Мы получили огромное количество отзывов и обоснованных опасений. Мы предположили, что, возможно, наши исследования были необъективны. Это заставило нас остановится и все пересмотреть. Было принято решение сказать людям, что мы переосмысливаем, слушаем и будем действовать в соответствии с этим — об этом был наш второй пост. Тем не менее, люди все еще были злы.

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

Кто из пользователей был больше всего разочарован?

Были опасения по поводу необходимости иметь подключение к Интернету. Часть людей волновалась из-за вещей, которые никогда не могли бы с нами произойти. Например, люди спрашивали, не хотим ли мы подсадить разработчиков на крючок, чтобы потом взвинтить цены? Здесь в JetBrains мы об этом ни когда даже и не думали, особенно учтивая, что солидная часть наших конкурентов — это бесплатные инструменты. Именно поэтому, если результат нашей работы не будет хорош, люди не будут им пользоваться.

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

Не могли бы вы обощить, что именно изменилось в сравнении с первоначальным анонсом?

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

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

Почему бы тогда просто не вернутся к предыдущей модели?

Для многих из наших продуктов мы выпускаем несколько мажорных релизов в год с различными фичами и другими серьезными улучшениями. Мы тратим столько же усилий на привлечение новых пользователей, сколько и на поддержку существующих. Мы можем это делать благодаря существенному расширению нашей пользовательской базы, но оно не может продолжаться до бесконечности. Нам нужно как-то выровнять нашу прибыль с затраченными усилиями. Ход с подпиской — попытка найти баланс, который даст нам стабильную бизнес-модель и позволит продолжить делать то, что мы любим, и что нравится нашим пользователям.

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

Является ли зрелость ваших программных продуктов одной из причин перехода к подписочной модели? Чувствуете ли вы, что теперь не будет необходимости делать новые фичи?

Я в это не верю, да и многие из наших неравнодушных пользователей отмечают, что JetBrains с каждым годом становится лучше. Ведь помимо новых фич мы должны поддерживать и все остальное, например Project Jigsaw (Java). У C# 6 есть новые фичи — мы должны поддерживать и его. И это не говоря уже об экосистеме JavaScript! Так что речь идет не только о добавлении новых фич, но также и о поддержке новых технологий.

Что вы ответите людям, которые считают, что все это из-за денег?

Сейчас в JetBrains работает 600 человек, большинство из которых разработчики. У нас нет венчурного капитала, мы не должны отвечать перед акционерами и тому подобное. Мы — компания, которая принадлежит частным лицам, и планируем такой и оставаться. Если мы это сделали, то только потому, что нам это нужно — оставаться стабильными.

Я не знаю как дела пойдут дальше — надеюсь, хорошо. Но что я знаю точно, так это то, что если наши пользователи несчастливы — несчастливы и мы, и не будет иметь значения, будем мы зарабатывать больше или нет. Обогатиться не является и ни когда не являлось нашей целью. Наша цель — это найти устойчивую модель, которая позволит нам заниматься тем, чем мы занимаемся сейчас.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

[recovery mode] «Деревянный» ЦОД группы Inoventica

ЦОД Inoventica размещается в Судогодском районе Владимирской области и является первым облачным ЦОД Группы компаний Inoventica. Сдан в коммерческую эксплуатацию в феврале 2012 года.

ЦОД обладает следующими преимуществами:
  • Современное высококачественное оборудование от компании HP;
  • Пропускная способность до 40 Тбит/c;
  • Ширина каналов 10 Гбит и 1 Гбит;
  • Круглосуточная техническая поддержка.

Оптимальная структура капитальных вложений при строительстве первого ЦОД Inoventica была достигнута за счет использования инновационных технологических решений (применение системы охлаждения по технологии фрикулинга и наличие системы удаленного мониторинга и управления инфраструктурой), а также автоматической системы управления сервисами. ЦОД был построен в рекордно короткие сроки — за шесть месяцев, при том, что общестроительные работы были завершены за 90 дней. Минимизация операционных затрат на этапе коммерческой эксплуатации ЦОД достигается за счет его интеграции в объект двойного назначения — рекреационно-оздоровительный комплекс. Из-за необходимости соблюдения единого экостиля всех построек комплекса ЦОД приобрел уникальный дизайн и название — первый в мире «деревянный» ЦОД.

При выборе места под строительство нашего первого ЦОД определяющими стали следующие факторы:
  • Непосредственная близость к собственной волоконно-оптической магистрали на стратегически важном направлении Москва — Владимир — Нижний Новгород, что позволило обеспечить необходимый уровень доступности и резервирования каналов для нашего ЦОД;
  • Территория, на которой построен ЦОД, находится за пределами субъекта федерации или районного центра, на значительной удаленности от крупных населенных пунктов, что в значительной мере защищает его от техногенных катастроф;
  • ЦОД расположен в лесопарковой зоне площадью 27 тыс. гектар, на территории парка-отеля «Жемчужина Золотого кольца»; средняя температура воздуха в данной местности, с учетом имеющихся здесь леса и озера, не поднимается выше 27 градусов, а качество воздуха позволяет применять, в отличие от условий, имеющихся в черте города, систему охлаждения на основе приточного воздуха без значительных затрат на его очистку.


Применение приточно-вытяжной системы охлаждения с функцией фрикулинга, которая смешивает свежий уличный воздух с отработанным воздухом из машзала в определенной пропорции, позволило значительно экономить как в холодное, так и в теплое время года.
Согласно нашим расчетам, температура воздуха для охлаждения серверов не должна превышать предельных 35—45 градусов, что соответствует оборудованию класса A4, основываясь на руководящих принципах по теплообмену в ЦОД ассоциации ASHRAE TC9.9 для ИТ-оборудования — от 5 до 45 °C при температуре точки росы в 12 °C TP (DP) и относительной влажности от 8 до 90 %).
Облачный ЦОД Inoventica принципиально отличается от любого другого ЦОД, построенного в России, так как в нем отсутствует механическое охлаждение, что позволило значительно повысить энергоэффективность объекта и смело заявить о том, что на сегодняшний день это самый экологичный ЦОД на всем постсоветском пространстве.

Изоляция горячего коридора позволяет предотвратить смешивание горячих и холодных потоков воздуха, а также предотвратить локальные перегревы.
Применение системы удаленного мониторинга и управления позволило строить ЦОД за пределами населенных пунктов, минимизируя операционные затраты и обеспечивая в конечном счете низкую себестоимость клиентского сервиса.
Данный подход не только демонстрирует отличные экономические показатели, которые, на наш взгляд, достаточно впечатлительные, но и особый подход нашей компаний к окружающей среде — бережное к ней отношение, а также стремление как можно более рационально использовать национальное богатство нашей страны.
Стоит также отметить, что расчетный коэффициент энергоэффективности ЦОД при полной загрузке должен составить порядка 1,07, что является значительным достижением не только в отечественной, но и в мировой практике строительства ЦОД. Такими же показателями могут похвастаться крупнейшие игроки интернет-рынка, например Google, Facebook, Yahoo.

Хотя в ЦОД есть огнетушители и пожарная сигнализация, а на территории комплекса присутствует собственная пожарная машина, мы сознательно отказались от установки газовой системы объемного пожаротушения. Такая система требуется по спецификациям Tier, но она не нужна для соответствия ГОСТ. Поскольку сервера являются нашей собственностью и застрахованы, перед нами не стоит цель спасать их любой ценой.

В качестве серверного оборудования мы используем в основном сервера производства Hewlett-Packard, и Supermicro различной конфигурации. Для организации высокопроизводительных и отказоустойчивых хранилищ данных используются продукты компании Hewlett-Packard (3PAR).

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

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

Как я участвовал в конкурсе Сбербанка про предсказание оттока клиентов

В рамках ICBDA 2015Сбербанк проводил конкурс про предсказание оттока своих клиентов. Я неслабо заморочился по этому поводу, ничего не выиграл и тем не менее хотел бы описать процесс решения.

Сбербанк щедро отгрузил данных. Нам дали ~20 000 пользователей, про которых было известно попали они в отток в ноябре, декабре, январе или нет. И было ~30 000 пользователей, для которых нужно было угадать уйдут ли они в феврале. Кроме этого прилагался файлик на 35Гб примерно такого содержания:
30.01.2015 09:22        29.01.2015 16:00        30.01.2015 09:22        EKGh+MraqvwwNT3GqgiMEN2/ySs=    kCE/6TYEHWRa4HwccK95Mq4YP+k=    443045  Самара  Почтовый        K+iMpCQsduglOsYkdIUQZQMtaDM=    2wNaK88zG9Yx/u5F2lFvNBHBgq4=    68APK1+X9Itc5/foOG78A1BhjHc=    5ECajFlJ8wgtg3Be+V6avsV1pgw=    JiMHOv2XOmO6Fiq7acyNJ7ybG8s=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    R823f2PM5MZ2kTwN/PWup/ocizA=    9tpw0k3iVpqAHzrlR2UMYtA6N2M=    Rob6shXTeqeQ/W4Sn19CJzuFW+M=    pbotcZX873SrDqATd+kosBvsOFY=    68APK1+X9Itc5/foOG78A1BhjHc=    REHZAJXiL/Fixs/9LqrqGgOTFC0=    lGKaUapcszPSt6UO77mm3R9jC1c=    c5DVo14pn+m59Jy8z2QUXorJtCo=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    IZJ4D+eekkxhXLOUJaZ+MQqmGGE=    443077  Самара  Юридический     K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    LR6ehKc5bT1KwZRwd/rc/uY5LiA=    2tobHSfP0RM0InwsKB0B2RfC3nk=    dJ/3XzbFv/Fd/1zsCwiDV4X9Dws=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    3bgl2TFAHdPT2qkZpZtKii1W5ac=    40moDWvi2ZOhvSUivfnzLRnjL+4=    K+iMpCQsduglOsYkdIUQZQMtaDM=    lXrM1IpuXivzJ1g9x8/NGEPJt9Q=    LR6ehKc5bT1KwZRwd/rc/uY5LiA=    +e0095FfDDZuFhsHLP5lMED3ttQ=    lGKaUapcszPSt6UO77mm3R9jC1c=    x+lNu8tXc34OwUCJEMQ9JfJnIp0=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    wpnh7B+yc22CcZrkRXlTsYcndxo=    Комиссия РКО    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    400000.0        400000.0        400000.0        wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     gu+AE/ARXawRDkF1uN3p/VFyHUw=    PROV    2wNaK88zG9Yx/u5F2lFvNBHBgq4=
01.03.2013 06:38        28.02.2013 16:00        01.03.2013 06:38        K+iMpCQsduglOsYkdIUQZQMtaDM=    oTXLCX+1oY7j5bQRHQeBnlv6pv0=    625048  Тюмень  Юридический     K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    LR6ehKc5bT1KwZRwd/rc/uY5LiA=    5GcyE42+h92lxrP20xfopBhm2hU=    JmS4MkjUwCLd9H1iWZTCnQ3009U=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    LeA91e1hh8TolYM2v8Md33VfsM0=    40moDWvi2ZOhvSUivfnzLRnjL+4=    K+iMpCQsduglOsYkdIUQZQMtaDM=    U+Nz/E4/rOeuSO5yQcWPr5vBjU4=    LR6ehKc5bT1KwZRwd/rc/uY5LiA=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    LG9280r6ZKr3gW8FGuNFKVqg66k=    625029  Тюмень  Юридический     K+iMpCQsduglOsYkdIUQZQMtaDM=    Antbbaf85R6dGC6FKWOZhUWY0Ps=    or83VmvYyVUx2hNUYOQXPo+JVPw=    K+iMpCQsduglOsYkdIUQZQMtaDM=    yQimGc+BR4slI19jTwkDBBDFVEw=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    oNQzXC2f9BzusSX6lAMGRgRUwMk=    9tpw0k3iVpqAHzrlR2UMYtA6N2M=    K+iMpCQsduglOsYkdIUQZQMtaDM=    7zk0pYI5nHZtFlsgp458x1IxWS8=    or83VmvYyVUx2hNUYOQXPo+JVPw=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    153750.0        153750.0        153750.0        wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     99mJrLpejr2E0IgD31Q2cGrVBfc=    PROV    Antbbaf85R6dGC6FKWOZhUWY0Ps=
27.01.2015 13:47        26.01.2015 16:00        27.01.2015 13:47        gZ0SI7XpYBPBnXjOQc8juxzoY/c=    fpzbQEHl82NiVVNPJKQVRHPbRsM=    109044  Москва  Юридический     K+iMpCQsduglOsYkdIUQZQMtaDM=    1X+UBlG07t36gjSIIdPmmPAqC6M=    hMxAglVE38hxluUM4fSVXqabAkQ=    KxwuJISsFaJtmMNblzUw/HLuB90=    ivblkef3XQi2UTgtVgxC6yOKwx8=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    y5Tl7KLkj310QuqpnGOiDM8agT0=    9tpw0k3iVpqAHzrlR2UMYtA6N2M=    IOBqzZS0aFreVYN33I/PbzhZzqg=    Fe/OH5JMHf6I0tL2BOBkm98IdXc=    hMxAglVE38hxluUM4fSVXqabAkQ=    CVMB3io2yaPGw/Krc3v/7aQz+Ws=    ByHiij4WTahzuNNLPcqJdKpoQ9I=    eGXHLSkEQzg+r4FMh5H8hrp7Tgg=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    qyu3UzMRa6YpWn8gCAxEIHyDDXE=    109544  МОСКВА  Юридический     K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    LR6ehKc5bT1KwZRwd/rc/uY5LiA=    feuiW2o7ET1rgBj7qgjQjxRKXRc=    DISDk4lki8N4+REEwCrYqP/sftQ=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    XziMVoejlSILvx9nkS8IwLr7f/U=    40moDWvi2ZOhvSUivfnzLRnjL+4=    K+iMpCQsduglOsYkdIUQZQMtaDM=    /Pbkdf/FCAShNHypf2GIcRyqfzQ=    LR6ehKc5bT1KwZRwd/rc/uY5LiA=    3UNnsbkaQUZPT/KwI2ldCh25Xq0=    ByHiij4WTahzuNNLPcqJdKpoQ9I=    HHsCUXCJpx9B8pWqCkvkTxc6CHU=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    qt4du/oGsA2UmjuJ2e6rp4m7czg=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    593220.0        593220.0        593220.0        wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     GAnLmHDZeSgmZXMIoSmO7TXovMo=    PROV    1X+UBlG07t36gjSIIdPmmPAqC6M=
26.06.2014 02:42        25.06.2014 17:00        26.06.2014 02:42        a0ZixkxJVju8yNHck+rmufP6LE4=    9e4hZde798SdydmuzPk+ZLfVUCo=    173009  Великий Новгород        Почтовый        6qVifvfceXwtxVrs9P01IB11Zyc=    3Ji3G+ARmzO1yVBTSXEWqZ/RpUI=    Na9xb8PpXgJeZj+xihgQHn2gdc0=    kqRQsgPScOPVd5oDV+zw+IUBusA=    dTERXJWzQRTmIOrEr6/pe/iQNs0=    K+iMpCQsduglOsYkdIUQZQMtaDM=    mPfUUmNnLU8bxfRysjFhzjRogQM=    SN5katQnekKDjC0q+YUCauj/nQQ=    9tpw0k3iVpqAHzrlR2UMYtA6N2M=    K+iMpCQsduglOsYkdIUQZQMtaDM=    q9QjDYtSH/+6e/NHdAWVT9B1M6M=    Na9xb8PpXgJeZj+xihgQHn2gdc0=    gVPa+gG3JV+E8zsaVFTs0vKiTgw=    6zly/tALWIksVkkTGtCZF4kNl50=    0IJF6vW5KDjKKz1lNMRKzAAHCvM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    jDRY3oGfXFLlH9T+9oKwk+G2zwM=    174406  БОРОВИЧИ        Почтовый        8NHZwcvtbn+LCCz43s7pGOY4UBs=    3Ji3G+ARmzO1yVBTSXEWqZ/RpUI=    pwCdHbjZVqmakV50R1HSRQbz8PM=    5/ws5kVuKtz6QESRwPvPz0jjurw=    HdeUf19XgiIlMLU6j4NH5jNRoig=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    Npz45hMcKJBMBdFE4ovXIB/Vjp4=    9tpw0k3iVpqAHzrlR2UMYtA6N2M=    K+iMpCQsduglOsYkdIUQZQMtaDM=    amGdo7mbrAGH+S1QlELG0BHJi08=    pwCdHbjZVqmakV50R1HSRQbz8PM=    YiSPZbeBZpXCVG5DzdLEbLQAmyU=    6zly/tALWIksVkkTGtCZF4kNl50=    1wrl8j0tjE2Lj82jdQfkuC30IDQ=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    2144960.0       2144960.0       2144960.0       wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     mPFBYItUYglELWkOfUnyuYIHe8U=    PROV    3Ji3G+ARmzO1yVBTSXEWqZ/RpUI=
10.12.2014 06:38        09.12.2014 16:00        10.12.2014 06:38        HC1kMBOyAU0TONoaqMgjfLip+dM=    UYh56W0ABat2pFZOCLegagXjH2U=    109439  Москва  Фактический     K+iMpCQsduglOsYkdIUQZQMtaDM=    1X+UBlG07t36gjSIIdPmmPAqC6M=    xDJw8OsOZ05UAYfqLLY3b6YiHac=    vIf+PQ+i6tr8iSvLLb3kzSe+E5A=    mCLg9y5cL8PI18uliJDpsbaOGAA=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    y3myHWlinvPvmVIfxj9yrajd/Kg=    9tpw0k3iVpqAHzrlR2UMYtA6N2M=    zJ9eY3dOBJftz2WCRaNe28qFBmc=    Sd6cIq3t7pmgxIinial5a+AQC5w=    xDJw8OsOZ05UAYfqLLY3b6YiHac=    a7g7e0UBN3M9Wsn9RGtUUXFgAR4=    ByHiij4WTahzuNNLPcqJdKpoQ9I=    dVQhMcirWkdw5zw73gMG/qI5PNw=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    null    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    CS3YMwLIuP0swS8myrV31ULCmGs=    2sCbZbq42P3mjf1/yVVUkBuCTMs=    SerGZ4dw0o2lzXPiDxEMxAWxTkE=    ByHiij4WTahzuNNLPcqJdKpoQ9I=    gQS6HcBAmyWfSH7QfbR3w48gWjA=    Od+lUoMxjTGv5aP/Sg4yU+IEXkM=    ONZZOkw+k/JrEHNJpKURA8eYVzA=    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    2084000.0       2084000.0       2084000.0       wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     6w7T/Bx7ioIqx8hiasT3d497waI=    PROV    1X+UBlG07t36gjSIIdPmmPAqC6M=


Физический смысл полей специально не раскрывался. Сказали «так интереснее». Было известно только, где искать id пользователей. Такой расклад показался мне крайне странным. Впрочем, Сбербанк тоже можно понять. Для начала этот адский массив данных я решил оставить в стороне и подробнее изучить пользователей из обучающего и тестового наборов.

Выяснилось невероятное: если пользователь не ушёл в ноябре и декабре, то и в январе он скорее всего не уйдёт. Если пользователь ушёл, то он скорее всего не вернётся:

Кроме этого оказалось, что 70% пользователей из тестовой выборки есть в обучающей. То есть напрашивается следующий гениальный классификатор: если пользователь ушёл в январе, то он будет в оттоке и в феврале, если не ушёл в январе, то и в оттоке его не будет. Чтобы прикинуть качество такого решения, берём всех пользователей из января и делаем для них предсказание по данным за декабрь. Получается не очень, но лучше чем ничего:

Да, понятно, что январь и февраль совершенно разные месяцы. Конец декабря, первая половина января вообще особенные для россиян. Но особого выбора нет, нужно же на чём-то проверять алгоритм.

Чтобы как-то улучшить решение, всё-таки придётся поразбираться в гигантском файле без описания. Первым делом я решил выкинуть все записи, в которых id не принадлежит ни одному пользователю из обучающей или тестовой выборки. О ужас, ни одной записи выкинуть не удалось. Одному пользователю там соответствует ни одна, а, в среднем, 300 записей. То есть, это какие-то логи, а не агрегированные данные. Кроме того, 50 из 60 колонок — это хеши. Логи с хешами вместо значений. В моём представлении это полный бред. Я люблю анализ данных за те моменты, когда удаётся открывать какие-то новые знания. В данном случае открытия могут выглядеть так: «если у пользователя в седьмом столбике часто встречается 8UCcQrvgqGa2hc4s2vzPs3dYJ30= значит, наверное, он скоро уйдёт». Не очень интересно. Тем не менее я решил проверить несколько гипотез, посмотреть, что получится.

Известно, что в каждой строчке лога есть два id, а не один. Поэтому я предположил, что мы работаем с какими-то транзакциями. Чтобы как-то это проверить, был построен граф, где в вершинах располагались id, а рёбра появлялись, если два id встречались в одной записи. Если в логе действительно транзакции, граф должен получится очень разреженным и должен хорошо группироваться в кластеры. Получилось не совсем то, что я ожидал, между кластерами на глаз было много связей:

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

Хорошо, если мы имеем дело с транзакциями, логичным дополнением к модели будет число входящих и исходящих транзакций. Действительно, среди тех, кто ушёл в январе, почти 40% имели менее десяти входящих транзакций.

Добавим это нехитрое условие в модель и получим уже неплохое качество:

Понятно, что просто количество транзакций — это не очень круто. Пользователь может сделать 500 транзакций в январе 2014 и легко уйти в январе 2015. Нужно смотреть на тренд. У утёкших, действительно, всё заканчивается на первом, втором месяце:

А у тех, кто остался историй посложнее:

Как-то просто добавить это условие в модель мне не удалось, поэтому пришлось обратиться к машинному обучению. Запили RandomForest на 500 деревьев глубиной 10 на фичах типа: «месяцев до первой транзакции», «месяцев до последней транзакции», «число месяцев с транзакциями». Качество немного подросло:

Резерв простых понятных решений был исчерпан. Поэтому пришлось закопаться в гигантский файл без описания ещё глубже. Для всех колонок было посчитано сколько уникальных значений там встречается.

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

Затем для колонок, в которых разумное число разных значений были посчитаны гистограммы:

Видно, что некоторые гистограммы похожи, например, 14 и 33, 22 и 41. Действительно, большинство полей идут парами (да, я вручную запилил граф корреляции признаков):

То есть часть колонок описывают id1, часть id2. Некоторые поля являются признаками транзакции. Чтобы наверняка убедиться какие колонки описывают пользователя, я посчитал как часто для одного id они принимают разные значения. Оказалось, что колонки с 5 по 15 почти никогда не принимают больше одного значения на id. Действительно, некоторые из них это название города, почтовый индекс. Они вошли в модель как категориальные. Остальные могут принимать разные значения для одного id (в основном null, конечно), поэтому они вошли в модель с весами.

Из-за всех этих категориальных фичей сложность модели очень сильно увеличилась, большинство новых признаков особого вклада не внесли. Но нашлась одна фича — 56-я. Она сильно повлияла. Качество значительно подросло:

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

Поподбирал ещё параметры для RandomForest. Разметил тестовую выборку. Убедился, что все кто ушли в январе, ушли и в феврале. Проверил что в целом доля ушедших нормальная. И заслал в Сбербанк. Но что-то видимо пошло не так, потому что в топ-3 я себя не обнаружил. А топ большего размера нам не показали.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

пятница, 18 сентября 2015 г.

[recovery mode] Microsoft выпустит свой собственный дистрибутив Linux

сегодня в 22:22

image

Да. Вы не ослышались: корпорация Microsoft действительно планирует выпустить собственный дистрибутив открытой операционной системы Linux. Именоваться он будет Azure Cloud Switch (ACS), и вкратце его можно описать, как кроссплатформенную модульную операционную систему для управления дата-центрами.
Вы наверняка в курсе, что в распоряжении Microsoft имеется личная облачная платформа Azure, которая позволяет хранить и обрабатывать громадные массивы данных, удалённо выполнять различные приложения и даже наделяет игровую консоль Xbox One дополнительной вычислительной мощностью. На сегодняшний день дата-центры Azure насчитывают более 300 000 мощных серверов.
Microsoft верит в будущее сетей открытого типа, поэтому ACS, прежде всего, нацелена на то, чтобы упростить настройку, мониторинг, диагностику и процесс управления дата-центрами и огромными массивами сетевых коммутаторов (в народе знаменитые, как «свитчи») самых разных производителей. ACS, если верить пресс-релизу, будет использовать все преимущества экосистемы Linux. Разумеется, система будет поддерживать не только софт, выпускаемый для неё Microsoft, но и любое другое open source программное обеспечение.
image
Microsoft выпустит свой собственный дистрибутив Linux
В пресс-релизе не говорится открыто, почему Microsoft решила использовать Linux в качестве основы данного дистрибутива. Но, скорее всего, причиной является тот факт, что большая часть сетевого оборудования работает именно под управлением Linux, вшитой в NAND-память устройств, а убедить производителей изменить свой подход у Microsoft вряд ли получилось бы.
Что ж, Линус Торвальдс может открыть шампанское по такому, пускай и маленькому, но поводу. Многие из нас и представить себе не могли, что Microsoft однажды пойдёт на такой необычный шаг. Но IT-индустрия развивается, и даже гигантские корпорации понимают, что монопольный подход к рынку не всегда выгоден.

delphi,php,C#, web

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

Alibaba запускает производительный и энергоэффективный дата-центр

Компания AliCloud, подразделение китайской корпорации Alibaba, занимающееся облачными сервисами, объявила о намерении запустить в работу «зеленый» дата-центр AliCloud Qiandao Lake Data Center. Это уже восьмой дата-центр компании, и его назначение — расширить возможности сервисов Alibaba, обеспечивая нормальную их работу. Дата-центр было решено построить из-за роста количества новых пользователей и развития общей инфраструктуры Alibaba.

Интересно, что объект будет расположен на берегу озера Цяньдаоху, провинция Чжэцян, Китай. Озеро это искусственное, образовалось еще в 1959 году после строительства местной гидроэлектростанции. На озере расположено 1078 островов из-за чего оно получило такое название. Общая площадь озера равна 573 км², объём — 17,8 км³. Общая площадь островов составляет около 86 км². Цяньдаоху — туристическая достопримечательность, но теперь здесь будет и технологический объект, на который стоит посмотреть — это AliCloud Qiandao Lake Data Center.

Инфраструктура и особенности


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

Здесь китайская компания планирует реализовать интереснейший проект — экономную в плане потребления энергии систему охлаждения, где будет использоваться холодная вода из озера. Здесь вода прохладная целый год, и подавляющее большинство систем дата-центра можно охлаждать именно при помощи воды. Такая система охлаждения удовлетворяет около 90% всех потребностей объекта в охлаждении. И еще 10% — это стандартные технологии, которые обычно применяются в дата-центра.

Благодаря реализации такой идеи, расходы на энергопотребление систем охлаждения удалось снизить на 80%. Плюс ко всему, дата-центр оказывает минимальное воздействие на окружающую среду.

В AliCloud Qiandao Lake Data Center отфильтрованная вода из озера прогоняется насосами через все уровни дата-центра. Затем вода попадает в 2,5 км канал, пересекающий местный город. В будущем тепло нагретой воды будет использоваться для обогрева местных домохозяйств и промышленных предприятий, расположенных неподалеку.

Интересно, что здесь будет использоваться и солнечная энергия, и гидравлика, и прочие нововведения. Благодаря работе с возобновляемыми источниками энергии коэффициент эффективности использования энергии (PUE) здесь ниже отметки 1,3, а эффективность использования воды (WUE) ниже 0,2.

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

Технологические особенности дата-центра


Собственные стойки компании, AliRack 2.0, позволяют компании доставить и обслужить около 5000 серверов в день, что в 10 раз больше, чем в случае использования традиционных методов. При этом плотность размещения серверов в дата-центре на 30% выше, чем в традиционном.

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

AliFlash — еще одна разработка компании, которая обеспечивает потребности Alibaba, плюс работает на 70% эффективнее, чем аналоги.

В настоящее время у Alibaba уже работают дата-центры в Пекине, Ханчжоу, Циндао, Ченьчжэне, Гонконге и Кремниевой долине, плюс вскоре будет введен в строй дата-центр в Сингапуре.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

О безопасности UEFI. Часть вторая

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

Часть вторая. SMM


Немножечко ликбеза
Информацию о SMM, благодаря специалистам по поисковой оптимизации и сетевому маркетингу (будь они здоровы!), решительно невозможно найти в сети по запросу «SMM», постоянно натыкаешься на предложения что-нибудь увеличить, ускорить и улучшить, поэтому будем проводить ликбез не отходя от снаряда.
System Management Mode — один из наиболее привилегированных режимов исполнения кода у x86/amd64-совместимых процессоров, впервые появившийся в специальной SL-версии Intel 80386. Начиная с 80486 поддерживается всеми x86 CPU, в том числе производства AMD и VIA.
Изначально SMM использовался для независимой от ОС реализации автоматического управления питанием и системными устройствами, т.к. научить этому ОС того времени было сложнее, чем добавить еще один режим исполнения в процессор.
Переход в режим SMM выполняется только при помощи специального прерывания — SMI, которое генерируется различными способами:
— аппаратно, выдачей высокого уровня на вывод SMI#
— самой системой, как результат каких-то событий
— программно, отправкой байта в CPU IO-регистр с заданным номером (чаще всего это регистр 0xB2)
Аппаратное SMI
Писать про него особенно нечего: подаем напряжение на ногу — имеем прерывание. Сейчас используется редко, т.к. почти на всех системах теперь имеются мультифункциональные GPIO, которые могут генерировать события, не прерывая работу ОС, плюс не нужна дополнительная логика для определения, кто же конкретно сгенерировал аппаратное SMI, ведь устройств много, а нога — одна.
Системные SMI
Источников системных SMI может быть довольно много, я перечислю лишь те, которыми можно управлять, включая и отключая их по желанию разработчика прошивки, взяв в качестве примера систему с чипсетом восьмой серии, т.е. с процессором Haswell/Broadwell:
  • xHCI SMI — генерируется USB-контролером, позволяет реализовать эмуляцию legacy USB и загрузку с USB-носителей в DOS
  • ME SMI — генерируется МЕ, позволяет работать с ним системам, которые не имеют нативного драйвера для основного интерфейса ME — HECI
  • GPIO unlock SMI — генерируется при снятии бита Lock с регистров управления выводами GPIO. На этот SMI разработчик прошивки может повесить собственный обработчик, в котором решать, позволять ли ОС управлять конкретным GPIO или нет.
  • Periodic SMI — генерируется чипсетом по внутреннему таймеру с настраиваемой периодичностью в 8/16/23/64 секунды, но обычно он отключен совсем.
  • TCO SMI — генерируется TCO-таймером, если он включен. TCO — это такой Intel-специфичный watchdog-таймер обратного отсчета, который ОС должна взводить каждые несколько секунд, чтобы сообщить watchdog'у, что она в порядке. Если таймер дотикает до нуля, генерируется SMI, в обработчике которого чаще всего происходит перезагрузка системы.
  • EC SMI — генерируется чипсетом при доступе к CPU IO-портам диапазона 0x62-0x66, на котором обычно находится EC, что позволяет наладить его эмуляцию либо защитить его прошивку от записи, к примеру. Чаще всего этот источник отключен и обращение к вышеуказанному диапазону сразу декодируется на шину LPC, куда физический EC и подключен. А если его нет — чипсет отвечает 0xFF на все запросы, и дело с концом.
  • APMC SMI, генерируется при записи в CPU IO-порт APM_CNT, подробнее о нем в следующем разделе.
  • SLP SMI, генерируется при переходе в состояния ACPI S1-S5, точнее при попытке установки бита SLP_EN. С помощью этого прерывания реализуются Sx-ловушки, позволяющие выполнить какой-то платформо-зависимый код перед уходом в сон или гибернацию.
  • IOTR SMI, генерируется при обращении к портам CPU IO. С помощью этого прерывания реализуются IO-ловушки, позволяющие эмулировать legacy-железо, висевшее раньше на IO-портах, т.е. SuperIO, клавиатуру, аудио-чипы, MIDI-, COM- и LPT-порты и некоторые другие вещи. Ваша USB-клавиатура работает в DOS только потому, что обращение к IO-портам 0x60/0x64 перехватывает либо SuperIO, либо IO Trap.
  • И пара-тройка других, о которых тут рассказывать надо слишком долго, всех интересующихся RTFM'ом шлю в даташит.

Программные SMI
Программные SMI генерируются чаще всего либо прошивкой, либо драйверами, но ничего не мешает атакующему с правами администратора в ОС (точнее, необходимы права на исполнение инструкции out) тоже генерировать их.
Программное SMI генерируется при записи в CPU IO-порт APM_CNT (чаще всего это порт 0xB2), в качестве параметра в регистре AL передается его номер. Таким образом, максимальное количество различных обработчиков программных SMI в системе — 256, но реально их от 0-5 на специализированных системах, подготовленных для работы с RTOS, до 15-20 на системах с кучей разного железа, которым надо управлять без вмешательства ОС.
Как реализован SMM
Для кода SMM-диспетчера и обработчиков SMI выделяется 1-3 области физической памяти, которую во всех «обычных» режимах исполнения чипсет помечает как область MMIO с несуществующим устройством, т.е. для всего остального мира эти области — сплошная череда 0xFF, которые невозможно перезаписать. Первая область, называемая обычно ASEG (т.е. «сегмент А»), предназначена для т.н. legacy SMM code, т.е. старых 16-битных обработчиков SMI, которых на современных системах уже нет. Имя сегменту досталось за то, что он находится по фиксированным физическим адресам 0xA0000 — 0xBFFFF. Вторая область с фиксированными адресами — HSEG(т.е. «высокий сегмент»), раньше находилась на 0xFEDA0000 — 0xFEDBFFFF, но на современных системах не используется, т.к. имеется гораздо более удобный сегмент с настраиваемыми адресом и размер — TSEG(т.е. «топовый сегмент»), в котором и находятся сейчас 99% кода, исполняемого в SMM, а в ASEG остается только небольшая заглушка для совместимости.
При переходе в SMM процессор сохраняет практически весь контекст (т.е. содержимое практически всех регистров, какие именно не сохраняются — зависит от конкретной микроархитектуры), причем к сохраненному контексту у обработчиков SMI есть полный доступ, и потому он может общаться с системой через изменение сохраненных значений.
Для ОС вызов SMM кода выглядит как волшебное изменение содержимого регистров и памяти, и хотя отследить длительность нахождения в SMM все же можно по косвенным признакам, а факт перехода в него — по непосредственным, при помощи чтения регистра MSR_SMI_COUNT до и после вызова инициации программного прерывания, но повлиять на длительность обработчика SMI ОС не может, поэтому SMM плохо совместим с hard-RTOS (стоит отметить, что вся архитектура x86 совместима с ними весьма через раз, но это другая история).
При настройках по умолчанию работающий в SMM код имеет полный доступ ко всей физической памяти на чтение и запись, полный доступ ко всем подключенным устройствам, в общем — может практически все, и при этом независим от ОС и недоступен из нее даже на чтение, что сильно затрудняет его анализ и делает код обработчиков SMI весьма привлекательной целью для атаки. Более того, если атакуемой системе доступна из SMM запись на SPI-микросхему (а она доступна во всех случаях, кроме систем с включенной PFAT, которые не найти с огнем, систем с Read-only BIOS'ом, которые встречаются еще реже, и систем с защитой через PR-регистры), то успешная атака может закончиться записью своего кода в BIOS, с последующем воровством, убийством и непотребством с гусями. Именно поэтому защитить SMM от вставки туда вредоносного кода — жизненно необходимо.
Атаки на SMM и защита от них
Забытый D_LOCK
Код в SMRAM не появляется там самостоятельно, сначала саму SMRAM нужно настроить, инициализировать физическую память, настроить TSEG так, чтобы все обработчики туда влезли, скопировать туда код SMM-диспетчера и обработчиков, настроить там таблицы дескрипторов — в общем, навести строгий уставной порядок, после чего обязательно снять бит D_OPEN, чтобы никто больше там ничего не испортил, и установить бит D_LOCK, чтобы D_OPEN нельзя было поставить назад. На некоторых старых системах установить D_LOCK забывали, и там SMM был отрыт всем ветрам, но во времена UEFI этого уже не происходит, так что этот вектор атаки ушел в историю.
SMM cache poisoning
Еще одна историческая атака — отравление кэша SMRAM, которую в 2009 году опубликовали Rafal Wojtczuk и Joanna Rutkowska. Суть атаки коротко — меняем тип памяти для региона SMRAM на Write-Back, организуем запись в регион SMRAM своего кода, запись в память не происходит, но при этом наш код остается в кэше второго уровня, после чего генерируем программное SMI и процессор читает данные не из SMRAM, а из кэша, и выполняет наш вредоносный код. Проблема решилась радикально — производители CPU запретили ставить режим WB на SMRAM, и потому системе с UEFI этой уязвимости не подвержены.
SMM call-out, она же SMM incursion attack
Но достаточно истории, перейдем к «современным» атакам. Начнем, пожалуй, с той самой SMM Incursion Attack, о которой тов. maseal упомянул в комментарии к первой части. Я специально поставил слово «современные» в кавычки, ибо этой атаке — сто лет в обед, впервые о ней сообщали еще в 2008 году как проблему тогдашних BIOS'ов, но в 2015 ее вновь переоткрыли Corey Kallenberg и Xeno Kovah. Атака простая как мычание — если обработчик SMI вызывает какой-либо код, находящийся вне SMRAM, то атакующий с правами на запись в физическую память может подменить вызываемый код на свой, и выполнить его таким образом в режиме SMM. А т.к. разработчики UEFI привыкли к доступности EFI Runtime-сервисов, то эти самые сервисы стабильно вызывались из обработчиков SMI на каждый чих (чаще всего это были вызовы GetVariable, SetVariable и ResetSystem). Уязвимости оказалось подвержено столько систем, что проще сказать, где их не было. По моей грубой оценке, если ваш UEFI старше мая-июня 2015 года по build date, в нем гарантированно имеется пара уязвимых к этой атаке обработчиков SMI. Вычистить систему от таких глючных обработчиков достаточно сложно, и т.к. раньше такое поведение вообще не считалось уязвимостью («какой дурак полезет сервисы хукать то?!») и о том, что так делать нельзя, не было известно простым IBV'шным кодерам — даже сейчас периодически приходят обновления для runtime-драйверов, подверженные этой проблеме. Все очень грустно, в общем.
Для защиты от вызова внешнего по отношению к SMRAM кода инженеры Intel добавили специальный MSR_SMM_FEATURE_CONTROL, после установки определенного бита в котором вызов такого кода генерирует немаскируемое и невосстановимое MCE, но есть такой MSR только в Haswell и более новых CPU, да и включается эта возможность только на время отладки прошивки, иначе за непонятные зависания на ровном месте пользователи могут к дверям отдела R&D прийти с вилами и дубьем — большинству нужно, чтобы работало и сейчас, а эта ваша безопасность вся — overhyped. Для обладателей более старых систем и система на базе процессоров AMD инженеры Phoenix нашли по своему гениальное решение — использовать NX-бит, настроив память для SMM-кода таким образом, чтобы вызов кода вне SMRAM заканчивался Page Fault'ом, который затем можно обработать, а не висеть намертво на MCE. Каюсь, я у себя пока еще это решение не внедрил, но когда дойдут руки — обязательно это сделаю.
Простому же пользователю от этой атаки можно защититься только не допуская исполнение непонятного кода от рута, но это, к сожалению, на современных ОС практически нереально — вариантов локального повышения прав как было море, так и остается, сколько таких 0day-эксплоитов на руках и в обороте, сказать невозможно. Остается только процитировать вышеупомянутого Xeno Kovah:

Please, please, please, go apply patches!


DMA attack
Еще одна интересная атака, на этот раз — с помощью своего же чипсета. Дело в том, что у современных чипсетов имеется контролер DMA, который используется для разгрузки CPU от задач пересылки данных из памяти и в память, как между DRAM, так и между DRAM и памятью PCIe-устройств. Причем инициировать такую передачу может как ОС, так и PCIe-устройство, у которого тоже может быть свой DMA-контролер. Причем, в случае инициации из ОС, операцию доступа к данным осуществляет чипсет, т.е. любые настройки процессора на него если и влияют, то достаточно слабо. Т.е. атакующий с правами администратора инициирует DMA с контролируемой им областью памяти с одной стороны и SMRAM с другой, и получает полный доступ к ней. То же самое может сделать и прошивка контролируемого атакующим PCIe-устройства. Для защиты от DMA-атаки у DMA-контролеров Intel имеется регистр TSEGMB в котором дублируется информация о местонахождении TSEG, и бит Lock, который запрещает это самое содержимое менять. Если авторы прошивки забыли установить (или восстановить при старте после S3, но об этом — в следующей части) — можно атаковать. Я не знаю, есть ли защита от DMA-атаки у чипсетов AMD, но постараюсь выяснить это в ближайшее время.
SMM cross-buffer attack
Представленная специалистами из Intel ATR атака на обработчики SMI, которые принимают в качестве параметра указатель и размер буфера, и производит запись в него. Атакующий может передать указатель и размер таким образом, чтобы буфер пересекал границу RAM-SMRAM, а т.к. обработчик SMI имеет доступ к SMRAM, то он перепишет какую-то часть данных вначале SMRAM. При удачном стечении обстоятельств (т.е. приблизительно после 500 часов отладки минимум) обработчик может переписать служебные структуры диспетчера SMM или других обработчиков нужным атакующему образом, и он получит возможность выполнения произвольного SMM-кода. Атака адски сложная и целевая, но вполне возможная, поэтому с начала 2015 года все обработчики SMI, принимающие указатели на буфер, обязаны валидировать его перед использованием. На более старых системах атака будет работать, но вероятность того, что именно вас через нее взломают — невелика.

Заключение


Ну вот, теперь разобрались более или менее и с SMM, в следующей части поговорим об атаках на S3 BootScript.
Спасибо за внимание, безопасных вам прошивок.

P.S.
Не могу не поблагодарить тов. d_olex за его статьи об SMM и атаках на него — раз и два. Для интересующихся темой и умеющих читать по английски — обе обязательны к прочтению.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

[Перевод] Охота на плохих парней: поиск неисправных серверов Netflix

Примечание переводчика:В нашем блоге мы много пишем о построении облачного сервиса 1cloud, но немало интересного можно почерпнуть и из опыта по работе с инфраструктурой других компаний. Мы уже рассказывали о дата-центре фотосервиса imgix, описывали детективную историю поиска проблем с SSD-дисками проекта Algolia, а сегодня представляем вашему вниманию адаптированный перевод заметки инженеров сервиса Netflix о том, как как они занимаются выявлением неисправных серверов.

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

В сериале Netflix «Сорвиголова», входящем в кинематографическую вселенную Marvel, Мэтт Мёрдок благодаря своим обостренным чувствам способен определять необычное поведение людей. Это позволяет ему замечать то, что не видят другие, например, он может «почувствовать», когда человек лжет. Мы решили создать подобную систему, которая бы искала неочевидные отклонения в работе серверов, способные вызывать проблемы с производительностью. В этом посте мы опишем наш автоматизированный способ выявления отклонений в работе серверов и их устранения, который спас нас от бессчетных часов ночного бдения.

В погоне за тенью


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

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

По фиолетовой линии на графике, приведенном выше, видно, что частота появления ошибок на этом сервере выше нормы. Все остальные сервера также имеют выбросы, но их характеристики «падают» обратно в ноль – а вот фиолетовая характеристика постоянно находится выше остальных. Расцените ли вы это как отклонение? Есть ли способ автоматически определять подобные отклонения на основании временных данных?

Сервер с серьезными проблемами работоспособности может быть легко обнаружен системами мониторинга, если значения задержек превышают некие пороговые значения. Однако такие системы требуют установки широких допусков, чтобы учитывать резкие скачки при обработке данных; также они требуют периодической настройки, в зависимости от объема данных и модели доступа. Ключевым шагом к достижению нашей цели – увеличению надежности – является автоматизация поиска неисправных серверов, которые не выявляются системами мониторинга.

Ищем иголку в стоге сена


Чтобы решить стоящую перед нами проблему, мы используем кластерный анализ, который является методом машинного «обучения без учителя». Целью кластерного анализа является объединение наиболее схожих объектов в группы. Достоинство техники «обучения без учителя» в том, что ей не нужна размеченная выборка, то есть нам не надо создавать тренировочный набор данных с примерами статистических выбросов. Существует достаточно большое количество различных кластерных алгоритмов, каждый из которых обладает своими достоинствами и недостатками. Для наших целей подойдет алгоритм кластеризации пространственных данных с присутствием шума DBSCAN (Density-Based Spatial Clustering of Applications with Noise).
Основная идея DBSCAN

DBSCAN – это кластерный алгоритм, который придумали Мартин Эстер (Martin Ester), Ганс-Питер Кригел (Hans-Peter Kriegel), Йорг Сандер (Jörg Sander) и Сяо Вей Ху (Xiaowei Xu) в 1996 году. Метод принимает на входе набор точек и маркирует как точки кластера те из них, которые имеют большое количество соседей. Точки, которые находятся в областях с меньшей плотностью, считаются статистическими выбросами. Если определенная точка принадлежит кластеру, то она должна находиться на определённом расстоянии от других точек этого кластера, которое определяется по специальной функции. Нафтали Харрис (Naftali Harris) в своем блоге привел отличную визуализацию метода DBSCAN.
Как мы используем DBSCAN

Чтобы наш метод выявления неисправных серверов заработал, владельцу сервиса необходимо определить метрику, которая будет использоваться в DBSCAN. Atlas – наша основная платформа динамической телеметрии – отслеживает эту метрику и формирует окно данных. Затем эти данные передаются алгоритму DBSCAN, который возвращает набор серверов с подозрением на неисправность. На изображении ниже показаны данные, которые поступают на вход алгоритма DBSCAN; область, выделенная красным – это текущее окно данных.

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

  • Связаться с владельцем сервиса по email;
  • Отключить сервер от сервиса, не останавливая его;
  • Собрать экспертные данные для дальнейшего расследования;
  • Остановить сервер, позволяя Auto Scaling Group заменить его.

Выбор параметров

Для настройки DBSCAN требуется два входных параметра: расстояние и минимальный размер кластера. Вот только владельцы сервисов не хотят утруждать себя подбором их верной комбинации, способствующей эффективному определению неисправных серверов. Мы упростили этот процесс: теперь им нужно просто указать текущее количество выбросов в момент конфигурирования (если такие есть). На основании этих данных мы можем сами определить расстояние и минимальный размер кластера с помощью алгоритма имитации отжига. Такой подход эффективно снижает сложность методологии, поэтому другим командам проще начать её использовать, а владельцам сервисов больше не надо забивать голову тонкостями работы алгоритма.

Проверка боем


Чтобы определить эффективность нашего метода, мы проверили его в боевых условиях на нашем рабочем сервисе. На основании недельных данных мы вручную определили, какие сервера должны попасть в категорию подозрительных и каким следует уделить внимание. Затем мы сопоставили наши результаты с результатами, предоставленными системой определения выбросов и получили возможность вычислить набор параметров, в том числе точность, полноту и F-меру.
Число серверов Точность Полнота F-мера
1960 93% 87% 90%

Глядя на эти результаты, мы видим, что идеально точно выбрать из огромного количества серверов все неисправные невозможно, но можно сделать это с довольно высокой вероятностью. Неидеальное решение вполне допустимо в нашей «облачной» среде, так как стоимость ошибки здесь достаточно мала. Поскольку отключаемые серверы сразу же заменяются «свежими», то ошибочная остановка сервера или его отключение оказывает незначительное воздействие на систему, если оказывает вообще. Статистических решений для автоматического восстановления должно быть достаточно; неидеальное решение лучше, чем никакого.

Дополнительно


Наша текущая версия системы использует mini-batch подход, когда мы формируем окно данных и используем его для принятия решения. По сравнению с обработкой в реальном времени наш алгоритм имеет недостаток: точность определения выброса связана с размером окна. Если выбрать слишком маленькое окно, то система начинает реагировать на шум, слишком большое – катастрофически падает скорость вычислений. Улучшенные подходы могут использовать достоинства фреймворков для потоковой обработки в реальном времени, таких как Mantis (система для потоковой обработки событий Netflix) и Apache Spark Streaming. Более того, в сферах поточных методов data-mining и динамического машинного обучения также была проделана огромная работа. Мы советуем любому, кто хочет внедрить подобную систему, обратить внимание на динамические техники, которые минимизируют время определения выбросов.

Можно усовершенствовать процесс выбора параметра, если внедрить еще два дополнительных сервиса: маркировщик данных для построения тренировочных наборов данных и сервер модели, который будет заниматься вычислением показателей производительности и переобучать модели с помощью приемлемого набора данных, собранных маркировщиком. Мы хотим позволить владельцам сервисов проводить начальную настройку перед определением неисправных серверов, путем маркировки данных (область, с которой они знакомы), передаваемых DBSCAN для вычисления параметров (область, которая лежит за пределами их компетенции) байесовским методом. Такой подход оптимизирует значения необходимых параметров на основании тренировочных данных.

Что дальше?


«Облачная» инфраструктура Netflix постоянно расширяется, а автоматизирование операционных решений открывает новые возможности, улучшая доступность сервиса и снижая количество ситуаций, когда требуется вмешательство человека. Сорвиголова использует свой костюм, чтобы усилить свои боевые качества, мы же можем использовать машинное обучение и автоматику, чтобы увеличить эффективность наших инженеров и on-call-разработчиков. Определение неисправных серверов – это всего лишь один из примеров подобной автоматизации. Другими хорошими примерами могут служить Scryer и Hystrix, а еще мы исследуем дополнительные области автоматизации, как то автоматизация:
  • Анализа и настройки таймаутов и порогов сервиса;
  • Canary Testing;
  • Переключения трафика во время плановых отключений электричества;
  • Тестов производительности, настраивающих правила для автоматического масштабирования.

Тем не менее, это – всего лишь некоторые из шагов на пути к построению самовосстанавливающихся систем огромных масштабов.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.