-Поиск по дневнику

Поиск сообщений в rss_rss_hh_new

 -Подписка по e-mail

 

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 17.03.2011
Записей:
Комментариев:
Написано: 51

Habrahabr/New








Добавить любой RSS - источник (включая журнал LiveJournal) в свою ленту друзей вы можете на странице синдикации.

Исходная информация - http://habrahabr.ru/rss/new/.
Данный дневник сформирован из открытого RSS-источника по адресу http://feeds.feedburner.com/xtmb/hh-new-full, и дополняется в соответствии с дополнением данного источника. Он может не соответствовать содержимому оригинальной страницы. Трансляция создана автоматически по запросу читателей этой RSS ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

[Обновить трансляцию]

Tizen: подводим итоги

Среда, 26 Июля 2017 г. 11:51 + в цитатник

PVS-Studio, Tizen, ИтогиНаша команда написала три заметки, связанные с анализом кода операционной системы Tizen. Операционная система содержит много кода и поэтому является благодатной почвой для написания различных статей. Думаю, что к Tizen мы ещё вернёмся в будущем, но сейчас нас ждут другие интересные проекты. Поэтому я подведу некоторые итоги проделанной работы и отвечу на ряд вопросов, возникших после опубликованных ранее статей.




Проделанная работа


Итак, наша команда написала 3 статьи:
  1. Андрей Карпов. 27000 ошибок в операционной системе Tizen. Фундаментальная статья, демонстрирующая всю важность использования статического анализа в больших проектах. Статический анализатор PVS-Studio отлично показал, как много различных паттернов ошибок он может обнаруживать в C/C++ коде.
  2. Андрей Карпов. Поговорим о микрооптимизациях на примере кода Tizen. На примере Tizen продемонстрировано, какие микрооптимизации кода предлагает анализатор PVS-Studio. Старый код править не стоит, но разрабатывать новый код с учетом этих рекомендаций следует однозначно.
  3. Сергей Хренов. Продолжаем изучать Tizen: C# компоненты оказались высокого качества. А вот здесь анализатор PVS-Studio не смог проявить себя. Неудача. Зато эта статья показывает, что мы честны в своих исследованиях. Удалось найти много интересных ошибок в C и C++ коде — мы написали про это. Не удалось найти ошибок в C# коде — про это мы тоже написали.

По итогам публикаций возникло два больших обсуждения: первое на Reddit, второе на Hacker News. Также появилось несколько новостных постов. Основные:
Всё это и натолкнуло меня на мысль обсудить несколько дополнительных тем и ответить на некоторые вопросы, которые поднимались в дискуссиях.

Надо всё переписать на Rust


В последнее время активизировались энтузиасты, агитирующие везде использовать Rust. Особенно бурный всплеск дискуссии на эту тему последовал после статьи "Rewrite the Linux kernel in Rust?".

Отметились эти энтузиасты и в комментариях к нашим статьям. Их предложение: чтобы не было таких ошибок, надо переписать всё на Rust.

Единорог facepalm


На самом деле, мне всё равно, будет что-то переписываться или нет. В мире написано так много кода на C и C++, что еще лет 50 анализатору PVS-Studio будет что проверять. Уж если до сих пор используются статические анализаторы для Cobol, то для C и C++ они также будут требоваться ещё многие десятилетия.

И тем не менее, я не могу обойти эту тему стороной. Вы серьезно предлагаете переписывать такие проекты на Rust? Вот взять и переписать 72 MLOC кода на Rust? Да это же сумасшествие!

Это потребует невероятного количества времени и сил. Более того, потратив много лет на разработку, вы в результате получите ровно то же, что уже и так существовало! Намного лучше было бы вложить эти человеко-годы в создание чего-то нового в уже существующем проекте.

Кто-то возразит, что после такого переписывания код станет лучше и надёжнее. Вот вообще нет такой гарантии. В крупных проектах значение языка не так велико. Вдобавок, многие библиотеки на C или C++ давно отлажены, а при переписывании придётся изобретать велосипеды, которые долгие годы будут радовать пользователей разнообразнейшими ошибками.

Я считаю, тот, кто предлагает переписать 72 MLOC кода, просто некомпетентен. Это можно простить новичку, но если это говорит человек с опытом работы, то он, видимо, тролль.

3.3% — это очень маленькая выборка и ваша оценка количества ошибок неверна


Да, такой подход может дать неточный результат. Но переживать об этом есть смысл, если мы проверили 1000, 3000 или 10000 строк кода. Переживать стоит и в том случае, если проверялся только один проект, написанный одной командой. В другом проекте плотность ошибок может сильно отличаться.

Но я напомню, что мною (при помощи анализатора PVS-Studio) было проверено 2 400 000 строк кода на C/C++. Это много! Это размер некоторых проектов.

При этом проверялся код разных проектов. Я использовал метод выборки «пальцем в небо». Очень хороший, честный способ. Вот список изученных мною проектов:

alsa-lib-1.0.28, aspell-0.60.6.1, augeas-1.3.0, bind-9.11.0, efl-1.16.0, enlightenment-0.20.0, ise-engine-anthy-1.0.9, bluetooth-frwk-0.2.157, capi-appfw-application-0.5.5, capi-base-utils-3.0.0, capi-content-media-content-0.3.10, capi-maps-service-0.6.12, capi-media-audio-io-0.3.70, capi-media-codec-0.5.3, capi-media-image-util-0.1.15, capi-media-player-0.3.58, capi-media-screen-mirroring-0.1.78, capi-media-streamrecorder-0.0.10, capi-media-vision-0.3.24, capi-network-bluetooth-0.3.4, capi-network-http-0.0.23, cynara-0.14.10, e-mod-tizen-devicemgr-0.1.69, ise-engine-default-1.0.7, ise-engine-sunpinyin-1.0.10, ise-engine-tables-1.0.10, isf-3.0.186, org.tizen.app-selector-0.1.61, org.tizen.apps-0.3.1, org.tizen.bluetooth-0.1.2, org.tizen.browser-3.2.0, org.tizen.browser-profile_common-1.6.4, org.tizen.classic-watch-0.0.1, org.tizen.d2d-conv-setting-profile_mobile-1.0, org.tizen.d2d-conv-setting-profile_wearable-1.0, org.tizen.download-manager-0.3.21, org.tizen.download-manager-0.3.22, org.tizen.dpm-toolkit-0.1, org.tizen.elm-demo-tizen-common-0.1, org.tizen.indicator-0.2.53, org.tizen.inputdelegator-0.1.170518, org.tizen.menu-screen-1.2.5, org.tizen.myplace-1.0.1, org.tizen.privacy-setting-profile_mobile-1.0.0, org.tizen.privacy-setting-profile_wearable-1.0.0, org.tizen.quickpanel-0.8.0, org.tizen.screen-reader-0.0.8, org.tizen.service-plugin-sample-0.1.6, org.tizen.setting-1.0.1, org.tizen.settings-0.2, org.tizen.settings-adid-0.0.1, org.tizen.telephony-syspopup-0.1.6, org.tizen.voice-control-panel-0.1.1, org.tizen.voice-setting-0.0.1, org.tizen.volume-0.1.149, org.tizen.w-home-0.1.0, org.tizen.w-wifi-1.0.229, org.tizen.watch-setting-0.0.1, security-manager-1.2.17.

Вряд ли мне «повезло» взять столько проектов, относящихся к одной команде. Очевидно, что здесь трудились разные команды специалистов.

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

Всё не так плохо, как вы утверждаете


После публикации моей статьи «27000 errors in the Tizen operating system» в интернете появилось несколько неграмотных новостей, где люди написали про большое количество уязвимостей, найденных в Tizen. Например, можно было встретить вот такие неграмотные заголовки «В коде операционной системы Tizen зафиксировано 27000 уязвимостей». Это, естественно, не соответствует действительности. Давайте я поясню почему.

Сразу скажу, что я писал не про уязвимости, а про ошибки. И ещё, в статье я нигде не говорил, что Tizen является некачественным кодом. Да, я говорю, что анализатор PVS-Studio выявляет много ошибок, однако в любом большом проекте ошибок будет много. Поэтому общее количество ошибок ещё не говорит о качестве кода.

Давайте теперь немного подробнее поговорим про уязвимости. Среди всех ошибок, которые встречаются в программах, выделяют security weaknesses. Их особенность в том, что возможно стечение обстоятельств, когда эта ошибка может использоваться злоумышленником. Эти типы ошибок описаны в CWE. CWE is a community-developed list of common software security weaknesses — https://cwe.mitre.org/.

В своей статье я классифицирую многие ошибки по классификации CWE. Однако это ещё ничего не значит. Дело в том, что такие ошибки удается очень редко использовать как уязвимости. Другими словами, очень редко удаётся превратить CWE в CVE. Подробнее с терминологией можно ознакомиться здесь: https://cwe.mitre.org/about/faq.html.

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

27000 ошибок говорит о хорошем или плохом качестве кода? Невозможно сказать. Однако это не является страшным числом, как может показаться на первый взгляд. Следует учитывать, что общий объём кода составляет 72 500 000 строк на языке C, C++ (без учёта комментариев). Получается, что анализатор PVS-Studio выявляет приблизительно 0,37 ошибки на 1000 строк кода. Или другими словами около 1 ошибки на 3000 строк кода.

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

Итак, PVS-Studio выявляет приблизительно 0,37 ошибок на 1000 строк кода. Это много или мало? Скорее, средне. Бывает лучше и хуже. Вот некоторые примеры:
Подведём итоги. На самом деле никакой сенсации нет. Шокирует число в 27000 ошибок, но такая внушительная цифра связана с большим размером проекта Tizen. Если взять другой большой проект, там тоже будет много ошибок.

Целью моей статьи было показать, что инструмент PVS-Studio может быть полезен проекту Tizen. И кажется, мне это удалось. Однако я вовсе не ожидал той бурной реакции и обсуждения, которые возникли вокруг этой статьи. Мы регулярно пишем подобные заметки. С ними можно ознакомиться здесь: https://www.viva64.com/ru/inspections/

В статье не указан процент ложных срабатываний


Начну издалека. К сожалению, многие читатели знакомятся со статьями очень невнимательно. В результате они довольно часто неправильно воспринимают числа, которые в них указываются. Я уже хорошо знаком с этим эффектом и стараюсь учитывать это в статьях. Например, в статье про «27000 ошибок» я специально дважды написал, что я нашел 900 ошибок, изучив 3.3% кода. При этом подчеркивал, что речь идёт именно об ошибках, а не о количестве выданных анализатором предупреждений.

И хотя я подстраховался, всё равно появился вот этот комментарий:

900 варнингов в аналоге Lint'а не означает 900 багов. Я бы даже сказал, что эти показатели вообще не связаны никак. Наверняка, там обнаружены ошибки в форматировании кода, областях видимости переменных и т.д. В топку таких аналитегов.

Человек не читал статью, но увидел число 900 и спешит поделиться своим мнением с другими.

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

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

Точно так же дело обстоит и с Tizen. Однако боюсь, на эти объяснения и примеры мало кто обратит внимание. Зато все запомнят число, означающее большой процент ложных срабатываний.

Возникает логичный вопрос: Тогда почему бы вам не настроить статический анализатор и не показать сразу хороший результат?

Отвечаю. Это займёт время, а меня ещё ждут такие интересные проекты, как iOS или Android. Однако это не главная причина, почему я не хочу этим заниматься. Дело в том, что непонятно где остановиться. Я знаю, что, приложив усилия, мы сможем свести количество ложных срабатываний до нуля, ну или почти до нуля. Например, мы сводили до нуля количество ложных срабатываний, когда работали над проектом Unreal Engine (см. статьи 1, 2).

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

Так как же программисту понять, хорошо работает наш анализатор или плохо? Очень просто! Нужно его скачать и попробовать проверить рабочий проект. Cразу станет понятно, нравится он или нет. И будет сразу видно, как много ложных срабатываний и какого они типа. После чего, возможно, ваша компания с удовольствием пополнит список наших клиентов.

Только прошу не совершать ошибку и не пробовать анализатор на маленьких проектах или вообще тестовых примерах. Причины:
Update. Вношу это примечание уже после написания статьи. Хорошо, читатели победили. Я сдаюсь и привожу число. Я провёл исследование EFL Core Libraries и вычислил, что статический анализатор PVS-Studio будет выдавать около 10-15% ложных срабатываний. Вот статья про это: пока не опубликована, чуть-чуть подождите.

Достаточно -Wall -Wextra -Werror


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

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

Впрочем, кроме слов у меня есть и доказательства. Каждый раз, когда мы проверяем какой-нибудь компилятор, мы находим там ошибки:
При этом не стоит забывать, что статический анализ — это не только предупреждения, это ещё и инфраструктура. Вот некоторые возможности PVS-Studio:
  • Удобная и простая интеграция с Visual Studio 2010-2017.
  • Интеграция с SonarQube.
  • Утилита BlameNotifier. Инструмент позволяет рассылать письма разработчикам об ошибках, которые PVS-Studio нашел во время ночного прогона.
  • Mass Suppression — позволяет подавить все старые сообщения, чтобы анализатор выдавал 0 срабатываний. К подавленным сообщениям всегда можно вернуться позже. Возможность безболезненно внедрить PVS-Studio в существующий процесс разработки и сфокусироваться на ошибках только в новом коде.
  • Сохранение и загрузка результатов анализа: можно ночью проверить код, сохранить результаты, а утром загрузить их и смотреть.
  • Поддержка IncrediBuild.
  • Mark as False Alarm — разметка в коде, чтобы не ругаться конкретной диагностикой в конкретном фрагменте файла.
  • Интерактивная фильтрация результатов анализа (лога) в окне PVS-Studio: по коду диагностики, по имени файла, по включению слова в текст диагностики.
  • Статистика ошибок в Excel — можно посмотреть темпы правки ошибок, количество ошибок во времени и т.п.
  • Автоматическая проверка на наличие новых версий PVS-Studio (как при работе в IDE, так и при ночных сборках).
  • Использование относительных путей в файлах отчета для возможности переноса отчета на другую машину.
  • CLMonitoring — проверка проектов, у которых нет файлов Visual Studio (.sln/.vcxproj); если вдруг вам не хватит функциональности CLMonitoring, то вы можете интегрировать PVS-Studio в любую Makefile-based систему сборки вручную.
  • pvs-studio-analyzer — утилита аналогичная CLMonitoring, но работающая под Linux.
  • Возможность исключить из анализа файлы по имени, папке или маске.

Подробнее про всё это можно узнать в документации.

Нет цены


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

Мы позиционируем PVS-Studio как B2B решение. При продаже компаниям необходимо обсудить множество моментов, которые влияют на цену лицензии. Вывешивать какую-то конкретную цену на сайт не имеет смысла и продуктивнее сразу приступить к обсуждению.

Почему мы не работаем с индивидуальными разработчиками? Мы пробовали, но у нас не получилось.

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

Не все участки, которые вы упоминаете в статье, являются настоящими ошибками


Да, возможно что-то окажется не ошибкой при более тщательном изучении кода. С другой стороны, при тщательном анализе может выясниться, что я, наоборот, пропускал некоторые ошибки. Например, я поленился изучать предупреждения V730 — Not all members of a class are initialized inside the constructor. Очень трудоёмко пытаться понять в чужом коде, является ли ошибкой, что какой-то член класса остался неинициализированным. Однако, если этим заняться, наверняка найдутся настоящие ошибки.

Давайте разберем один из таких случаев. Код относится к проекту org.tizen.browser-profile_common-1.6.4.

Для начала рассмотрим определение класса BookmarkItem.
class BookmarkItem
{
public:
    BookmarkItem();
    BookmarkItem(
        const std::string& url,
        const std::string& title,
        const std::string& note,
        unsigned int dir = 0,
        unsigned int id = 0
        );
    virtual ~BookmarkItem();

    void setAddress(const std::string & url) { m_url = url; };
    std::string getAddress() const { return m_url; };

    void setTitle(const std::string & title) { m_title = title; };
    std::string getTitle() const { return m_title; };

    void setNote(const std::string& note){m_note = note;};
    std::string getNote() const { return m_note;};

    void setId(int id) { m_saved_id = id; };
    unsigned int getId() const { return m_saved_id; };

    ....
    ....

    bool is_folder(void) const { return m_is_folder; }
    bool is_editable(void) const { return m_is_editable; }

    void set_folder_flag(bool flag) { m_is_folder = flag; }
    void set_editable_flag(bool flag) { m_is_editable = flag; }

private:
    unsigned int m_saved_id;
    std::string m_url;
    std::string m_title;
    std::string m_note;
    std::shared_ptr m_thumbnail;
    std::shared_ptr m_favicon;
    unsigned int m_directory;
    std::vector m_tags;
    bool m_is_folder;
    bool m_is_editable;
};

Для нас интерес представляют члены m_is_folder и m_is_editable. Обратите внимание, что они находятся в конце описания класса. Я готов поставить $10 на то, что изначально их не было в первой версии класса и появились они уже позже, в процессе развития проекта. Так вот, когда добавляли эти члены, был модифицирован только один конструктор.

В результате мы имеем вот такие два конструктора:
BookmarkItem::BookmarkItem()
: m_saved_id(0)
, m_url()
, m_title()
, m_note()
, m_thumbnail(std::make_shared<.....>())
, m_favicon(std::make_shared<.....>())
, m_directory(0)
, m_is_folder(false)
, m_is_editable(true)
{
}

BookmarkItem::BookmarkItem(
                const std::string& url,
                const std::string& title,
                const std::string& note,
                unsigned int dir,
                unsigned int id
                        )
: m_saved_id(id)
, m_url(url)
, m_title(title)
, m_note(note)
, m_directory(dir)
{
}

Один конструктор инициализирует члены m_is_folder и m_is_editable, а другой — нет. У меня нет абсолютной уверенности, но скорее всего это ошибка.

Анализатор PVS-Studio выдаёт для второго конструктора следующее предупреждение: V730. Not all members of a class are initialized inside the constructor. Consider inspecting: m_is_folder, m_is_editable. BookmarkItem.cpp 268

Кстати, анализатор PVS-Studio умеет искать 64-битные ошибки. Tizen пока 32-битный, так что для него они пока не актуальны, но я хочу посвятить пару слов этой теме.

Я предвижу 64-битные ошибки


На самом деле, никаких «64-битных ошибок» не существует. Однако есть смысл выделять некоторые ошибки в такую категорию и рассматривать их отдельно. Дело в том, что такие ошибки никак не проявляют себя в 32-битной версии приложений. Причем совсем не проявляют и их невозможно обнаружить никаким тестированием.

Рассмотрим простой пример для пояснения. Нужно создать массив указателей и для этого написан вот такой ошибочный код:
int **PtrArray = (int **)malloc(Count * size_of(int));

Память выделяется для массива int, а не для массива указателей. Правильный код должен был быть таким:
int **PtrArray = (int **)malloc(Count * size_of(int *));

Ошибка в 32-битной программе не проявляет себя. Размер указателя и типа int совпадают, поэтому выделяется буфер правильного размера. Всё корректно работает и проблемы начнутся только когда мы начнем собирать 64-битную версию программы.

Примечание. Конечно, в некоторых 64-битных системах размер указателя также может совпадать с размером типа int. А может быть так, что размеры будут отличаться и в 32-битных системах. Это экзотика, про которую нет смысла говорить. Рассмотренный пример будет корректно работать во всех распространённых 32-битных системах и давать сбой в 64-битных.

На нашем сайте можно найти много интересных материалов, посвященных 64-битным ошибкам и способам борьбы с ними:
  1. Коллекция примеров 64-битных ошибок в реальных программах
  2. C++11 и 64-битные ошибки
  3. Undefined behavior ближе, чем вы думаете
  4. Уроки разработки 64-битных приложений на языке Си/Си++

Вернёмся к проекту Tizen и возьмём для примера проект capi-media-vision-0.3.24. Здесь можно наблюдать интересную разновидность 64-битных ошибок. Анализатор PVS-Studio выдаёт для него 11 предупреждений с кодом V204:
  1. V204 Explicit conversion from 32-bit integer type to pointer type. mv_testsuite_common.c 94
  2. V204 Explicit conversion from 32-bit integer type to pointer type. mv_video_helper.c 103
  3. V204 Explicit conversion from 32-bit integer type to pointer type. mv_video_helper.c 345
  4. V204 Explicit conversion from 32-bit integer type to pointer type. mv_mask_buffer.c 39
  5. V204 Explicit conversion from 32-bit integer type to pointer type. mv_surveillance.c 52
  6. V204 Explicit conversion from 32-bit integer type to pointer type. mv_surveillance.c 134
  7. V204 Explicit conversion from 32-bit integer type to pointer type. mv_surveillance.c 172
  8. V204 Explicit conversion from 32-bit integer type to pointer type. surveillance_test_suite.c 452
  9. V204 Explicit conversion from 32-bit integer type to pointer type: (unsigned char *) malloc(buf_size) surveillance_test_suite.c 668
  10. V204 Explicit conversion from 32-bit integer type to pointer type: (unsigned char *) malloc(buf_size) surveillance_test_suite.c 998
  11. V204 Explicit conversion from 32-bit integer type to pointer type: (unsigned char *) malloc(buf_size) surveillance_test_suite.c 1109

Эти предупреждения выдаются на первый взгляд на совершенно безобидный код вот такого вида:
*string = (char*)malloc(real_string_len * sizeof(char));

В чем же причина? Дело в том, что нигде не подключен заголовочный файл, в котором объявлен тип функции malloc. В этом можно убедиться, выполнив препроцессирование C-файлов и посмотрев содержимое i-файлов. Использование функции malloc есть, а её объявления нет.

Так как эта программа на языке Си, то она компилируется, несмотря на отсутствие объявления. Раз функция не объявлена, то считается, что она принимает и возвращает аргументы типа int.

Т.е. компилятор считает, что функция объявлена так:
int malloc(int x);

Благодаря этому 32-битная программа отлично компилируется и работает. Указатель помещается в тип int и всё хорошо.

Эта программа будет компилироваться и в 64-битном режиме. Она даже почти всегда работает. Важно вот это самое «почти всегда».

Всё будет хорошо, пока память выделяется в младших адресах адресного пространства. Однако в процессе работы память в младшей части адресного пространства может оказаться занятой или фрагментированной. Тогда менеджер памяти вернёт память, выделенную за пределами младших адресов. Произойдёт сбой из-за обрезания старших бит в указателе. Подробнее, как и что происходит, я описывал здесь: "Красивая 64-битная ошибка на языке Си".

В итоге мы видим 11 дефектов, которые могут приводить к трудновоспроизводимым сбоям программы. Очень неприятные ошибки.

К сожалению, диагностики PVS-Studio для выявления 64-битных ошибок генерируют много шума (ложных срабатываний) и с этим ничего нельзя сделать. Такова их природа. Анализатор часто не знает, каков диапазон тех или иных значений, и не может понять, что код будет работать правильно. Но если хочется сделать надёжное и быстрое 64-битное приложение, следует поработать со всеми этими предупреждениями. Кстати, мы можем взять на себя эту кропотливую работу и выполнить на заказ портирование приложения на 64-битную систему. У нас есть опыт по этому направлению (см. "Как перенести проект размером в 9 млн строк кода на 64-битную платформу").

Так что если разработчики Tizen захотят сделать систему 64-битной, то знайте, наша команда готова помочь в этом.

Заключение


Спасибо всем за внимание. Тем, кто заинтересовался анализатором PVS-Studio и хочет узнать больше о его возможностях, предлагаю посмотреть большую презентацию (47 минут): PVS-Studio static code analyzer for C, C++ and C#.

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



Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Andrey KarpovDate: 26.07.2017. Tizen: Summing Up

Прочитали статью и есть вопрос?
Часто к нашим статьям задают одни и те же вопросы. Ответы на них мы собрали здесь: Ответы на вопросы читателей статей про PVS-Studio, версия 2015. Пожалуйста, ознакомьтесь со списком.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334172/


Skype-бот с человеческим лицом (на Microsoft Bot Framework V3 и Slack API)

Среда, 26 Июля 2017 г. 11:38 + в цитатник


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



Перед школой Skyeng всегда стояла задача создания удобного канала связи между мессенджарами и операторами службы поддержки пользователей. Мессенджер, который сейчас принимает у нас наибольшее число заявок, – Skype. Когда количество контактов в Skype исчисляется тысячами, общение напрямую через клиент Skype становится проблематичным. Во-первых, производительность этого клиента при такой работе падает почти до нуля, контакт-лист подгружается непозволительно долго. Во-вторых, часто нескольким операторам нужно вести параллельную связь с пользователями; использование одного Skype-аккаунта на нескольких устройствах возможно, но входящие сообщения из всех диалогов видны всем операторам, что мешает работе. Кроме того, все коммуникации в Skype остаются в самом Skype, для их извлечения во внутренние CRM или HelpDesk системы приходится заниматься копи-пейстом.

Эти трудности привели нас к решению создать чат-бот, который будет служить точкой входа для сообщений в службу поддержки. Тема чат-ботов в последнее время весьма популярна, и Microsoft предоставила доступ к Skype REST API, к которому прилагается SDK с примерами для C# и Node.js.

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

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



Архитектура


Система не подразумевает каких-то сложных вычислений на сервере; основные ее задачи – прием, хранение и роутинг данных. Поэтому в качестве основной платформы был выбран Node.js, хорошо подходящий для подобных задач. Взяли последнюю доступную LTS версию, на момент старта проекта – 6.3.0. Согласно node.green шестерка покрывает 95% ES 2015, что весьма приятно, а nodesource-блог обещает ее функционирование вплоть до апреля 2018, после чего начнется фаза maintenance. Годится.



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

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

В результате получилась следующая схема работы:



Система состоит из трех основных сервисов (Skype service, Logic service, Slack service) и дополнительного микро-сервиса Slack messaging micro-service. Основная задача Slack service – обеспечение работы endpoint-а для Skype-бота и отправка сообщений в Skype. Logic service отвечает за роутинг сообщений, хранение сообщений, обработку команд и предоставление API для интеграции с внутренними сервисами школы. Slack service имеет подписку к Slack RTM и отвечает за endpoint по приемке команд от операторов поддержки в Slack.

Дополнительный Slack messaging micro-service понадобился для того, чтобы уверенно отправлять сообщения в Slack, не боясь превысить лимиты Slack API, поэтому сообщения отправляются путем long-polling считывания их по таймеру из RabbitMQ и передачи в Slack.

Можно ли доверять Preview? Миграция на Microsoft Bot Framework


Использование preview-версий инструментов всегда несет в себе определенный риск, поскольку к моменту релиза в них могут произойти серьезные изменения или, что еще хуже, этот релиз вообще не состоится. Именно такая участь постигла SDK для разработки Skype-ботов: он появился в виде preview и в этом же виде состарился (получил статус deprecated). После этого создание новых ботов исключительно для Skype стало невозможным, а затем и вовсе появились редирект на Microsoft Bot Framework и предупреждение о необходимости мигрировать в ближайшее время.




Microsoft Bot Framework – это попытка Microsoft охватить множество каналов связи в одном инструменте. На данный момент поддерживаются: Facebook Messenger, Kik, Slack, Telegram, Skype и даже такие каналы, как Email, Twilio (SMS) и Direct Line. Все это интересно, но на данном этапе нас интересовал только Skype (хотя задел, конечно, хороший, можно впоследствии добавить поддержку других мессенджеров с меньшими трудозатратами).



Мы не стали ждать и мигрировали сразу. Регистрация нового бота в Microsoft Bot Framework проста, достаточно иметь аккаунт Microsoft.

Алгоритм следующий:
  • пройти по ссылке;
  • заполнить все поля со звездочкой;
  • нажать Create Microsoft App ID and Password;
  • откроется новая страница, на которой нужно ввести название приложения например TestBotApp;
  • далее кнопка Generate a password to continue;
  • сгенерированный пароль нужно где-то себе сохранить, поскольку посмотреть повторно его уже нельзя, а он понадобится для работы с Framework и App ID;
  • далее кнопка Finish and go back to Bot Framework;
  • на странице регистрации нужно принять соглашение и нажать Register, после чего у нас есть готовый зарегистрированный бот для Microsoft Bot Framework

На странице регистрации есть поле Messaging endpoint, оно не обязательно для регистрации, но это точка входа для бота, без которой он не будет функционировать. Основное требование к endpoint'у – это должна быть рабочая HTTPS-ссылка.

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

bot.send(
   '8:skype.username',
   'message from bot to user',
   true, // escape
   (error) => console.log(error)
);

превратилось в

bot.send(
   new builder.Message()
   .address({
       channelId: "skype",
       user: {
           id: "29:some-long-hash-here",
           name: "User Display Name"
       },
       bot: {
           id: "28:bot-uuid",
           name: "Bot Name"
       },
       serviceUrl: "https://skype.botframework.com",
       useAuth: true
   })
   .text('Message from bot to user'),
   (err) => console.log(err)
);

И небольшие изменения приема сообщений:

bot.on('personalMessage', (bot, data) => {
 console.log('Got message from user');
});

Поскольку в Bot Framework есть такое понятие, как диалоги, но нам нужно было просто получать сообщения, то мы сделали подписку на самый общий диалог, который представлен слэшем; он будет принимать все входящие сообщения:

bot.dialog("/", [
   (session) => {
       console.log("Got message from bot", session.message);
   }
]);

В приведенных фрагментах кода bot в случае Skype Bot SDK – экземпляр класса BotService, а на Bot Framework это уже UniversalBot.

Также стоит отметить, что если в Skype Bot SDK мы надеялись иметь возможность по id пользователя примерно понимать, с кем имеем дело, то в Microsoft Bot Framework все пользователи представлены в виде длинных хэшей, что делает собеседников анонимным. Задачу определения личности можно решить только в живом диалоге с пользователем.

Еще один любопытный момент – редактирование отправленных ботом сообщений. В Skype Bot SDK, как говорят некоторые пользователи github, такая возможность была, а вот в Microsoft Bot Framework именно для Skype ее нет (хотя для других платформ, в частности Telegram и Slack, это возможно).

Тем не менее, Microsoft Bot Framework – хороший шаг к унификации платформы разработки ботов для различных каналов коммуникаций. Остается надеяться, что Microsoft продолжит развитие этого продукта и добавит недостающие сейчас функции для Skype-ботов.

Встречаем сообщения в Slack


Для организации многоканальной приемки сообщений мы воспользовались таким инструментом Slack, как приватные каналы; в терминологии Slack API это groups.

Первоначально мы рассчитывали, что нам будет достаточно создания одного Custom Bot'а, который покроет весь функционал отправки сообщений в Slack: создаст там приватный канал, добавит туда оператора и дальше будет обеспечивать proxy-коммуникацию. Выяснилось, однако, что боты в Slack не имеют права создавать приватные каналы.

Поэтому кроме подключенного к Slack RTM Api Custom Bot’а мы создали еще и Slack-приложение, которое от лица обычного пользователя Slack создает приватные каналы и приглашает в них операторов.

Slack API достаточно стабилен, хорошо документирован и содержит даже онлайн-тестер, позволяющий проверить вызов методов, поэтому других сюрпризов, к счастью, не было. Для работы с ним мы взяли вот этот весьма простой npm пакет: он удобен, поскольку его методы в большинстве своем повторяют одноименные методы Slack API.

Не все так просто!


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

Итак, через две недели после первого сабмита мы получили это:



с пояснением: Bot content is in Russian language. At this time, Skype Bots only support English Users. Please provide a translation or alternative option for users to read and use the bot in English («ваш бот на русском, а надо, чтобы он умел общаться с пользователями по-английски»). Как выяснилось, для решения этой проблемы достаточно иметь Terms of Service и Privacy Policy на английском; окей, написали, вывесили, отправили новую заявку.

На сей раз отлуп пришел быстрее:



Наш бот призван только связывать клиента с оператором. По мнению Microsoft, этого мало. Пришлось прикрутить минимальный функционал – пару команд, на которые бот сможет реагировать самостоятельно (help и lessons-count).

Пока мы выполняли эти требования, появилось новое: бот должен уметь по команде выдавать Terms of Service и Privacy Policy (просто наличия их на сайте недостаточно). Окей, сделали и это. Оказалось, что этого мало, условия должны присутствовать в каждом сообщении. Хорошо. Тем временем, в лондонском офисе Microsoft начались массовые перестановки, из-за чего одобрение опять раз за разом откладывалось…

Но в конце концов мы получили долгожданный апрув:



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

Заключение


В результате мы получили Skype-бота, обеспечивающего быструю качественную реакцию на входящие сообщения и разговаривающего с клиентом «как живой» (что неудивительно, учитывая, что управляет им оператор). Ушли в прошлое ответы не в тот канал и пропущенные входящие контакты; «ваш вопрос очень важен для нас» – не пустые слова, сейчас ни одно сообщение не потеряется, а беседа не затухнет по нашей вине. При этом были решены проблемы обычного Skype, а коммуникации приобрели структурированную форму, которую мы интегрировали в наши внутренние сервисы поддержки пользователей. А вся «магия» – в незамысловатой архитектуре роутинга сообщений между разными платформами.

PS Напоминаем, что наши двери открыты для разных талантливых специалистов!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/309602/


Метки:  

Добавляем эффект нажатия в Xamarin.Forms

Среда, 26 Июля 2017 г. 11:30 + в цитатник

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


У меня стояла задача сделать небольшое расширение, позволяющее добавить эффект нажатия на почти любой элемент для iOS и Android.


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


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


Как это должно выглядеть


Для Android 5+ очевидно, надо использовать Ripple effect. Но для iOS и Android <5 это решение будет выглядеть неуместно. Для этих платформ я решил реализовать цветное анимированное выделение, срабатываемое при касании.


Реализация


PCL


Для начала в PCL проекте был создан статический класс TouchEffect с двумя BindableProperty:


  • bool On
  • Color Color

Первое отвечает за активность расширения для элемента, соответсвенно второе за цвет эффекта.


Android


Необходимо определить переменную, которая идентифицирует нужно использовать Ripple effect или нет в зависимости от версии Android:


public bool EnableRipple => Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop;

Для реализация стандартных волн для андроида довольно проста:


private void AddRipple()
{
    if (Element is Layout)
    {
        _rippleOverlay = new FrameLayout(Container.Context)
        {
            LayoutParameters = new ViewGroup.LayoutParams(-1, -1)
        };

        _rippleListener = new ContainerOnLayoutChangeListener(_rippleOverlay);
        _view.AddOnLayoutChangeListener(_rippleListener);

        ((ViewGroup)_view).AddView(_rippleOverlay);

        _rippleOverlay.BringToFront();
        _rippleOverlay.Foreground = CreateRipple(Color.Accent.ToAndroid());
    }
    else
    {
        _orgDrawable = _view.Background;
        _view.Background = CreateRipple(Color.Accent.ToAndroid());
    }

    _ripple.SetColor(GetPressedColorSelector(_color));
}

private void RemoveRipple()
{
    if (Element is Layout)
    {
        var viewgrp = (ViewGroup)_view;
        viewgrp?.RemoveOnLayoutChangeListener(_rippleListener);
        viewgrp?.RemoveView(_rippleOverlay);

        _rippleListener?.Dispose();
        _rippleListener = null;

        _rippleOverlay?.Dispose();
        _rippleOverlay = null;
    }
    else
    {
        _view.Background = _orgDrawable;
        _orgDrawable?.Dispose();
        _orgDrawable = null;
    }
    _ripple?.Dispose();
    _ripple = null;
}

private RippleDrawable CreateRipple(Android.Graphics.Color color)
{
    if (Element is Layout)
    {
        var mask = new ColorDrawable(Android.Graphics.Color.White);
        return _ripple = new RippleDrawable(GetPressedColorSelector(color), null, mask);
    }

    var back = _view.Background;
    if (back == null)
    {
        var mask = new ColorDrawable(Android.Graphics.Color.White);
        return _ripple = new RippleDrawable(GetPressedColorSelector(color), null, mask);
    }
    else if (back is RippleDrawable)
    {
        _ripple = (RippleDrawable) back.GetConstantState().NewDrawable();
        _ripple.SetColor(GetPressedColorSelector(color));

        return _ripple;
    }
    else
    {
        return _ripple = new RippleDrawable(GetPressedColorSelector(color), back, null);
    }
}

У контрола берется задний фон и на него добавляется эффект.


Для более старых версий андроида я решил добавлять FrameLayout поверх элемента с анимацией Alpha канала заднего фона.
К событию Touch элемента подписывается этот метод:


private void OnTouch(object sender, View.TouchEventArgs args)
{
    switch (args.Event.Action)
    {
        case MotionEventActions.Down:
            Container.RemoveView(_layer);
            Container.AddView(_layer);
            _layer.Top = 0;
            _layer.Left = 0;
            _layer.Right = _view.Width;
            _layer.Bottom = _view.Height;
            _layer.BringToFront();
            TapAnimation(250, 0, 65, false);
            break;
        case MotionEventActions.Up:
        case MotionEventActions.Cancel:
            TapAnimation(250, 65, 0);
            break;
    }
}

Который при нажатии добавляет в контейнер новый лэйаут с анимацией A-канала с 0 до 65, а при отпускании анимирует обратно от 65 до 0 и удаляет из контейнера.


Потом, в методе OnAttached определяем, что делать, создавать Ripple effect или подписываться на Touch:


if (EnableRipple)
    AddRipple();
else
    _view.Touch += OnTouch;

iOS


Для iOS подход схож с предыдущим шагом, добавляется UIView поверх основного элемента при нажатии и так же анимируется A-канал. Для этого создаются UITapGestureRecognizer и UILongPressGestureRecognizer и добавляются к элементу:


_tapGesture = new UITapGestureRecognizer(async (obj) => {
    await TapAnimation(0.3, _alpha, 0);
});

_longTapGesture = new UILongPressGestureRecognizer(async (obj) => {
    switch (obj.State)
    {
        case UIGestureRecognizerState.Began:
            await TapAnimation(0.5, 0, _alpha, false);
            break;
        case UIGestureRecognizerState.Ended:
        case UIGestureRecognizerState.Cancelled:
        case UIGestureRecognizerState.Failed:
            await TapAnimation(0.5, _alpha);
            break;
    }
});

_view.AddGestureRecognizer(_longTapGesture);
_view.AddGestureRecognizer(_tapGesture);

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


Использование


XAML:



    
        
    

iOS Android API >=21 Android API < 21

Итоги


Я привел основую идею реализации эффекта касания, весь код, а так же Nuget пакеты доступны на GitHub.


P.S. Опыт у меня в нативной разработке небольшой, буду рад советам, что можно улучшить/доработать.
P.P.S Habrastorage немного коряво преобразовал gif'ки.

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334166/


Метки:  

Случайный лес vs нейросети: кто лучше справится с задачей распознавания аудио

Среда, 26 Июля 2017 г. 11:16 + в цитатник
Исторически сложилось так, что наибольшего успеха глубокое обучение достигло в задачах image processing – распознавания, сегментации и обработки изображений. Однако не сверточными сетями едиными, как говорится, живет наука о данных.

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

/ Фотография justin lincoln / CC-BY

Что «услышит» наш алгоритм


Характеристики голоса, которые мы будем использовать

Первым делом нужно разобраться в физике процессов – понять, чем мужской голос отличается от женского. Про устройство речевого тракта у людей можно почитать в обзорах или специальной литературе, но и базовое объяснение «на пальцах» вполне прозрачно: голосовые связки, колебания которых производят звуковые волны до модуляции другими органами речи, у мужчин и женщин имеют различную толщину и натяжение, что ведет к разной частоте основного тона (она же pitch, высота звука). У мужчин она обычно находится в пределах 65-260 Гц, а у женщин – 100-525 Гц. Иными словами, мужской голос чаще всего звучит ниже женского.

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

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

Звук – изменчивый сигнал, а значит его спектр с точки зрения среднего времени вряд ли даст нам что-то осмысленное, поэтому разумно рассмотреть спектрограмму — спектр в каждый момент времени, а также его статистику. Звуковой сигнал делят на перекрывающиеся 25-50 миллисекундные отрезки – фреймы, для каждого из которых при помощи быстрого преобразования Фурье вычисляют спектр, а для него уже после ищутся моменты. Чаще всего используют центроид, энтропию, дисперсию, коэффициенты асимметрии и эксцесса – много всего, к чему прибегают при подсчете случайных величин и временных рядов.

Также используют мел-частотные кепстральные коэффициенты (MFCC). Про них стоит почитать, например, тут. Проблем, которые они пытаются решить, две. Во-первых, восприятие звука человеком не линейно по частоте и по амплитуде сигнала, стало быть, требуется провести некоторое шкалирование (логарифмическое). Во-вторых, сам спектр речевого сигнала меняется по частоте довольно плавно, и его описание можно сократить до нескольких чисел без особенных потерь в точности. Как правило, используют 12 мел-кепстральных коэффициентов, каждый из которых представляет собой логарифм спектральной плотности внутри определенных частотных полос (ее ширина тем выше, чем больше частота).

Именно этот набор признаков (pitch, статистики спектрограммы, MFCC) мы и будем использовать для классификации.


/ Фотография Daniel Oines / CC-BY

Решаем задачу классификации


Машинное обучение начинается с данных. К сожалению, нет открытых и популярных баз для идентификации пола, таких как ImageNet для классификации изображений или же IMDB – для тональности текстов. Можно взять известную базу для распознавания речи TIMIT, но она платная (что накладывает некоторые ограничения на её публичное использование), поэтому воспользуемся VCTK – 7 Гб базой в свободном доступе. Она предназначена для задачи синтеза речи, но устраивает нас по всем параметрам: там есть звук и данные о 109 спикерах. Для каждого из них мы возьмем по 4 случайных высказывания длительностью 1-5 секунд и попытаемся определить пол их автора.



В компьютере звук выводится как последовательность чисел – отклонений мембраны микрофона от равновесного положения. Частота дискретизации чаще всего выбирается из диапазона от 8 до 96 кГц, и для одноканального звука одна его секунда будет представляться как минимум 8 тысячами чисел: любое из них кодирует отклонение мембраны от равновесного положения в каждый из восьми тысяч моментов времени в секунду. Для тех, кто слышал про Wavenet – нейросетевую архитектуру для синтеза звукового сигнала, – это не кажется проблемой, но в нашем случае подобный подход избыточен. Логичным действием на этапе предобработки данных является расчет признаков, которые позволяют существенно снизить количество параметров, описывающих звук. Здесь мы обратились к openSMILE – удобному пакету, способному рассчитать почти все, что имеет отношение к звуку.

Код написан на Python, а реализация – Random Forest, который лучше всего справился с классификацией, – взята из библиотеки sklearn. Также любопытно посмотреть, как с этой задачей справятся нейросети, но о них мы сделаем отдельный пост.

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

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

Кроме того, нам необходим алгоритм валидации классификатора – следует убедиться, что он все делает правильно. В задачах обработки речи считается, что обобщающая способность модели низкая, если она хорошо работает не для всех спикеров, а только для тех, на которых обучалась. В противном случае говорят, что модель является т.н. speaker free, и это само по себе неплохо. Чтобы проверить этот факт, достаточно разбить спикеров на группы: на одних обучиться, а на остальных – проверить точность.

Так мы и поступим.

Таблица с данными хранится в файле data.csv, столбцы подписаны в первой строчке, при желании ее можно вывести на экран или посмотреть вручную.

Подключаем нужные библиотеки, читаем данные:

import csv, os
import numpy as np
from sklearn.ensemble import RandomForestClassifier as RFC
from sklearn.model_selection import GroupKFold

# read data
with open('data.csv', 'r')as c:
	r = csv.reader(c, delimiter=',')
	header = r.next()
	data = []
	for row in r:
		data.append(row)
data = np.array(data)

# preprocess
genders = data[:, 0].astype(int)
speakers = data[:, 1].astype(int)
filenames = data[:, 2]
times = data[:, 3].astype(float)
pitch = data[:, 4:5].astype(float)
features = data[:, 4:].astype(float)

Сейчас нужно организовать процедуру кросс-валидации по спикерам. Встроенный в sklearn итератор GroupKFold работает следующим образом: каждая точка в выборке относится к какой-либо группе, в нашем случае – к одному из спикеров. Множество всех спикеров разбивается на равные части и последовательно исключается каждая из них, на оставшихся обучается классификатор и запоминается точность на выкинутой. За точность классификатора берется средняя по всем частям точность.

def subject_cross_validation(clf, x, y, subj, folds):
	gkf = GroupKFold(n_splits=folds)
	scores = []
	for train, test in gkf.split(x, y, groups=subj):
		clf.fit(x[train], y[train])
		scores.append(clf.score(x[test], y[test]))
	return np.mean(scores)

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

# classify frames separately
score_frames_pitch = subject_cross_validation(RFC(n_estimators=100), pitch, genders, speakers, 5) 
print 'Frames classification on pitch, accuracy:', score_frames_pitch
score_frames_features = subject_cross_validation(RFC(n_estimators=100), features, genders, speakers, 5) 
print 'Frames classification on all features, accuracy:', score_frames_features

Ожидаемо мы получили невысокую точность – 66 и 73% верно классифицированных фреймов. Не густо, ненамного лучше, чем случайный классификатор, который дал бы порядка 50%. В первую очередь такая низкая точность связана с наличием мусора в выборке – для 64% фреймов не удалось посчитать частоту основного тона. Причин может быть две: фреймы либо не содержали речь совсем (тишина, вздохи), либо были составными частями согласных звуков. И если первые можно отбраковать безнаказанно, то вторые – с оговорками: мы считаем, что по звуковым фреймам нам удастся корректно разделять мужскую и женскую речь.

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

def make_sample(x, y, subj, names, statistics=[np.mean, np.std, np.median, np.min, np.max]):
	avx = []
	avy = []
	avs = []
	keys = np.unique(names)
	for k in keys:
		idx = names == k
		v = []
		for stat in statistics:
			v += stat(x[idx], axis=0).tolist()
		avx.append(v)
		avy.append(y[idx][0])
		avs.append(subj[idx][0])
	return np.array(avx), np.array(avy).astype(int), np.array(avs).astype(int)

# average features for each frame
average_features, average_genders, average_speakers = make_sample(features, genders, speakers, filenames)
average_pitch, average_genders, average_speakers = make_sample(pitch, genders, speakers, filenames)

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

# train models on pitch and on all features
score_pitch = subject_cross_validation(RFC(n_estimators=100), average_pitch, average_genders, average_speakers, 5) 
print 'Utterance classification on pitch, accuracy:', score_pitch
score_features = subject_cross_validation(RFC(n_estimators=100), average_features, average_genders, average_speakers, 5) 
print 'Utterance classification on features, accuracy:', score_features

97,2% — уже совсем другое дело, вроде бы всё здорово. Осталось отбросить мусорные фреймы, пересчитать статистики и радоваться результату:

# skip all frames without pitch
filter_idx = pitch[:, 0] > 1
filtered_average_features, filtered_average_genders, filtered_average_speakers = make_sample(features[filter_idx], genders[filter_idx], speakers[filter_idx], filenames[filter_idx])
score_filtered = subject_cross_validation(RFC(n_estimators=100), filtered_average_features, filtered_average_genders, filtered_average_speakers, 5) 
print 'Utterance classification an averaged features over filtered frames, accuracy:', score_filtered

Ура, планка в 98.4% достигнута. Подбором параметров модели (и выбором самой модели), наверное, можно увеличить и это число, но качественно новых знаний мы не получим.

Заключение


Машинное обучение в обработке речи – объективно сложно. Решение «в лоб» в большинстве случаев оказывается в итоге далеким от желаемого, и часто приходится дополнительно «наскребать» по 1-2% точности, меняя что-то, казалось бы, малозначимое, но обоснованное физикой или математикой. Строго говоря, этот процесс можно продолжать бесконечно, но…

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

Над материалом работали:

  • Григорий Стерлинг, математик, ведущий эксперт Neurodata Lab по машинному обучению и анализу данных
  • Ева Казимирова, биолог, физиолог, эксперт Neurodata Lab в области акустики, анализа голоса и речевых сигналов

Оставайтесь с нами.



Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334136/


Метки:  

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

Среда, 26 Июля 2017 г. 11:10 + в цитатник


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

Игнорирование карт лояльности и возможности допродаж


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

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

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



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

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

Ошибки при работе с товарами


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

Распространенная ситуация — в кассовом софте у продукта установлена одна цена, но на ценнике по каким-то причинам оказалась другая (например, сотрудник ошибся или забыл ее сменить). Обычно все это выясняется уже на кассе, когда товар «пробился» по более высокой цене, чем ожидал покупатель — и это мало кому понравится.

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

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

image

Однако внедрение системы электронных ценников (железо + софт) стоит достаточно дорого, и это пока влияет на проникновение технологии.

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

image

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

Кроме того, использование технологий автоматизации позволяет работникам магазина и администрации торговой точки лучше понимать месторасположение конкретного товара. Это, помимо прочего, снижает вероятность потерь товара или его кражи.

Британский ритейл-консультант Ромео Ричардс в своем блоге приводит следующие расчеты по этому поводу — если у нас есть сеть с оборотом lb10 млн фунтов и показателем розничной усадки (то есть списаний потерянного, испорченного или украденного товара) в 2%, а на ошибки сотрудников приходится 18% этой «усадки», то в год это выльется в потерю lb36000. Если при этом уровень чистой прибыли магазина составляет 1%, то, чтобы покрыть эти убытки, нужно будет сгенерировать продаж на lb3,6 млн. Много ли магазинов могут так легко это сделать? Поэтому автоматизация очень важна.

Нарушение законодательных норм и правил


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

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



Будущее: угрожают ли технологии сотрудникам?


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

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

  • процессы автоматизации товароучёта. Электронные ценники, мобильные принтеры позволяют ритейлерам сократить штат и траты на расходные материалы. В обоих случаях работникам магазинов не требуется вручную распечатывать ценники и расклеивать их по залу;
  • внедрение в магазине систем самообслуживания позволяет сократить количество касс и, соответственно, кассиров, а также оптимизировать работу с наличностью;
  • технология Digital Signage поможет ритейлеру сократить затраты на проведение промо-акций и, как следствие, и уменьшить число персонала, вовлеченных в них. Кроме того, этот инструмент позволяет продавать рекламное время своим партнерам и иметь дополнительный источник дохода;
  • информационные киоски помогут сократить штат консультантов. Покупатели, просто отсканировав штрих-код интересующего товара, уточнят его цену и получат дополнительную информацию о нем. Ритейлеры могут демонстрировать на инфокиоске любой мультимедийный контент.

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

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

Другие материалы по теме:


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334082/


Метки:  

Опыт использования FPGA платы DE10-Standard и DMA PL330

Среда, 26 Июля 2017 г. 11:07 + в цитатник


Получил в свое распоряжение плату Terasic DE10-Standard. На ней много всего интересного: встроенный JTAG программатор, светодиоды, переключатели, кнопки, разъемы Audio / VGA / USB / Ethernet. Думаю, что нет особой необходимости перечислять все ее возможности, ведь каждый желающий может прочитать спецификацию платы на сайте производителя.

Для меня важно, что на плате стоит FPGA чип Cyclone V SX – 5CSXFC6D6F31C6N. Эта микросхема содержит два процессора ARM Cortex-A9 и 110K логических элементов FPGA. Это уже настоящая SoC HPS: System-On-Chip, Hard Processor System. С такими ресурсами можно пробовать делать довольно сложные проекты. Далее расскажу о своем опыте использования платы.

Очень просто скачать образ Linux с сайта терасика и подготовить загрузочную SD карту для платы DE10-Standard. ОС Linux загружается с SD, плата оживает и демонстрирует свои возможности.



Как только загрузился Linux, на рабочем столе можно отыскать иконку тестового приложения. Это тестовое GUI приложение позволяет включать и выключать отдельные светодиоды платы, смотреть состояние переключателей и кнопок, устанавливать значения на 7-сегментных индикаторах и так далее. Там много чего интересного. Когда поигрался с этой программой думаешь, что вот и сам сейчас быстро сможешь сделать свой проект и быстро его запустить.

Я не считаю себя новичком-разработчиком ПЛИС. Я делал проекты с софт процессорами и представляю себе, что такое Linux kernel. Я и сам участвую в разработке плат разработчиков с ПЛИС Altera/Intel. Однако, честно говоря, это мой первый опыт работы с SoC HPS-FPGA. Когда я начал делать свой собственный проект для этой платы, именно для этой ПЛИС, я понял, что на самом деле будет не просто.



Конечно, плата DE10-Standard сама по себе не виновата.
Есть некоторая иллюзия легкости разработки: вот есть образ SD карты от терасика, есть исходники примера проекта для ПЛИС и сишные исходники для тестовых программ. Казалось бы, бери адаптируй под свои нужды и будет все работать. Но, нет.

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

Пришлось очень много читать и изучать, например:
1. К плате прилагается диск DE10-Standard_v.1.2.0_SystemCD и он содержит 38 PDF файлов различной документации, схем и руководств.

2. Просто техническое описание от компании Интел “Cyclone V Hard Processor System Technical Reference Manual” www.altera.com/en_US/pdfs/literature/hb/cyclone-v/cv_5v4.pdf содержит 3536 страниц.

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

Есть еще хороший ресурс: https://rocketboards.org/, который содержит еще больше документации, исходников примеров и даже форум. Это делает жизнь с одной стороны легче, а с другой — еще сложнее, ведь придется читать и впитывать еще больше информации… К сожалению даже на форуме rocketboard, не всегда удается найти ответы на свои вопросы.

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



Представьте себе часовой механизм с множеством шестеренок. Каждая шестеренка должна в точности подходить к следующей — иначе ничего не будет крутиться. То же самое и в случае с системой HPS-FPGA. Система состоит из очень многих программных и аппаратных компонентов: Preloader, U-BOOT, Linux kernel и драйвера, DTB файл генерируется из DTS файла, затем еще нужно создать RootFS и, конечно, разработать саму аппаратную систему в ПЛИС: FPGA SoC проект будет содержать несколько IP блоков, аппаратные регистры отображаемые в память, тактовые частоты и домены, сигналы ввода/вывода и прочее и прочее…

Я предполагаю, что знаю, как создать проект для FPGA для моей SoC, и я думаю, что должно работать ну где-то на 80% так как я не вижу очевидных ошибок в проекте. Так же я думаю, что примерно знаю, как написать DTS файл, который описывает мою аппаратную платформу. Предположим, я уверен, что я написал DTS файл правильно на 80%. Из DTS файла генерируется DTB файл. Потом, к своей аппаратуре ПЛИС я должен написать kernel driver. Это не просто, но я умею писать драйвера. Надеюсь я там не наделал много ошибок? Надеюсь мой драйвер корректен ну хотя бы на 80%. Но что там насчет Preloader? Preloader – это первая программа, которая будет считана и запущена с SD карты и она должна запрограммировать нужные аппаратные конфигурационные регистры системы на кристалле. Сделал ли я Preloader правильно? Ну допустим, я уверен на 80%. Теперь если подумать, то какова вероятность, что моя система заработает? Я думаю, что где-то вот так: 0.8*0.8*0.8*0.8=0.4096… Чем больше компонентов в системе, тем хуже. Если что-то не работает или не работает вообще ничего (например, kernel panic), то довольно трудно понять где проблема — она может быть везде.

Цель моей работы была сделать проект HPS-FPGA который использует DMA транзакции для переноса данных из системной памяти в ПЛИС и обратно из ПЛИС в системную память. Использование DMA должно разгрузить процессор. На хабре уже была статья про реализацию DMA в FPGA Cyclone V, однако, мне не хотелось идти путем создания собственного контроллера, как это сделал Des333… Я хотел использовать уже имеющийся в системе контроллер PL330.

Работая с платой DE10-Standard Board некоторое время я получил бесценный опыт. Если позволите, хочу дать несколько советов тем, кто решится заняться разработкой SoC HPS в ПЛИС.

Подготовьте плату к разработке.


Вероятно это совет из разряда очевидных. Существует образ SD карты, который содержит нужные файлы для старта системы: образ FPGA, файл DTB, U-BOOT и Linux kernel zImage. Дополнительные разделы содержат Preloader и RootFS. Если я разрабатываю SoC HPS проект для ПЛИС, я его компилирую в среде САПР Quartus Prime и результат (RBF, Raw Binary File) должен записать на SD карту. Потом я компилирую Linux kernel и мой драйвер в составе ядра. Мне так же нужно записать получившиеся файлы на SD Card.

Нет никакого смысла вытаскивать SD карту из платы, вставлять в кардридер компьютера или ноутбука, чтобы записать файлы на карту. Это может занимать слишком много времени. К тому же, частый plug/unplug может привести к поломке разъема SD карты в плате или ноутбуке. Я рекомендую сконфигурировать U-BOOT таким образом, чтобы нужные файлы скачивались из сети с TFTP сервера.

Плата имеет разъем UART-to-USB для ее подключения через USB кабель к компьютеру разработчика. Открываю программу терминала, например, PUTTY, и включаю плату. Сразу видно, как в терминале побежали сообщения из U-BOOT. Загрузку можно прервать, если сразу нажать любую клавишу в терминале.

Я добавил несколько переменных в окружение U-BOOT:

ethaddr=fe:cd:12:34:56:67
ipaddr=10.8.0.97
serverip=10.8.0.36
xfpga=tftpboot 100 socfpga.rbf; fpga load 0 100 $filesize; run bridge_enable_handoff; tftpboot 100 socfpga.dtb
xload=run xfpga; tftpboot 8000 zImage; bootz 8000 – 100


На компьютере разработчика IP 10.8.0.36 я установил сервер TFTP. В папке /tftpboot я храню socfpga.rbf (Raw Binary File) – результат компиляции проекта SoC FPGA в среде Quartus Prime. Кроме того, там же в папке храню socfpga.dtb – соответствующий Device Tree Blob и Linux kernel zImage файл.

Теперь, когда я включаю питание на плате, я тут же прерываю обычную загрузку нажатием любой клавиши в терминале и ввожу команду:
>run xload

По этой команде U-BOOT загружает нужные файлы из TFTP сервера, инициализирует FPGA последним скомпилированным образом проекта и загружает мой последний zImage. Быстро и просто. Когда делаю изменение в проекте ПЛИС, компилирую проект квартусом, результат копирую в папку /tftpboot. Точно так же, компилирую ядро Linux, результат компиляции копирую в папку /ftfpboot. Перезагружаю плату, делаю “run xload” и вот уже можно пробовать вести отладку новой системы.

2. Постарайтесь найти opensource пример проекта SoC-HPS максимально похожий на то, что вы собираетесь делать.


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

Изначально DE10-Standard_v.1.2.0_SystemCD содержит два примера проектов для HPS-FPGA. Первый проект — это DE10_Standard_GHRD, представляет собой минимальные возможности, Linux console, простую отображаемую в память периферию вроде портов ввода вывода для светодиодов, кнопочек и переключателей. Второй пример, DE10_Standard_FB, — сложнее. Здесь уже в FPGA реализован framebuffer, видеоконтроллер, устройство захвата и декодирования видеосигнала и ряд других возможностей. Это позволяет запустить полноценный десктопный Linux. Если вас устраивают эти примеры — тогда все нормально, берите и пользуйтесь.

Лично мне хотелось найти пример с использованием DMA контроллера, так как я хотел разгрузить CPU во время передачи данных из системной памяти в FPGA и назад из FPGA в системную память. Я поискал такой пример и нашел его на сайте rocketboards: https://rocketboards.org/foswiki/view/Documentation/SampleDmaQuartusProjectForFpgaDmaCInTheKernel313

Пример вообще-то не очень, но хоть что-то, можно пробовать что-то сделать. Cyclone V HPS имеет встроенный DMA контроллер PL330 и я хотел бы попытаться использовать его. Я взял IP корку из проекта примера Loopback_FIFO и вставил его с помощью Quartus Prime QSYS в мой клон проекта DE10_Standard_GHRD. К сожалению, я потратил очень много времени на написание правильного DTS файла к моему проекту, DTS файла не было в архиве примера. Так же, я не сразу понял, что в Linux kernel уже есть пример DMA драйвера в arch/arm/mach-socfpga/fpga-dma.c. Я понял это слишком поздно, когда уже почти написал свой собственный драйвер.

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

3. Используйте исходники Linux kernel как документацию.


С FPGA Cyclone V HPS я разрабатываю новую аппаратную платформу. С большой вероятностью мне придется писать свой собственный драйвер к новой аппаратуре в ПЛИС. В интернете очень много статей как писать драйвера уровня ядра Linux. Но учтите, что очень многие из этих статей уже давным давно устарели, содержат не верные примеры, вызывают старый kernel API.

Если выбрать конкретную версию ядра Linux для проекта, то всю информацию о том, как писать драйвера можно почерпнуть конкретно из исходников этой версии ядра и это будет самая актуальная информация. Примеры драйверов в папке ./drivers, дествующая документация в папке ./Documentation, примеры написания *.DTS файлов в папке ./arch/arm/boot/dts

В моем случае для моего проекта с DMA контроллером документация о написании драйверов DMA получена из файлов ./Documentation/dmaengine/*.

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

Как я понял, теоретически разработка должна идти вот так:
  1. Разрабатываем аппаратную систему в среде САПР Quartus Prime QSYS, настраиваем параметры HPS, добавляем в систему компоненты и IP ядра, соединяем компоненты. Генерируем систему с помощью QSYS и получаем результат soc_system.qsys и soc_system.sopsinfo файлы.
  2. Создаем DTS файл из *.sopsinfo файла используя командную строку:
    >sopc2dts --input soc_system.sopcinfo --output socfpga.dts --board soc_system_board_info.xml --board hps_clock_info.xml
  3. Создаем DTB из DTS файла:
    >dtc -I dts -O dtb -o socfpga.dtb socfpga.dts

Я прочитал такую инструкцию на страницах рокетбоардс, но этот метод как-то не очень работает (совсем не работает). Для себя я понял, что единственно работающий метод — это вручную исправлять существующий пример DTS файла адаптируя его под свой аппаратный проект.

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

Дайвайте посмотрим пример DMA драйвера из ./driver/dma/fpga-dma.c

Драйвер вызывает API функцию platform_driver_probe() и передает в качестве аргумента указатель на структуру:
#ifdef CONFIG_OF
static const struct of_device_id fpga_dma_of_match[] = {
	{.compatible = "altr,fpga-dma",},
	{},
};

MODULE_DEVICE_TABLE(of, fpga_dma_of_match);
#endif

static struct platform_driver fpga_dma_driver = {
	.probe = fpga_dma_probe,
	.remove = fpga_dma_remove,
	.driver = {
		   .name = "fpga_dma",
		   .owner = THIS_MODULE,
		   .of_match_table = of_match_ptr(fpga_dma_of_match),
		   },
};

static int __init fpga_dma_init(void)
{
	return platform_driver_probe(&fpga_dma_driver, fpga_dma_probe);
}


Это значит, что в DTS файле должна быть соответствующая секция с совместимым именем устройства:
fpga_dma: fpga_dma@0x10033000 {
compatible = "altr,fpga-dma";


То есть, видимо функция platform_driver_probe будет просматривать DTB файл искать устройство с именем fpga-dma от производителя altr.

Если драйвер вызывает функции
csr_reg  = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr");
data_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, "data");

то это значит, что DTS файл должен содержать именованные регистры с такими же точно именами “csr” и “data”. В противном случае драйвер не сможет стартовать.

Точно так же, драйвер ядра может запрашивать каналы DMA по имени:

static int fpga_dma_dma_init(struct fpga_dma_pdata *pdata)
{
	struct platform_device *pdev = pdata->pdev;

	pdata->txchan = dma_request_slave_channel(&pdev->dev, "tx");
	if (pdata->txchan)
		dev_dbg(&pdev->dev, "TX channel %s %d selected\n",
			dma_chan_name(pdata->txchan), pdata->txchan->chan_id);
	else
		dev_err(&pdev->dev, "could not get TX dma channel\n");

	pdata->rxchan = dma_request_slave_channel(&pdev->dev, "rx");
	if (pdata->rxchan)


А вот соответствующий фрагмент DTS файла, который отображает кореляцию исходников драйвера ядра и DTS файла:

fpga_dma: fpga_dma@0x10033000 {
compatible = "altr,fpga-dma";
reg = <0x00000001 0x00033000 0x00000020>,
<0x00000000 0x00034000 0x00000010>;
reg-names = "csr", "data";
dmas = <&hps_0_dma 0 &hps_0_dma 1>;
dma-names = "rx", "tx";


Таким образом, DTS файл должен быть написан с учетом того, как драйвер запрашивает из него ресурсы. Если используются именованные регистры и канала DMA, то имена должны совпадать и в исходнике ядра и в DTS файле. Только так две шестереночки системы: драйвер ядра и DTS/DTB могут работать вместе.

4. Помните, что ваши исходники могут быть не самыми свежими.


Мне нужен был компилятор и исходники Linux kernel, чтобы я смог начать разрабатывать свой драйвер и компилировать ядро для моей FPGA системы. Именно поэтому я выкачал последний (на тот момент) Intel SoC FPGA Embedded Development Suite v17.0 и установил его.

После полной установки я увидел новую папку ~/intelFPGA/17.0/embedded/embeddedsw/sources, где лежал скрипт git_clone.sh. Я запустил этот скрипт и получил исходники ядра вот здесь ~/intelFPGA/17.0/embedded/embeddedsw/sources/linux-sources.

Git branch получился вот такой: sockfpga-4.1.22-ltsi-16.1-release. Версия ядра 4.1.22 — ну пусть.

Я принял версию 4.1.22 как данность и начал работать с этой веткой над этими исходниками. Я собрал ядро и нашел, что есть драйвер DMA, называемый fpga-dma, и этот драйвер в общем-то работает с моим LoopbackFIFO IP core в моем FPGA проекте. Однако, я заметил, что производительность по передаче данных из памяти системы в FPGA и назад очень мала — передача осуществляется одиночными передачами, по одному слову за несколько тактов. Я перепроверил мой FPGA проект сотню раз, и я перепроверил fpga-dma.c драйвер сотню раз, но я так и не мог понять почему на шине не происходит burst transfers. Я уже было начал разбираться с исходниками самого драйвера DMA контроллера PL330. Так же, мне пришлось таки читать Cyclone V Hard Processor System Technical Reference Manual про HPS PL330 DMA контроллер. Этот DMA контроллер очень сложный, у него у самого есть свой набор инструкций, к нему нужно писать свою программу. Программа на языке ассемблера для PL330 DMA контроллера может выглядеть вот так:

DMAMOV CCR, SB4 SS64 DB4 DS64
DMAMOV SAR, 0x1000
DMAMOV DAR, 0x4000
DMALP 16
DMALD
DMAST
DMALPEND
DMAEND


В результате всех моих изыскания я понял, что драйвер ./drivers/dma/pl330.c никогда не инициализирует регистр CCR контроллера DMA для burst передачи. Я не понимал, что же мне делать, но позже я обнаружил, что более новые версии ядра уже содержат исправление этого недоразумения: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=848e9776fee424b9368c72377de5d3509b17937c

Я вручную добавил патч на исходники DMA драйвера и получил burst transfers! Вот здесь снимок с экрана SignalTap, где я захватываю DMA Mem-to-Device transfer:



Таким образом, если однажды вы столкнетесь с технической проблемой, которую не знаете, как решить, перепроверьте: вдруг к вашей проблеме уже есть исправление в более свежих исходниках ядра Linux? Какя понял, проблема с блочной передачей DMA контроллера PL330 решена в ядре 4.6.

5. Внимательно относитесь к отдельным деталям системы.


Конечно, разработка FPGA SoC системы требует специфических знаний. Сейчас я не хочу касаться особенностей и методов разработки IP ядер или синтаксиса Verilog / VHDL. Конечно, разработчик должен многое знать. Однако, я хочу обратить внимание, что заставить все части системы работать вместе — это не очень простая задача. Слишком много шестеренок, которые должны синхронно вращаться.

Попробую привести пример и моей практики.
Я пытался заставить работать драйвер контроллера PL330 DMA с моим IP core. Я встретил такую проблему: операции записи в устройство проходят успешно, а вот операции чтения всегда завершаются таймаутом. Я пытался найти решение в интернете и видел, что многие разработчики так же спрашивают про эту проблему, но решения нет. В системном логе я вижу сообщение из драйвера fpga-dma “Timeout waiting for RX DMA!”. Но в чем проблема? — не понятно. Почему с TX передачей все нормально, а с RX передачей — нет? Я поменял местами каналы RX и TX в FPGA проекте, и получил наоборот “Timeout waiting for TX DMA!”. Что же не правильного в моем втором канале DMA?

Я использую Quartus Prime Qsys для редактирования моей SoC. Один из наиболее важных компонентов системы SoC это hps_0, “Arria V / Cyclone V Hard Processor System”. Я отредактировал свойства этого компонента и убедился, что оба канала DMA у меня включены, и RX и TX:



Достаточно ли этого? На самом деле, конечно, нет! Qsys генерирует компоненты системы soc_system для Quartus Prime, но так же он создает программные компоненты в папке ./hps_isw_handoff/soc_system_hps_0.

Тут есть файл hps.xml в котором видно следующее:

  
    
    
    
    
    
    


Это значит, что позже я должен сгенерировать компонент Preloader, и для его компиляции используется этот XML файл. Скомпилированный Preloader должен быть записан в специальный раздел SD карты. Когда стартует система стартует и Preloader. Именно он включает все необходимые компоненты системы делая нужные записи в специальные аппаратные регистры.

Регистры Cyclone V HPS Reset Manager расположены по физическому адресу 0xFFD05000 (Cyclone V Hard Processor System Technical Reference Manual). Некоторые биты в регистрах Reset Manager, должны быть сброшены, чтобы включить DMA на отдельных каналах.

Ну хорошо. Я изменяю свойства компонента hps_0 в Qsys и теперь я знаю, что вероятно я должен перекомпилировать Preloader и записать его на SD.

Но и это еще не вся история!
Если я использую два канала DMA, то мне нужно и два прерывания для этих двух каналов и их еще нужно вручную объявить в DTS файле.
hps_0_dma: dma@0xffe01000 {
compatible = "arm,pl330-16.1", "arm,pl330", "arm,primecell";
reg = <0xffe01000 0x00001000>;
interrupt-parent = <&hps_0_arm_gic_0>;
interrupts = <0 104 4>, <0 105 4>;
clocks = <&l4_main_clk>;


Откуда такие странные числа 104 и 105?
Пришлось читать Cyclone V HPS Reference Manual. Я вижу, что Generic Interrupt Controller имеет зарезервированные линии запросов DMA IRQ 136 and 137:



Однако, почему-то нумерация начинается “32”. Таким образом я решаю, что 136-32=104 и 137-32=105 — это правильные числа. Вот такие магические подсчеты дают правильные значения для DTS файла в секции interrupts. Без объявления второго IRQs для PL330 в DTS файле второй канал DMA всегда получал ошибку таймаута в драйвере ядра… Получается, что я изменяю в Qsys свойства HPS и из-за этого мне может потребоваться одновременное изменение и Preloader и DTS файла — и об этом нужно все время помнить.

Заключение.


У меня был исходный проект с примером DMA проекта, который я нашел на страницах сайта rocketboard. Однако, я адаптировал его и заставил работать на DE10-Standard board и с ядром Linux 4.1.
Вероятно, это не очень большое достижение, однако:
  1. Я написал DTS файл, которого не было в исходном проекте. Это было довольно трудно.
  2. Понял, что требуется делать патч ядра, чтобы получить блочную передачу (burst transfer).
  3. Подключил анализатор SignalTap к FPGA проекту и теперь могу видеть сигналы на шине в момент DMA передачи
  4. Научился писать DMA драйвер ядра
  5. Надеюсь, что понял весь road-map разработчика для Cyclone V HPS


Если кто-то захочет поэкспериментировать с DMA в SoC я рекомендую начинать эксперименты с альтеровского драйвера fpga-dma. Он использует DebugFS, это позволяет использовать прямо в консоли терминала простые команды “cat”, “echo” для выполнения транзакций в DMA канале:



Надеюсь эта статья окажется полезной тем, кто только начинает работы с FPGA SoC HPS Cyclone V.

Посмотреть исходники проекта можно здесь: https://github.com/marsohod4you/DE10_Standard_GHRD_w_FIFO
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334154/


Метки:  

Как управлять ценообразованием в SAP Business One

Среда, 26 Июля 2017 г. 11:07 + в цитатник
Мы продолжаем серию публикаций про решение для малого и среднего бизнеса от компании SAP – SAP Business One. В этой статье рассмотрим стандартные возможности ценообразования в SAP Business One и вариант реализации нестандартного расчета цены, примененного нашим партнером, компанией ЦМД-софт, на проекте внедрения.

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

Предприятие-продавец выстраивает ценовую матрицу с учётом многих факторов, среди которых данные, подлежащие внутреннему учету: номенклатура товара, количество товара на складе, условия поставки, категория клиента и т.д.

Ценовая политика предприятия возлагает на ERP-систему требования по идентичному отражению различных ценовых подходов во взаимосвязи со многими учетными данными. Для успешности процесса продаж адекватное отображение логики ценообразования торговой организации является важной и ответственной задачей настройки информационной системы.
Давайте рассмотрим с помощью примеров как с вопросами ценообразования справляется решение от SAP для среднего и малого бизнеса. В SAP Business One путем несложных настроек можно достичь различных ценовых вариаций и удовлетворить большинство потребностей клиентов.

На рисунке выделены и проиллюстрированы основные подходы к расчету цены, а также примеры, сгруппированные по принципу организации стандартных возможностей системы:
image
Основные виды расчета цены в SAP Business One


1. Прайс-листы
В SAP Business One возможно ведение различных версий прайс-листов для продаж и закупок. Прайс-листы продаж/закупок создаются в Запасы => Прайс-листы => Прайс-листы:

image
Хранение справочника прайс-листов

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

imageКоэффициенты для расчета прайс-листов

Возможно ведение прайс-листов с НДС или без НДС, в нескольких валютах (в основной и двух дополнительных) – например, РУБ, USD, EUR. Есть возможность зафиксировать цену за единицу, при изменении коэффициента – цена не будет пересчитываться:

image
Настройка прайс-листа с/без НДС, фиксированная цена в разных валютах

Определенный прайс-лист можно назначить конкретному клиенту/поставщику. Привязка прайс-листа осуществляется в карточке клиента Бизнес-партнёры => Справочник бизнес-партнёров => вкладка Условия оплаты => поле Прайс-лист:

image
Настройка прайс-листа для поставщика

Для редактирования цены в прайс-листе для определенного товара достаточно в карточке товара выбрать прайс-лист и изменить цену Запасы => Справочник товаров и услуг => поле Прайс-лист:

image
Настройка цены товара


2. Объемные скидки

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

image
Скидки в зависимости от периода и количества


3. Группы скидок

Группы скидок настраиваются по пути Запасы => Прайс-листы => Группы скидок.

Назначение групп скидок возможно для всех бизнес-партнеров, конкретного клиента/поставщика, группы заказчиков или группы поставщиков:

image
Настройка скидок для конкретного клиента

Группы скидок по Группам товаров настраиваются на вкладке Группы товаров. Можно активировать срок действия данной скидки:

image
Настройка скидок по группе товаров

Группы скидок по свойствам товаров настраиваются на вкладке Свойства товара. Чтобы дополнительная скидка складывалась, необходимо установить значение Отношение скидки = Всего:

image
Настройка скидок по свойствам товаров

Группы скидок могут быть назначены по производителям (брендам) на вкладке Производитель:

image
Настройка скидок по производителям (брендам)

Для расчета скидки по определенным товарам выбираем данные товары на закладке Товары:

image
Настройка скидок по товарам


4. Специальные предложения

SAP Business One позволяет установить цену для клиента или поставщика на отдельные товарные позиции в одном или нескольких прайс-листах:

image
Настройка специальных цен для определенного клиента


5. Нестандартный расчет цены

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

  • Цена за единицу (указывается без НДС, по умолчанию берется из прайс-листа)
  • Скидка % (значение не может быть больше 100%)
  • Цена вкл. налог (рассчитывается с учетом Скидки плюс НДС),
  • Всего (НВ) (по умолчанию является результатом умножения значений полей Цена вкл. налог и Количество)

image
Каскадный пересчет значений связанных полей при изменении значения в одном из полей

Для реализации нестандартных сценариев расчета цены могут быть использованы различные инструменты, встроенные в SAP Business One. Гибкость решения и независимость ядра позволяет без написания кода (программирования) добавлять пользовательские объекты в системные документы.

Создание пользовательского поля
С помощью инструмента Пользовательские поля можно добавить новое поле и привязать его к документам, основным данным и другим системным объектам (как на уровне заголовка, так и на уровне строк). Пользовательские поля могут быть различного типа: алфавитно-цифровой, цифровой, дата или время, единицы измерения и расчета. В соответствии с выбранным типом поля изменяется внешний вид отображения данных. Значения этих полей могут быть связаны с сущностями (системная или пользовательская таблица), включать в себя ограниченный набор данных (введенных при определении поля) или соответствовать определенным критериям. Пользовательскому полю может быть присвоено стандартное значение и/или свойство обязательного ввода (пользователь не сможет сохранить документ, если данное поле не заполнено).
Добавляем пользовательское поле на уровне заголовка документа, в которое будем вводить размер дополнительной скидки:

image
Добавление пользовательского поля на уровне заголовка документа

Создание пользовательского запроса
Для формирования алгоритма расчета используем инструменты в разделе Запросы. С помощью этих инструментов можно построить, изменить и управлять SQL запросами. Для «неискушенных» имеется Ассистент запросов – мастер, помогающий пошагово создать свой SQL запрос.
В SAP Business One возможно вычисление на уровне открытого документа, когда значение еще не внесено в системную или пользовательскую таблицу (документ не сохранен). Для этого используется синтаксис вида $[$X.Y.Z], где X — системный номер или название поля, а Y и Z дополнительные условия.

В запросе для определения пользовательского значения (в нашем случае – нестандартный расчет цены) указываем динамический синтаксис по считыванию элементов открытой формы:

image
Добавление пользовательского SQL запроса


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

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

Ставим курсор мыши в поле Всего (НВ) – созданный запрос будет выполняться в этом поле. Добавим пользовательское значение на основе запроса.
Выбираем созданный запрос. Устанавливаем настройку автоматического расчета значения при изменении созданного пользовательского поля. Выбираем настройку Просмотр сохраненных пользовательских значений. Сохраняем результаты:

image
Присвоение пользовательского запроса полю

Результат
Открываем маркетинговый документ Заказ на продажу. Находим требуемый документ или создаем новый. В пользовательское поле Дополнительная скидка вносим размер скидки, например, 50. С помощью созданного запроса и настройки определения пользовательского значения на основе запроса во всех строках документа обновилось поле Скидка, %, Всего (НВ) и общая стоимость заказа уменьшилась на 50%:

image
Автоматический расчет значений в связанных полях документа


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

Ознакомиться с примерами внедрений SAP Business One можно на нашем сайте: www.sapb1repository.com
Видео с обзорами возможностей и не только доступно на нашем канале в YouTube:
www.youtube.com/user/businessonesap/featured

Комментируйте, делитесь впечатлением, задавайте вопросы :)

Всем спасибо за прочтение и обратную связь!

Предыдущие материалы о SAP Business One:

Возможности ERP-решения SAP Business One на платформе SAP HANA: habrahabr.ru/company/sap/blog/324966

Business One: ERP для малого бизнеса существует: habrahabr.ru/company/sap/blog/317962
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334114/


Метки:  

Подробно о новой версии Veeam Backup for Microsoft Office 365 и коротко о розыгрыше билетов на VMworld 2017

Среда, 26 Июля 2017 г. 11:04 + в цитатник
Недавно Veeam запустил программу бета-тестирования новой версии Veeam Backup for Microsoft Office 365. Эта новость особенно актуальна в свете последних отчетов от Microsoft, согласно которым выручка от продаж корпоративных подписок на облачный Office 365 за прошедший квартал впервые превысила выручку от лицензий на традиционные offline-приложения из пакета Office.
В нашем блоге мы рассказывали о версии 1.0 решения Veeam, предназначенного для резервного копирования и восстановления данных Exchange Online. C версией же 1.5 будет возможно бэкапить и восстанавливать почту не только для облачного, но и для локального Exchange или для гибридной организации.
Новая версия намечена к выпуску на конец текущего квартала и, как мы надеемся, особенно порадует сервис-провайдеров. Но не только их – ведь, помимо новой распределенной архитектуры и улучшенного интерфейса, в ней для автоматизации работы администраторов предлагается набор командлетов PowerShell, а также RESTful API.
За подробностями добро пожаловать под кат.



Итак, сегодня в программе:


Новое в архитектуре


По сравнению с первой версией архитектура была значительно переработана и теперь позволяет масштабировать решение для крупных организаций и сервис-провайдеров. За счет чего можно это сделать? Вот ключевые моменты:
  1. Основную нагрузку по работе с данными теперь несет прокси-сервер, а их можно развернуть столько, сколько вам потребуется для бэкапа данных вашей организации. Прокси-сервер может работать c одной или с несколькими Exchange-организациями.
  2. Для каждого прокси-сервера настраивается репозиторий (один или несколько), куда прокси будет сохранять данные почты.
  3. Центральный же сервер VBO365 выполняет управленческие функции, поддерживает базу данных конфигурации, обеспечивает работу пользовательской консоли и RESTful API. На этом же сервере по умолчанию ставится дефолтный прокси и дефолтный репозиторий.
  4. Задание резервного копирования (job) — совокупность настроек, согласно которым выполняется бэкап. Мы указываем, какие почтовые ящики надо бэкапить, куда сохранять данные, в какое время все это проделывать. Фактически, мы получаем политику резервного копирования для почты.

На картинке все это выглядит примерно так:


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

Для восстановления писем, общих папок, задач и календарей все так же используется Veeam Explorer for Microsoft Exchange.

ОЧЕНЬ ВАЖНО! Бета-версия требует чистой установки. Обновление на 1.5 beta с релизной 1.0 не поддерживается. Также не будет поддержано обновление с бета-версии на релизную 1.5. Будьте внимательны!

Теперь подробнее о компонентах.

Сервер Veeam Backup for Microsoft Office 365


Этот центральный компонент ставится на физическую или виртуальную машину под управлением ОС Windows 7 и выше. Машина должна удовлетворять следующим требованиям:
  • ЦПУ: x64
  • RAM: 4ГБ
  • Диск: минимум 500 МБ свободного места для установки

В функции сервера входят управление лицензиями и общими настройками (в частности, настройки уведомлений о выполнении заданий и о статусе прокси, выбор папок, которые не надо бэкапить — например, Junk E-mail), управление заданиями, хранение конфигурационной базы, обеспечение работы RESTful API, и т.п.

Важно! Рекомендованные файловые системы для развертывания сервера VBO365 — NTFS и ReFS. Использование FAT32 не рекомендуется, поскольку ограничивает размер конфигурационной базы 4мя гигабайтами.

Обновленный пользовательский интерфейс


В интерфейсе появилось новое представление под названием Backup Infrastructure. Оно сделано по образу и подобию аналогичного представления в Veeam Backup & Replication: в дереве навигации отображаются объекты, составляющие инфраструктуру резервного копирования Veeam Backup for MS Office 365 — прокси-серверы и репозитории. С помощью команд меню, расположенных на соответствующих вкладках, можно добавлять, удалять и редактировать свойства этих объектов.




Прокси-сервер


Это новый компонент архитектуры, который позволяет оптимизировать обработку данных, разгрузив сервер управления, а также масштабировать решение по мере необходимости. В качестве прокси вы можете использовать физическую или виртуальную машину под управлением ОС Windows 7 и выше. Требования к ней аналогичны требованиям к серверу управления. При планировании установки обратите внимание на следующее:
  • Сервер управления и прокси-сервер должны находиться в одном домене, разрешается также развертывание в trusted доменах.
  • Для передачи данных между прокси и сервером управления по умолчанию используются TCP порты 9192 и 9193.
  • Для передачи данных между прокси и Exchange Online по умолчанию используются порты 80 и 443.
  • Можно использовать дефолтный прокси, по умолчанию развернутый на сервере управления.
    Для настройки нового прокси открываем представление Backup Infrastructure, при этом в дереве навигации фокус автоматически переходит на первый узел – Backup Proxies.




По правому клику или по команде Add Proxy с соответствующей вкладки меню запустится мастер настройки из 3 шагов:
  1. Вводим имя или IP-адрес нового прокси.
  2. Указываем учетку, под которой будем стучаться к этому серверу. У нее должны быть права локального админа на машине с прокси.
    Примечание: Сервис Veeam.Archiver.Proxy будет работать под Local System.
  3. Наблюдаем за ходом установки компонентов на указанный сервер.

После этого будет задан вопрос – а не хотим ли мы сразу настроить и репозиторий для нового прокси?
Отвечаем Yes и приступаем.

Репозиторий


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

Важно: Один и тот же прокси-сервер может работать с несколькими репозиториями.

Создаем репозиторий также с помощью мастера из 3 шагов. Сначала указываем имя, выбираем, на каком прокси-сервере и по какому пути будет расположен репозиторий:



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

Обращаю ваше внимание на типы хранилищ, которые Veeam Backup for Microsoft Office 365 поддерживает в качестве репозитория:
  • Локальная папка на управляющем сервере (репозиторий по умолчанию).
  • Direct Attached Storage (DAS), подключенный к управляющему серверу; поддерживаются внешние устройства с подключением по USB/eSATA и тома с RDM (raw device mapping).
  • Сетевые системы хранения Storage Area Network (SAN); управляющий сервер необходимо подключить к SAN с помощью аппаратного или виртуального HBA либо iSCSI initiator-а.
  • Поддержка папок общего доступа SMB 3.0 заявлена в качестве экспериментального режима (для учетной записи управляющего сервера потребуется предоставить как минимум права на запись).

Путь к дефолтному репозиторию, ассоциированному с дефолтным же прокси на сервере Veeam Backup for Office 365, будет таким: С:\VeeamRepository.

Примечание: Не рекомендуется использовать в качестве места хранения бэкапов почты тот же репозиторий, с которым работает Veeam Backup & Replication, если таковой у вас развернут. Это связано с тем, что у Veeam Backup for Microsoft Office 365 и Veeam Backup & Replication совершенно разная структура данных бэкапа, а также разные политики хранения для содержимого репозиториев.

Как это работает


Veeam Backup for Microsoft Office 365 собирает данные почты с организации Exchange, используя Exchange Web Services и PowerShell, и сохраняет эти данные в репозиторий. Передача данных идет через прокси-сервер, указанный в настройках задания; при передаче используется SSL.

Примечание: Естественно, возможен и сценарий «всё в одном», то есть на локальном сервере у вас и управление, и дефолтный прокси с дефолтным же репозиторием.
  1. При первом запуске задания резервного копирования в репозитории создаются файл базы данных в формате ADB и вспомогательные файлы. По умолчанию, они находятся в папке с именем (год последнего изменения объекта из почты). Для работы с этой базой используется движок Extensible Storage Engine for Windows (ESE). Первый проход задания создает полный бэкап содержимого для всех выбранных ящиков.
  2. При следующих проходах задания данные о структуре базы и данные собственно почты синхронизируются с текущим состоянием организации Exchange, используя Exchange Web Services. Каждый раз успешно отработавшее задание создает точку восстановления, где сохраняет соответствующее состояние базы. Эти бэкапы уже инкрементальные – то есть Veeam выявляет изменения в данных почты (новые ящики или какие-либо модификации), произошедшие с момента последнего запуска. Затем выполняется «инкрементальная синхронизация».

В репозитории образуется и поддерживается вот такая структура:



Как мы видим, есть папки, куда складывается бэкап почты — они именуются согласно времени последнего изменения этой почты. То есть письма, претерпевшие последнее изменение в 2016 году, попадут в папку с именем 2016. А если письмо было модифицировано, скажем, 26 мая 2015 года, то оно попадет в папку 2015.
В файле Repository.xml хранятся настройки конфигурации, включая ID прокси и управляющего сервера.
Внутри же папок репозитория находятся следующие файлы:



  • repository.adb – файл базы, где, собственно, и хранятся данные почтовых ящиков организации Exchange Organization, с сохранением всей иерархии (ящики, папки и объекты в них – письма, календари, задачи). Срок хранения этих данных устанавливается в настройках репозитория, как описывалось выше.
  • файлы журналов транзакций и чекпойнт – потребуются, когда вы решите восстановить базу на выбранное состояние.


Настройки канала передачи данных


В версии 1.5 число потоков, настроенных по умолчанию, будет увеличено до 64. Пользователям предоставляется возможность самим задавать значение этого параметра в свойствах прокси-сервера. Здесь же можно и указать ограничение пропускной способности для канала, используемого данным прокси (по умолчанию ограничений нет).




Автономная работа прокси-сервера


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


Типы поддерживаемых организаций


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



Поддержка PowerShell и RESTful API


С помощью PowerShell и RESTful API конечные пользователи и сервис-провайдеры смогут автоматизировать типовые задачи.
  • Поддержка PowerShell реализована с помощью модуля, вызываемого командой Import-Module Veeam.Archiver.PowerShell.
  • RESTFul API, как ожидается, будет полезен сервис-провайдерам наряду с описанными выше возможностями масштабирования с помощью прокси и выделенных репозиториев для пользовательских организаций.

Для работы с RESTful API нужно активировать соответствующий сервис.
  1. Кликаем по иконке главного меню в левом верхнем углу консоли, открывается диалог с опциями.
  2. Переходим на вкладку REST API и зачекиваем галку Enable REST Service.


  3. Затем кликаем по кнопке Install и пользуемся мастером выбора сертификата.


Уведомления


На управляющем сервере можно настроить отправку уведомлений о статусе заданий бэкапа и о состоянии прокси-серверов. Администратор может указать, о каких именно состояниях заданий нужно уведомлять по e-mail: Success, Warning или Failure.
Аналогичные настройки можно использовать, чтобы вовремя получить сообщение о неработающем прокси-сервере.

Восстановление почты


Опции восстановления остались теми же, что в версии 1.0, реализованы они с помощью Veeam Explorer for Exchange:
  • Экспорт почтовых ящиков, папок и отдельных писем в формат .pst
  • Сохранение писем в формат .msg
  • Отправка писем\календарей\задач путем прикрепления к e-mail
  • Восстановление почтовых ящиков, писем, папок непосредственно в организацию Exchange

Теперь к ним добавилось еще и восстановление с использованием командлетов PowerShell.
Таким образом, в версии 1.5 Veeam Backup for MS Office 365 мы имеем хорошо масштабируемое решение с улучшенной производительностью, обладающее набором фич, которые будут полезны как конечным пользователям, так и сервис-провайдерам.

И немного о розыгрыше билетов на VMworld


На этот раз Veeam разыгрывает билеты на VMworld 2017 – ежегодную международную конференцию, организуемую компанией VMware.
  • Конференция в США пройдет на площадке Mandalay Bay Hotel & Convention Center в Лас Вегасе с 27 по 31 августа.
  • Европейская конференция пройдет на площадке Fira Gran Via в Барселоне с 11 по 14 сентября.

Что там будет? Как всегда, интереснейшие доклады и популярнейшие спикеры, последние новинки из мира виртуализации и облачных инфраструктур, известные эксперты, профессионалы ИТ-отрасли. Всех участников ждут специальные призы и подарки, а в завершение – посещение знаменитой вечеринки VMworld Customer Appreciation Party.

Как туда попасть? В этом году Veeam предоставляет 10 бесплатных билетов на VMworld 2017. Чтобы принять участие в розыгрыше, нужно зарегистрироваться на сайте, вот тут. Билет включает в себя посещение всех общих докладов и любых тематических сессий, тестовых лабораторий VMware Hands-On Labs и стендов Solutions Exchange.
Будучи на выставке, непременно посетите стенд Veeam — там можно будет пообщаться с нашими экспертами. Они ответят на ваши вопросы о продуктах компании, об обеспечении доступности данных, о возможностях резервного копирования и восстановления при работе в публичных, частных и гибридных облаках, в виртуальной и физической среде, и так далее. Не пропустите встречи с IT-профи со всего мира и, разумеется, розыгрыши призов от Veeam. Скучно не будет!
Розыгрыши билетов продлятся до 4 августа. Возможно, счастливый билет ждет именно вас – заходите за ним сюда. Желаем удачи!

Полезные ссылки


  • Чтобы присоединиться к программе бета-тестирования Veeam Backup for Microsoft Office 365, нужно, как всегда, указать почтовый ящик вот тут
  • Для бета-версии нужно использовать соответствующую лицензию (входит в пакет). Руководство пользователя также включено в пакет (на англ. языке), документацию для версии 1.0 (на англ. языке) можно найти тут
  • Нюансы работы можно обсудить на форуме, где также будут рады вашим комментариям и предложениям
  • Статья на Хабре о первой версии Veeam Backup for Microsoft Office 365
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334104/


Метки:  

Как мы бесплатно привлекли почти 90% своих пользователей

Среда, 26 Июля 2017 г. 10:52 + в цитатник


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

Идея сервиса


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

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

1. Блок повышения доверия

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

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

— фотографии работ,
— сертификаты,
— сканы отзывов клиентов,
— фотографии вашего офиса и сотрудников.

Вот пример попапа с отзывами и сертификатами с сайта по строительству домов:


2. Блок повышения конверсии

Во многих тематиках важно соблюдать баланс качества и количества информации на сайте.

Как обычно ведет себя средний пользователь? Он открывает 10-15 вкладок по интересующей информации и сравнивает цены и условия. Поэтому наша задача не просто проинформировать клиента, но и попытаться получить от него взамен номер телефона.

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

Пример «псевдо-калькулятора» с сайта по вывозу мусора, который по результатам 5 шагов с вопросами предлагает ввести номер телефона в обмен на итог расчета:


Протестировав на разных сайтах несколько десятков кнопок, попапов и баннеров, мы выделили список обязательных разделов, которые необходимо добавить на каждый сайт:

— Портфолио (примеры работ);
— Официальные документы (сертификаты и лицензии);
— Отзывы клиентов;
— Цены и калькулятор;
— Заметная форма контактов;
— Акция или скидка.

Причём не просто добавить, а добавить на видное место, чтобы они сразу бросались пользователю в глаза.

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

Результаты наших тестов и тепловые карты из Яндекс.Метрики подтвердили, что такие виджеты хорошо привлекают внимание посетителей. Более того, они становятся самым кликабельным элементом сайта, а количество заявок растет на 10-25% в зависимости от тематики.

Карты тепловых кликов:







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

Сервис готов, а что дальше?


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

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

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

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



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



Не исключением стали и мы. Увидев потребность в небольшой нише, мы так же сделали свой виджет со ссылкой на наш сервис, и на данный момент доля регистраций переваливает за 50% от общего числа.



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

Влияние рекламной стратегии на функционал и результаты


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

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

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

Если этот кейс показался вам полезным или интересным, то рекомендую так же почитать мои заметки в Telegram-канале @rovertask о развитии нашего нового стартапа, мессенджере для бизнеса Rovertask.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334158/


Метки:  

Новшества главной робототехнической олимпиады России 2017 в официальном видео

Среда, 26 Июля 2017 г. 10:45 + в цитатник




Опубликовали видео о Всероссийской Робототехнической Олимпиаде, которая проходила на базе Университета Иннополис 23—25 июня. Герои ролика рассказывают о главной теме соревнования «Устойчивое развитие», о новых номинациях этого года и о технологиях, способных сделать жизнь людей удобнее и безопаснее.

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

Все победители и призёры примут участие в Федеральных учебно-тренировочных сборах на базе Университета Иннополис. В сентябре по итогам сборов вуз объявит состав сборной России, которая отправится на Всемирную олимпиаду роботов: 10—12 ноября в Коста-Рике. 

Подробный обзор проектов-призёров творческой категории мы публиковали на Rusbase.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334152/


Метки:  

Быстрое удаление пробелов из строк на процессорах ARM — альтернативный анализ

Среда, 26 Июля 2017 г. 10:30 + в цитатник

Оригинал статьи: https://github.com/blu/ascii_pruner
Автор: Мартин Кръстев


Один мой друг обратил мое внимание на интересную статью на habrahabr.ru — русский перевод статьи Дэниела Лемира Быстрое удаление пробелов из строк на процессорах ARM. Эта статья заинтриговала меня по двум причинам: во-первых, кто-то на самом деле потратил время и усилия по поиску оптимального решения общей проблемы на не-x86 архитектуре (ура!), а во-вторых, результаты автор дал в конце статьи немного озадачили меня: порядка 6-ти кратное преимущество для Intel? Автор сделал однозначный вывод, что ARM-у ну очень далеко по соотношению «эффективность на такт» до «большого железа» от Интела в этой простой задаче.


Вызов принят!


Но начнем с самого начала! Автор начал с некого бейзлайна — последовательной реализации, поэтому я тоже решил начать оттуда и двигаться вверх. Давайте назовем этот базис testee00 для пущей тайны:


inline void testee00() {
    size_t i = 0, pos = 0;
    while (i < 16) {
        const char c = input[i++];
        output[pos] = c;
        pos += (c > 32 ? 1 : 0);
    }
}

Я запускал testee00 на нескольких процессорах amd64 и одном процессоре arm64, используя разные версии компилятора GCC и Clang, всегда беря за основу лучший результат компиляции. Ниже приведены результаты соотношения такт/символ, рассчитанные perf -e cycles, деленным на количество обработанных символов (в нашем случае — 5 10 ^ 7 16) и усеченные до 4-й цифры после десятичной точки:


CPU Compiler & flags clocks/character
Intel Xeon E5-2687W (SNB) g++-4.8 -Ofast 1.6363
Intel Xeon E3-1270v2 (IVB) g++-5.1 -Ofast 1.6186
Intel i7-5820K (HSW) g++-4.8 -Ofast 1.5223
AMD Ryzen 7 1700 (Zen) g++-5.4 -Ofast 1.4113
Marvell 8040 (Cortex-A72) g++-5.4 -Ofast 1.3805

Таблица 1. Производительность testee00 на десктоповых ядрах


Интересно, не так ли? Маленький чип телефона (3-Decoder OoO) действительно дает лучшее соотношение такт / символ, чем более крупный настольный чип (в конце этой статьи вы можете увидеть фактические данные статистики).


Итак, давайте перейдем к SIMD. Я не претендую на то, чтобы считаться опытным кодером на NEON, но иногда я заморачиваюсь с ARM SIMD. Я не буду инлайнить подпрограммы SIMD в основную часть этой статьи, чтобы не отпугнуть читателя; Вместо этого весь тестовый код и участвующие тестовые процедуры можно найти в конце этой статьи.


Я взял на себя смелость изменить первоначальную процедуру обрезки SSSE3 Даниэля — на самом деле, я использовал свою версию для теста. Причина? Я не могу просто так взять 2 ^ 16 * 2 ^ 4 = 1 Мбайт таблицы поиска в моем коде — это был бы большой пожиратель кеша для любых сценариев, где мы не просто обрезаем потоки ascii, но вызов подпрограммы облегчает другую работу. Версия LSS-less SSSE3 поставляется с ценой немногочисленных вычислений, но работает только на регистрах, и, как вы увидите, цена за исключение таблицы не является запретительной даже при интенсивных нагрузках на обрезку. Более того, как новая версия SSSE3, так и версия NEON (ASIMD2) используют один и тот же алгоритм, поэтому сравнение является настолько прямым, насколько это возможно физически:


CPU Compiler & flags clocks/character
Intel Xeon E5-2687W (SNB) g++-4.8 -Ofast -mssse3 .4230
Intel Xeon E3-1270v2 (IVB) g++-5.4 -Ofast -mssse3 .3774
Marvell 8040 (Cortex-A72) g++-5.4 -Ofast -mcpu=cortex-a57 1.0503

Таблица 2. Производительность testee01 на десктопных ядрах


Замечание: Тюнинг микроархитектуры для A57 передается в билд arm64, поскольку планировщик A72 от компилятора явно хуже в этой версии, что касается кода NEON, и A57 является довольно «общим» общим знаменателем ARMv8, когда дело доходит до планирования.


Как вы видите, эффективность в расчете на такта составляет 2x в пользу Sandy Bridge — ядро, которое при том же (или аналогичном) fabnode будет в 4 раза больше по площади A72. Так что все не так уж плохо для телефонных чипов; )


Бонусный материал: тот же тест на малых arm64 and amd64 CP:


CPU Compiler & flags clocks/character, scalar clocks/character, vector
AMD C60 (Bobcat) g++-4.8 -Ofast -mssse3 3.5751 1.8215
MediaTek MT8163 (Cortex-A53) clang++-3.6 -march=armv8-a -mtune=cortex-a53 -Ofast 2.6568 1.7100

Таблица 3. Производительность testee00 на testee01 на entry-level ядрах




Xeon E5-2687W @ 3.10GHz


Scalar version


$ g++-4.8 prune.cpp -Ofast
$ perf stat -e task-clock,cycles,instructions -- ./a.out
alabalanica1234

 Performance counter stats for './a.out':

        421.886991      task-clock (msec)         #    0.998 CPUs utilized
     1,309,087,898      cycles                    #    3.103 GHz
     4,603,132,268      instructions              #    3.52  insns per cycle

       0.422602570 seconds time elapsed

$ echo "scale=4; 1309087898 / (5 * 10^7 * 16)" | bc
1.6363

SSSE3 version (batch of 16, misaligned write)


$ g++-4.8 prune.cpp -Ofast -mssse3
$ perf stat -e task-clock,cycles,instructions -- ./a.out
alabalanica1234a

 Performance counter stats for './a.out':

        109.063426      task-clock (msec)         #    0.997 CPUs utilized
       338,414,215      cycles                    #    3.103 GHz
     1,052,118,398      instructions              #    3.11  insns per cycle

       0.109422808 seconds time elapsed

$ echo "scale=4; 338414215 / (5 * 10^7 * 16)" | bc
.4230



Xeon E3-1270v2 @ 1.60GHz


Scalar version


$ g++-5 -Ofast prune.cpp
$ perf stat -e task-clock,cycles,instructions -- ./a.out
alabalanica1234

 Performance counter stats for './a.out':

        810.515709 task-clock (msec)         #    0.999 CPUs utilized
     1,294,903,960 cycles                    #    1.598 GHz
     4,601,118,631 instructions              #    3.55  insns per cycle

       0.811646618 seconds time elapsed

$ echo "scale=4; 1294903960 / (5 * 10^7 * 16)" | bc
1.6186

SSSE3 version (batch of 16, misaligned write)


$ g++-5 -Ofast prune.cpp -mssse3
$ perf stat -e task-clock,cycles,instructions -- ./a.out
alabalanica1234a

 Performance counter stats for './a.out':

        188.995814 task-clock (msec)         #    0.997 CPUs utilized
       301,931,101 cycles                    #    1.598 GHz
     1,050,607,539 instructions              #    3.48  insns per cycle

       0.189536527 seconds time elapsed

$ echo "scale=4; 301931101 / (5 * 10^7 * 16)" | bc
.3774



Intel i7-5820K


Scalar version


$ g++-4.8 -Ofast prune.cpp
$ perf stat -e task-clock,cycles,instructions -- ./a.out
alabalanica1234

 Performance counter stats for './a.out':

        339.202545      task-clock (msec)         #    0.997 CPUs utilized
     1,204,872,493      cycles                    #    3.552 GHz
     4,602,943,398      instructions              #    3.82  insn per cycle

       0.340089829 seconds time elapsed

$ echo "scale=4; 1204872493 / (5 * 10^7 * 16)" | bc
1.5060



AMD Ryzen 7 1700


Scalar version


$ perf stat -e task-clock,cycles,instructions -- ./a.out
alabalanica1234

 Performance counter stats for './a.out':

        356,169901      task-clock:u (msec)       #    0,999 CPUs utilized
        1129098820      cycles:u                  #    3,170 GHz
        4602126161      instructions:u            #    4,08  insn per cycle

       0,356353748 seconds time elapsed

$ echo "scale=4; 1129098820 / (5 * 10^7 * 16)" | bc
1.4113



Marvell ARMADA 8040 (Cortex-A72) @ 1.30GHz


Scalar version


$ g++-5 prune.cpp -Ofast
$ perf stat -e task-clock,cycles,instructions -- ./a.out
alabalanica1234

 Performance counter stats for './a.out':

        849.549040      task-clock (msec)         #    0.999 CPUs utilized
     1,104,405,671      cycles                    #    1.300 GHz
     3,251,212,918      instructions              #    2.94  insns per cycle

       0.850107930 seconds time elapsed

$ echo "scale=4; 1104405671 / (5 * 10^7 * 16)" | bc
1.3805

ASIMD2 version (batch of 16, misaligned write)


$ g++-5 prune.cpp -Ofast -mcpu=cortex-a57 -mtune=cortex-a57
$ perf stat -e task-clock,cycles,instructions -- ./a.out
alabalanica1234

 Performance counter stats for './a.out':

        646.394560      task-clock (msec)         #    0.999 CPUs utilized
       840,305,966      cycles                    #    1.300 GHz
       801,000,092      instructions              #    0.95  insns per cycle

       0.646946289 seconds time elapsed

$ echo "scale=4; 840305966 / (5 * 10^7 * 16)" | bc
1.0503

ASIMD2 version (batch of 32, misaligned write)


$ clang++-3.7 prune.cpp -Ofast -mcpu=cortex-a57 -mtune=cortex-a57
$ perf stat -e task-clock,cycles,instructions -- ./a.out
alabalanica1234

 Performance counter stats for './a.out':

       1140.643640      task-clock (msec)         #    0.999 CPUs utilized
     1,482,826,308      cycles                    #    1.300 GHz
     1,504,011,807      instructions              #    1.01  insns per cycle

       1.141241760 seconds time elapsed

$ echo "scale=4; 1482826308 / (5 * 10^7 * 32)" | bc
.9267



AMD C60 (Bobcat) @ 1.333GHz


Scalar version


$ g++-4.8 prune.cpp -Ofast
$ perf stat -e task-clock,cycles,instructions -- ./a.out
alabalanica1234

 Performance counter stats for './a.out':

       2208.190651 task-clock (msec)         #    0.997 CPUs utilized
     2,860,081,604 cycles                    #    1.295 GHz
     4,602,968,860 instructions              #    1.61  insns per cycle

       2.214173331 seconds time elapsed

$ echo "scale=4; 2860081604 / (5 * 10^7 * 16)" | bc
3.5751

SSSE3 version (batch of 16, misaligned write)


$ clang++-3.5 prune.cpp -Ofast -mssse3
$ perf stat -e task-clock,cycles,instructions -- ./a.out
alabalanica1234a

 Performance counter stats for './a.out':

       1098.519499 task-clock (msec)         #    0.998 CPUs utilized
     1,457,266,396 cycles                    #    1.327 GHz
     1,053,073,591 instructions              #    0.72  insns per cycle

       1.101240320 seconds time elapsed

$ echo "scale=4; 1457266396 / (5 * 10^7 * 16)" | bc
1.8215



MediaTek MT8163 (Cortex-A53) @ 1.50GHz (sans perf)


Scalar version


$ ../clang+llvm-3.6.2-aarch64-linux-gnu/bin/clang++ prune.cpp -march=armv8-a -mtune=cortex-a53 -Ofast
$ time ./a.out
alabalanica1234

real    0m1.417s
user    0m1.410s
sys     0m0.000s
$ echo "scale=4; 1.417 * 1.5 * 10^9 / (5 * 10^7 * 16)" | bc
2.6568

ASIMD2 version (batch of 16, misaligned write)


$ ../clang+llvm-3.6.2-aarch64-linux-gnu/bin/clang++ prune.cpp -march=armv8-a -mtune=cortex-a53 -Ofast
$ time ./a.out
alabalanica1234

real    0m0.912s
user    0m0.900s
sys     0m0.000s
$ echo "scale=4; 0.912 * 1.5 * 10^9 / (5 * 10^7 * 16)" | bc
1.7100

Мартин Кръстев.


Перевод: Дмитрий Александров

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334142/


Метки:  

[Перевод] Анализ исходного кода Doom 3

Среда, 26 Июля 2017 г. 10:20 + в цитатник

Метки:  

[Из песочницы] Простой трекер семейного бюджета с помощью AWS SES, Lambda и DynamoDB (и Route53)

Среда, 26 Июля 2017 г. 10:20 + в цитатник

Как контролировать семейный бюджет?


image


У меня всегда были сложности точно следовать бюджету, особенно сейчас, когда все покупки проходят по кредитной карте. Причина проста — перед глазами нет пачки денег, которая постепенно сокращается, и в какой-то момент ты понимаешь, что тратить больше нечего. Если большая часть покупок оплачивается кредитной картой, то единственный способ узнать, сколько cредств осталось или сколько потрачено, это зайти в Интернет-банк или мобильный банк, или же использовать финансовые агрегаторы, например Mint, в которые тоже надо заходить и проверять баланс. Это возможно, но на это требуется дисциплина, а когда с той же карточки платишь не только ты, то установить её сложно.


Я подумал, что меня устроит вариант, если каждый день мне будет приходить уведомление о том, сколько денег у меня ещё осталось в этом месяце. То есть я бы устанавливал бюджет на месяц, и что-то бы считало мои траты и каждый день посылало отчёт о состоянии бюджета.


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


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


Что нам понадобится в AWS?


В AWS есть множество сервисов, но нам нужно всего три: чтобы получать и отправлять электронные письма — SES, чтобы их обрабатывать — Lambda, и чтобы хранить результат DynamoDB. Плюс ещё пара вспомогательных для связки — SNS, Kinesis, CloudWatch. Это не единственный вариант обработки сообщений: вместо Lambda можно использовать EC2, вместо DynamoDB хранить данные можно в RDS (MySQL, PostgreSQL, Oracle, …), а можно и вообще написать простенький скрипт на своём маленьком сервере на перле и BerkleyDB.


Как выглядит вся обработка в общем? Приходит письмо о транзакции, мы записываем дату, сумму и место платежа в БД, и раз в день отправляем письмо с остатком для данного месяца. Вся архитектура чуть сложнее и выглядит следующим образом:



  1. Письмо приходит в SES.
  2. SES отправляет письмо в SNS топик.
  3. Lambda-функция ProcessCharge запускается по приходу письма по SNS, парсит письмо и записывает данные о транзакции в DynamoDB таблицу Transactions.
  4. Lambda-функция UpdateSummary срабатывает как триггер после записи в таблицу Transactions и обновляет данные о текущем состоянии бюджета в таблице Summary.

Рассмотрим эти шаги более подробно.


Получение письма


Simple Email Service, он же SES, это сервис для приёма и отправки писем. При получении письма можно указать, какое действие должно быть выполнено: сохранить письмо в S3, вызвать Lambda-функцию, послать письмо в SNS и другие. Для получения писем необходимо привязать свой домен, а именно указать SES сервера в MX записи домена. Своего домена у меня на тот момент не было, и я решил, что это хороший повод его зарегистрировать, воспользовавшись ещё одним AWS сервисом Route 53. Захостил я его тоже там же, в Route 53.


При привязки домена к SES требуется его проверка. Для этого SES просит добавить некоторые записи в DNS зону (MX и TXT), а затем проверяет их наличие. Если домен хостится в Route 53, то всё это делается автоматически. Когда домен проверен, можно переходить к настройке правил для получения почты. Моё единственное правило очень простое: все письма, приходящие на адрес ccalert@ нашего домена, отправлять в SNS топик ccalerts:


aws> ses describe-receipt-rule --rule-set-name "ccalerts" --rule-name "ccalert"
{
    "Rule": {
        "Name": "ccalert",
        "Recipients": [
            "ccalert@=censored=”
        ],
        "Enabled": true,
        "ScanEnabled": true,
        "Actions": [
            {
                "SNSAction": {
                    "TopicArn": "arn:aws:sns:us-west-2:=censored=:ccalerts",
                    "Encoding": "UTF-8"
                }
            }
        ],
        "TlsPolicy": "Optional"
    }
}

Обработка письма


Когда новое письмо публикуется в SNS-топик, вызывается Lambda-функция ProcessCharge. Ей нужно сделать два действия — распарсить письмо и сохранить данные в БД.


from __future__ import print_function
import json
import re
import uuid
from datetime import datetime
import boto3

def lambda_handler(event, context):
    message = json.loads(event['Records'][0]['Sns']['Message'])
    print("Processing email {}".format(message['mail']))

    content = message['content']
    trn = parse_content(content)
    if trn is not None:
        print("Transaction: %s" % trn)
        process_transaction(trn)

За парсинг отвечает метод parse_content():


def parse_content(content):
    content = content.replace("=\r\n", "")
    match = re.search(r'A charge of \(\$USD\) (\d+\.\d+) at (.+?) has been authorized on (\d+/\d+/\d+ \d+:\d+:\d+ \S{2} \S+?)\.', content, re.M)
    if match:
        print("Matched %s" % match.group(0))
        date = match.group(3)

        # replace time zone with hour offset because Python can't parse it
        date = date.replace("EDT", "-0400")
        date = date.replace("EST", "-0500")

        dt = datetime.strptime(date, "%m/%d/%Y %I:%M:%S %p %z")
        return {'billed': match.group(1), 'merchant': match.group(2), 'datetime': dt.isoformat()}
    else:
        print("Didn't match")
        return None

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


A charge of ($USD) 100.00 at Amazon.com has been authorized on 07/19/2017 1:55:52 PM EDT.

К сожалению, стандартная библиотека Питона знает мало часовых поясов, и EDT (Eastern Daylight Time) не среди них. Поэтому мы заменяем EDT на числовое обозначение -0400, и делаем такое же для основного часового пояса, EST. После этого мы можем распарсить дату и время транзакции, и преобразовать его в стандартный формат ISO 8601, поддерживаемый DynamoDB.


Метод возвращает хэш-таблицу с суммой транзакции, названием магазина и датой со временем. Эти данные передаются в метод process_transaction:


def process_transaction(trn):
    ddb = boto3.client('dynamodb')
    trn_id = uuid.uuid4().hex
    ddb.put_item(
        TableName='Transactions',
        Item={
            'id': {'S': trn_id},
            'datetime': {'S': trn['datetime']},
            'merchant': {'S': trn['merchant']},
            'billed': {'N': trn['billed']}
        })

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



Обновление бюджета


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


  • budget — размер бюджета на месяц;
  • total — сумма трат за месяц;
  • available — остаток, (buget — total);

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


  1. Каждый раз, когда надо узнать состояние бюджета, транзакции суммируются чтобы получить total, затем available = (budget — total).
  2. Каждый раз, когда записывается новая транзакция, обновляется total. Когда надо узнать состояние бюджета, делается available = (budget — total).

Оба подхода имеют плюсы и минусы, и выбор сильно зависит от требований и ограничений системы. Первый подход хорош тем, что он не денормализует данные, храня отдельно сумму транзакций. С другой стороны, с ним сумму надо считать при каждом запросе. Для моих объёмов это не будет проблемой, но в моём случае у меня есть ограничение, вызванное DynamoDB. Чтобы посчитать сумму N транзакций, надо прочитать N записей, а значит потратить N read capacity units. Очевидно, это не очень масштабируемое решение, которое будет вызывать сложности (или высокую стоимость) даже при нескольких десятках транзакций.


При использовании второго подхода, total обновляется после каждой транзакции и всегда актуально, что позволяет избежать суммирования всех транзакций. Мне этот подход показался более рациональным в моём случае. Реализовать его, опять же, можно по-разному:


  1. Обновлять total после записи каждой транзакции в той же Lambda-функции ProcessCharge.
  2. Обновлять total в триггере после добавления нового элемента в таблицу Transactions.

Обновление в триггере более практично, в том числе с точки зрения многопоточности, поэтому я создал Lambda-функцию UpdateSummary:


from __future__ import print_function
from datetime import datetime
import boto3

def lambda_handler(event, context):
    for record in event['Records']:
        if record['eventName'] != 'INSERT':
            print("Unsupported event {}".format(record))
            return

        trn = record['dynamodb']['NewImage']
        print(trn)

        process_transaction(trn)

Нас интересуют только события о добавлении элементов в таблицу, все остальные игнорируются.


def process_transaction(trn):
    period = get_period(trn)
    if period is None:
        return

    billed = trn['billed']['N']

    # update total for current period
    update_total(period, billed)

    print("Transaction processed")

В process_transaction() мы вычисляем период, в виде год-месяц, к которому относится транзакция, и вызываем метод обновления total.


def get_period(trn):
    try:
        # python cannot parse -04:00, it needs -0400
        dt = trn['datetime']['S'].replace("-04:00", "-0400")
        dt = dt.replace("-05:00", "-0500")
        dt = dt.replace("-07:00", "-0700")
        dt = datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S%z")

        return dt.strftime("%Y-%m")
    except ValueError as err:
        print("Cannot parse date {}: {}".format(trn['datetime']['S'], err))
        return None

Этот код весьма далёк от совершенства, и в этом сыграла роль интересная особенность Питона, что он не может распарсить дату/время с часовым поясом в формате -HH:MM, который соответствует стандарту ISO 8601, и которую сам же Питон и сгенерировал (код выше, в методе parse_content()). Поэтому нужные мне часовые пояса я просто заменяю на понимаемый им формат -HHMM. Можно было воспользоваться сторонней библиотекой и сделать это более красиво, оставлю это на будущее. Возможно, ещё сказывается моё плохое знание Питона — этот проект мой первый опыт разработки на нём.


Обновление total:


def update_total(period, billed):
    ddb = boto3.client('dynamodb')

    response = load_summary(ddb, period)
    print("Summary: {}".format(response))

    if 'Item' not in response:
        create_summary(ddb, period, billed)
    else:
        total = response['Item']['total']['N']
        update_summary(ddb, period, total, billed)

В этом методе мы загружаем сводку (Summary) за текущий период с помощью метода load_summary(), total в котором нам надо обновить. Если сводки ещё не существует, мы создаём её в методе create_summary(), если существует, обновляем в update_summary().


def load_summary(ddb, period):
    print("Loading summary for period {}".format(period))
    return ddb.get_item(
        TableName = 'Summary',
        Key = {
            'period': {'S': period}
        },
        ConsistentRead = True
    )

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


def create_summary(ddb, period, total):
    print("Creating summary for period {} with total {}".format(period, total))
    ddb.put_item(
        TableName = 'Summary',
        Item = {
            'period': {'S': period},
            'total': {'N': total},
            'budget': {'N': "0"}
        },
        ConditionExpression = 'attribute_not_exists(period)'
    )

При создании новой сводки, по той же причине возможной записи из нескольких потоков, используется условная запись, ConditionExpression = 'attribute_not_exists(period)', которая сохранит новую сводку только в случае, если она не существует. Таким образом, если кто-то успел создать сводку в промежутке, когда мы попробовали её загрузить в load_summary() и её не было, и когда мы попытались её создать в create_summary(), наш вызов put_item() завершится исключением и вся Lambda-функция будет перезапущена.


def update_summary(ddb, period, total, billed):
    print("Updating summary for period {} with total {} for billed {}".format(period, total, billed))
    ddb.update_item(
        TableName = 'Summary',
        Key = {
            'period': {'S': period}
        },
        UpdateExpression = 'SET #total = #total + :billed',
        ConditionExpression = '#total = :total',
        ExpressionAttributeValues = {
            ':billed': {'N': billed},
            ':total': {'N': total}
        },
        # total is a reserved word so we create an alias #total to use it in expression
        ExpressionAttributeNames = {
            '#total': 'total'
        }
    )

Обновления значения total в сводке производится внутри DynamoDB:


UpdateExpression = 'SET #total = #total + :billed'

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


ConditionExpression = '#total = :total',

Так как total является ключевым словом для DynamoDB, чтобы использовать его в выражениях DynamoDB надо создать синоним:


ExpressionAttributeNames = {
'#total': 'total'
}

На этом процесс обработки транзакций и обновления бюджета завершён:


period budget total
2017-07 1000 500

Отправка уведомления о состоянии бюджета


Последняя часть системы — уведомление о состояние бюджета. Как я писал в самом начале, мне достаточно получать уведомление раз в день, что я и реализовал. Однако ничего не мешает уведомлять после каждой транзакции, или после каких-то пороговых значений расходов / остатка. Архитектура отправки электронного письма с уведомлением достаточно проста и выглядит так:



  1. Таймер CloudWatch Timer срабатывает раз в день и вызывает Lambda-функцию DailyNotification.
  2. DailyNotification загружает данные из DynamoDB таблицы Summary и вызывает SES для отправки письма.

from __future__ import print_function
from datetime import date
import boto3

def lambda_handler(event, context):
    ddb = boto3.client('dynamodb')
    current_date = date.today()
    print("Preparing daily notification for {}".format(current_date.isoformat()))

    period = current_date.strftime("%Y-%m")
    response = load_summary(ddb, period)
    print("Summary: {}".format(response))

    if 'Item' not in response:
        print("No summary available for period {}".format(period))
        return

    summary = response['Item']
    total = summary['total']['N']
    budget = summary['budget']['N']
    send_email(total, budget)

def load_summary(ddb, period):
    print("Loading summary for period {}".format(period))
    return ddb.get_item(
        TableName = 'Summary',
        Key = {
            'period': {'S': period}
        },
        ConsistentRead = True
    )

Сперва мы пытаемся загрузить сводку для текущего периода, и если её нет, то заканчиваем работу. Если есть — готовим и отправляем письмо:


def send_email(total, budget):
    sender = "Our Budget <ccalert@==censored==>"
    recipients = [“==censored==“]
    charset = "UTF-8"

    available = float(budget) - float(total)
    today = date.today().strftime("%Y-%m-%d")

    message = '''
As of {0}, available funds are ${1:.2f}. This month budget is ${2:.2f}, spendings so far totals ${3:.2f}.

More details coming soon!'''

    subject = "How are we doing?"       
    textbody = message.format(today, float(available), float(budget), float(total))
    print("Sending email: {}".format(textbody))

    client = boto3.client('ses', region_name = 'us-west-2')
    try:
        response = client.send_email(
            Destination = {
                'ToAddresses': recipients
            },
            Message = {
                'Body': {
                    'Text': {
                        'Charset': charset,
                        'Data': textbody,
                    },
                },
                'Subject': {
                    'Charset': charset,
                    'Data': subject,
                },
            },
            Source = sender,
        )

    # Display an error if something goes wrong. 
    except Exception as e:
        print("Couldn't send email: {}".format(e))
    else:
        print("Email sent!")

Итог


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

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334146/


Метки:  

БИТ-пикник глоток лета и полезной информации

Среда, 26 Июля 2017 г. 09:54 + в цитатник


Компания HPE не первый год проводит свои выездные мероприятия по всей стране. Объехав большинство крупных регионов России, в этом году БИТ-пикник был организован и в Московском регионе. Об основных докладах и о самом мероприятии в общем я сегодня и хочу вам рассказать, поделиться собственными впечатлениями.

Но, начать хотелось бы с неприятного. На мой взгляд дата мероприятия была выбрана не совсем верно. Связано это с выходом новых процессоров Intel и, соответственно, обновлением линеек серверных продуктов компании HPE. Дело в том, что анонс новых процессоров Intel был запланирован на следующий день после БИТ-пикника и компания не имела возможности привезти новое поколение серверных продуктов (кроме Microserver Gen10, обзор которого нам уже пообещали в ближайшей перспективе) и рассказать о них хоть какую-то информацию. Но, несмотря на это, доклады на мероприятии оказались не менее интересными. О них я и постараюсь рассказать. Не буду даже пытаться в полной мере рассказать о тех решениях, которые были освещены, так как на это потребуется далеко не одна статья, поэтому для всех заинтересовавшихся я просто оставлю ссылки на имеющиеся вебинары по этим продуктам.

Так же было приятно видеть не просто «голые» доклады, но и то, что компания HPE привезла немного своего оборудования и устроила демонстрационные стенды.









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



Следующим выступил Олег Васьков, руководитель Центра высоких технологий HPE, который занимается в том числе и подготовкой тестовых стендов для заказчиков компании HPE. Он говорил о новых идеях в IT бизнесе, о их необходимости и внедрении, называя это «ИТ экономикой идей». Вообще выступления Олега очень запомнились. Человек настолько любит компанию, в которой он работает, и продукты, которые она выпускает, что слушать его можно очень долго.



Олег и на выставочном стенде, присутствующем на конференции, ещё долго рассказывал всем желающим о продуктах компании (в этот день он отвечал за x86 серверы и платформу Moonshot). По своему настроению и восторженности от собственных продуктов его презентация напоминала мне чем-то Apple-эвенты.



Далее свою презентацию представил Владислав Логвиненко, менеджер по системам хранения HPE. Он рассказал о том, что нового произошло за последнее время в направлении СХД HPE 3Par, о преимуществах этой системы, а так же рассказал о недавней покупке компании HPE — компании Nimble. Лучше, чем он сам, я вам всё-равно не расскажу, поэтому, если вам интересно данное направление, рекомендую ознакомится с его вебинаром — Обновление продуктовой линейки семейства HPE 3PAR. В вебинаре рассказывается о HPE Nimble InfoSight и о планах интеграции этой системы в массивы 3Par, а так же про поддержку накопителей Intel Optane массивами 3Par, которая станет доступна уже в конце этого года (как только Intel Optane появится на рынке).



Следующим был доклад от компании Red Hat, которая традиционно рассказала о своих продуктах и преимуществах СПО, о том чем отличается решение Red Hat от ПО других разработчиков и почему стоит выбрать именно Rad Hat. Честно сказать, я немного пропустил это выступление, углубившись в общение с представителями HPE на стендах.



»Гиперконвергенция HPE SimpliVity – примеры внедрений", — с такой презентацией выступил Виталий Артемьев, региональный директор по России и СНГ компании SimpliVity. Он рассказал о продукте который компания HPE так же недавно приобрела — SimpliVity. Не все из присутствующих были знакомы с данной гиперконвергентной системой, поэтому его выступление вызвало большой интерес. Основную идею системы я взял из презентации Виталия,



а за более подробной информацией по этому направлению опять-таки отсылаю вас к двум недавним вебинарам по данной теме.

Анатомия гиперконвергенции HPE: внедрение в СМБ, филиалах, VDI и разработке
HPE SimpliVity 380 — самая полная гиперконвергентная платформа на рынке

Завершил первую часть семинара Вячеслав Закариев, руководитель IT департамента компании HENDERSON, который рассказал о проблемах, которые у них возникали во время эксплуатации, какие из намеченных проблем они планировали решить, как достигали результата и какое оборудование HPE в этом помогало. Выступление, интересное наверное больше представителям бизнеса, показало насколько эффективны продукты HPE.

Компания HPE постаралась учесть интересы всех посетителей мероприятия и после основного ряда докладов было разделено на 2 части: первая часть была для IT, по продуктам и технологиям компании, вторая же часть была посвящена бизнесу. Естественно для себя я выбрал посещение именно ITшных докладов.

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



Благо лето в Москве в этом году нас радует не очень сильно, по этому я был рад совместить приятное с полезным.



И первым, после обеда, на технической ветке появился Олег Васьков, говоривший о сотрудничестве Intel и HPE. К сожалению, как я уже говорил в начале, время мероприятия было выбрано не слишком удачно и буквально к вечеру того же дня большая часть рассказанной им информации была уже не совсем актуальна. Если вы хотите в числе первых послушать про новую линейку серверов компании HPE, то я предлагаю обратиться к их официальному YouTube каналу, где уже появилось несколько обзоров:

Обзор 1
Обзор 2
Обзор 3
Обзор 4

За время подготовки этой статьи, ребята из HPE анонсировали старт продаж некоторых моделей серверов Gen 10, рассказали о нововведениях и моделях, которые уже доступны к заказу. Компания HPE начала продажи новых серверов HPE ProLiant Gen10



Продолжил техническую ветку сессий — Дамир Артыков, руководитель отдела разработки сетевых решений Aruba. Честно признаюсь — в сетях я не понимаю совершенно ничего, поэтому доклад пропустил мимо ушей, как раз в этот момент у меня заработал Wi-Fi и я стал проверять рабочую почту.

Но я собрал для вас небольшую подборку вебинаров по Aruba от HPE:

Как правильно “приготовить” Wi-Fi: современный подход HPE Aruba
Кто в вашей сети? Функции и сценарии применения платформы безопасности Aruba
ArubaOS 8: умная операционная система для рабочего места будущего
AirWave или Central: какая система управления Aruba подойдет именно вашей сети?
HPE ArubaOS-Switch: удобство управления и безопасность вашей сети



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



Следующее выступление было для меня не менее интересно, т.к. у экрана появился Александр Светлаков, руководитель направления Blade-систем и платформы Synergy. Кто-то уже возможно слышал о данной системе, а кто-то мог уже читать о ней здесь на Хабре. Если же для вас это что-то новое или вы знаете о ней не всё, что хотелось бы, то я порекомендую серию достаточно подробных вебинаров по этой платформе.

Платформа HPE Synergy для корпоративных ЦОД – часть 1
Платформа HPE Synergy для корпоративных ЦОД – часть 2
Платформа HPE Synergy для корпоративных ЦОД – часть 3
Платформа HPE Synergy для корпоративных ЦОД – часть 4
Платформа HPE Synergy для корпоративных ЦОД – часть 5

Заканчивал официальную часть данного мероприятия так же Александр, рассказав о платформе централизованного управления OneView. И ведь действительно — единая система управления всей инфраструктурой снижает и время, необходимое на развёртывание оборудования, на процессы администрирования, и так же экономию средств. Но лично я, за все свои годы работы в различных компаниях и работе с заказчиками, никогда не видел на практике использование подобных систем. Действительно бывали редкие случаи, когда в компании всё построено на оборудовании одного вендора, но даже в этих случаях подобные системы не использовались.

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

А в конце я хотел бы поблагодарить компанию HPE и лично Алексея Казьмина за приглашение на мероприятие и пожелать удачи на будущих митапах.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334134/


Метки:  

История с хэппи-эндом: интеграция «Битрикс24» с Asterisk

Среда, 26 Июля 2017 г. 09:35 + в цитатник


Сегодня жизненно необходима интеграция CRM и телефонии. Если клиент слишком долго слушает автоматическое приветствие или вы не перезваниваете по оставленной им на сайте заявке — вы его потеряете.

Как мы, компания-интегратор informUnity, пришли к созданию массового продукта для интеграции «Битрикс24» и Asterisk под управлением FreePBX, и что из этого вышло — под катом.

Предыстория


К концу 2016 года у нас было практически готовое решение для контакт-центров на базе коробочного «Битрикс24» и Asterisk. Практически — потому что используемый для обработки WebRTC в браузере форк SIPML5 еще не был отлажен.

Мы уже планировали финальное тестирование и запуск тиражируемого продукта, когда в декабре появилась поддержка телефонии в REST API «Битрикс24». А вместе с ней коллегам понадобилось интегрировать Asterisk и «Битрикс24» с помощью новых REST-методов.

Тем временем потребность в такой интеграции как раз назрела. Связка через VoxImplant включала лишнее звено, требовала «танцев с бубном» в настройке и лишала «астерискеров» свободы. Так как часть логики обработки звонка вместе с SIP трафиком отдавалась во внешнюю систему.

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



MVP


Оказалось, что у коллег используется целых три Asterisk:

  • один с кастомными контекстами
  • два подключенных к первому

Это затрудняло по сути несложную задачу:

  • определить ответственного
  • открыть карточку
  • записать звонок в CRM

Действительно несложная, — скажете вы. Часа на четыре работы. Так и есть: если пишете для себя, то можно ограничиться только нужными вам сценариями. Но любой шаг в сторону добавляет очередные четыре часа. Однако, мы делали для всех. Значит наша цель — не легкий путь для разработчика. А легкий путь для пользователя.
 
За основу решения выбрали фреймворк FreePBX v.13. Он самый популярный среди аналогов на сегодняшний день. Активно развивается и включает все необходимое для нашего решения.

Основную часть мы оформили как модуль для FreePBX.

Плюсы тринадцатой версии FreePBX:

  • современный интерфейс
  • удобные оповещения при настройке модуля
  • поддержка AJAX и
  • простой процесс обновления модуля с изменением структуры таблиц

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

Сегодня основная работа идет с контекстами ext-did-001, ext-did-002 и macro-dial-one для входящих звонков и outrt-, macro-dialout-trunk — для исходящих.

За два месяца Asterisk и «Битрикс24» были интегрированы. CRM «Битрикс24» теперь следит всевидящим оком за входящими и исходящими звонками.

Мы получили большой опыт в ходе совместной работы. Многочисленные обсуждения разных сценариев не прошли зря. А некоторые багрепорты закрывались в течение дня. К концу марта у нас был продукт, который мы уже могли отдать в каталог приложений с пометкой “бета”.



Первые результаты


Создавая MVP, мы ориентировались на простую и прозрачную логику. Например, время начала и конца разговора привязано к каналу внешнего абонента (при входящем — первый открывшийся канал, при исходящем — канал, на котором находится вызываемый номер). В беклог MVP не вошла поддержка Ring Groups и FollowMe. Но это не повлияло на функциональность, так как они заменяются на Queues.
 
Результат не заставил себя долго ждать: с первых дней мы получаем 15–20 установок в день. Для нас это была проверка гипотезы. Первая бета-версия представляла из себя достаточно сырой MVP. Поэтому такой результат придал нам сил и уверенности. А вместе с уверенностью пришел и шквал вопросов на первую линию.



С заботой о пользователях


Большинство установок Asterisk отрезаны от мира и спокойно работают за NAT. Тем не менее, получать от сисадминов десятки вопросов о том, как настраивать Firewall для интеграции, было весьма удивительно.

«Проброс портов? Конечно слышали. А что пробрасывать? Куда? Зачем?».

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


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

Высокая динамика разработки накладывает ограничения на проектирование интерфейсов. Мы поставили перед собой амбициозную задачу — сделать удобное приложение для связки «Битрикс24» с Asterisk. И мы справились — теперь «подружить» их сможет любой желающий.



Вместо послесловия


За полтора месяца бета-тестирования мы проверили множество гипотез и реализовали десятки сценариев. Это заслуга службы поддержки.
 
Мы сразу отказались от тикетов и электронной почты. Такая переписка не предполагает быстрой реакции. А рассмотрение одного простого вопроса может затянуться на несколько дней.

Нам очень помогли открытые линии в «Битрикс24». И мы, и клиенты пользуемся одним продуктом. Клиент всегда может найти нашу открытую линию в списке своих чатов и посмотреть всю историю переписки. Мы получаем задачи, внутренние коммуникации и общение с клиентом в одной экосистеме.
 
Благодаря такому формату клиенты получают ответ на обращение в среднем в течение трёх минут. А клиент доволен поддержкой и охотно делится не только проблемами, но и идеями по улучшению продукта.
 
С выходом stable-версии нам пришлось искусственно снижать динамику в пользу качества: ответственность перед коммерческими пользователями не дает экспериментировать в прежних масштабах.

Сборку и тестирование, а также установку и работу модуля в Docker-контейнерах, автоматизировали на базе GitLab CI (об этом планируем написать отдельно). Обновления стараемся выпускать раз в неделю, но все эксперименты вынесли в ветку beta. Кстати, приглашаем к сотрудничеству бета-тестеров.



На этом и сказке конец, но история нашего решения только начинается.  
Сам продукт: ссылка.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334120/


Метки:  

Настройка push-нотификаций для своего сервиса

Среда, 26 Июля 2017 г. 08:23 + в цитатник
В этой публикации мы рассмотрим пример интеграции платформы подписки на push-уведомлений PushAll с сервисом мониторинга сайтов ХостТрекер. Эта информация будет полезна тем, кому необходимо быстро настроить push для своих сервисов, а желания изобретать велосипед нет.




В чем же дело?


Вопрос скорее риторический. Ранее мы опубликовали детальный обзор методов оповещений, которые использует ХостТрекер при фиксировании ошибок на сайтах клиентов. В нем была ссылка на конкретные исследования, которые вроде бы говорили нам, что push-уведомления в нашем случае не так актуальны. Тем не менее, запросы клиентов — прежде всего. К тому же, нашелся легкий способ их настроить.

Каждому — по Push-у


Итак, благодаря сервису PushAll есть возможность легко прикрутить пуш к чему бы то ни было. Рассмотрим наш пример.
Нам любезно создали микросервис, который принимает POST-запрос и рассылает push-уведомления. Ну а далее уже дело техники. В нашем случае нужно слать запрос на URL:

https://pushall.ru/channels/host-tracker/callback.php?uid=47920&key=0cfd2f05b7442aeb988a326f7adadb06

а шаблоны POST-запросов для разных случаев (падение и восстановление работы сайтов) у нас уже есть:


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

То есть, если необходимо получать уведомления о состоянии сайтов (аптайм, падения, обновления домена или сертификата, попадание в списки Роскомнадзора и т.д.) по Push — тогда три клика и готово. Если нужно прикрутить push к своему сервису — PushAll также предоставит вам такую возможность. Чтобы три клика и готово.


И, кстати, это еще один пример того, как ХостТрекер развивается благодаря клиентским запросам. Вряд ли кто-то знает лучше самих клиентов что им надо. Поэтому, если возникнут вопросы, пожелания или критика — всегда рады!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334038/


[Перевод] Дядя Боб Мартин: «Вези меня в Торонто, HAL»

Среда, 26 Июля 2017 г. 01:02 + в цитатник
Я не перестаю читать в новостях о неизбежном наступлении беспилотных автомобилей. Финансовые новости все время трещат об этой идее, и технологические тоже. Прогнозируют, что в течение следующих пяти лет водители грузовиков, таксисты и уберисты останутся без работы.

У меня есть одно слово для всех этих прогнозов: Торонто!

Вы помните тот момент, когда IBM Watson играл и выиграл в «Джеопарди»? [Jeopardy — ТВ игра в США, похожая на «Свою игру». — прим. пер.] Это произошло в феврале 2011 года. Успех был впечатляющим. Watson так значительно превосходил соперников-людей, что было несколько грустно. После этого, Кен Дженнингс [Ken Jennings], один из оппонентов Watson'а, который перед этим выиграл 74 игры подряд, нехотя признал поражение, приветствуя «наших новых компьютерных повелителей».

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

Один такой случай произошел, когда соперников попросили назвать город в США, в котором есть один аэропорт, названный в честь героя Второй Мировой Войны, и другой аэропорт, названный в честь битвы в ней же. Задумайтесь на секунду. Пробегитесь по трем крупнейшим городам в США. Нью-Йорк? Нет, Аэропорт Джона Кеннеди, Ла-Гуардия и Ньюарк не подходят. Лос-Анджелес? Нет, Аэропорт Лос-Анджелес, Аэропорт Джон Уэйн, Онтэрио не подходят. Ага! О'Хара и Мидуэй! Это они. Так какой город США выбрал Watson?

Торонто.

Конечно, сейчас ясно, что существовала причина, по которой Watson выбрал Торонто вместо Чикаго. В конце-концов, Watson был компьютером и у компьютеров всегда есть абсолютно дискретные и однозначные причины, по которым они делают что-либо. Ряд if-выражений, сравнивающих взвешенные значения при помощи сложного ассоциативного дерева, дал конечный, определенный результат. То есть, безусловно, существовала причина. Веская причина.

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

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

Итак, налицо дилемма: Watson превосходит соперников по «Джеопарди» со значительным отрывом. Заявляется, что машины без водителей будут так же значительно превосходить водителей-людей. Беспилотные автомобили уменьшат количество аварий и жертв, сделают дороги безопаснее. Так утверждают.

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

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

Представьте себе зал суда. Обезумевшие родители, гневная пресса, подавленные адвокаты, представляющие компанию, выпустившую автомобиль. Бортовой компьютер находится на стойке. Он вот-вот ответит на вопрос. Стоит тишина, поскольку все склонились к нему. Обвинитель задает вопрос по существу: «Почему этот ребенок должен был умереть?». И компьютер, распарсив все данные из памяти, бежит по цепочке if-выражений, сравнивая все аккуратно взвешенные значения, и наконец, отвечает: «Причина была в том, что Торонто».
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334130/


Метки:  

Мама хочет внуков! Или где может пригодиться телемедицина

Среда, 26 Июля 2017 г. 00:35 + в цитатник
image
На днях в России был принять законопроект о телемедицине, а значит с 1 января 2018 года врачи смогут взаимодействовать с пациентами удаленно (собирать анамнез до очного приема, консультировать — после. Очный прием для диагностики все еще будет обязателен), с 2019 — выписывать электронные рецепты (даже содержащие наркотические вещества, т.е. весь спектр препаратов).
Мы, юные и амбициозные аспиранты кафедры биотехнических систем, радостно чешем руки. Врачи — задумчиво чешут головы и не понимают, зачем им это надо при и без того большом потоке пациентов. Вопросов пока больше чем ответов, но сегодня хотим поделиться с хабравчанами нашими идеями по проекту удаленного мониторинга состояния здоровья плода и матери и, может, непоняток о пользе слова с большой буквы «Т» станет меньше.

Предыстория: на данный момент любая медицинская деятельность может осуществляться только очно, с использованием имеющихся протоколов обследований, документация — в бумажном виде. Если используется компьютер с электронными картами — все равно печатать и подшивать. Консультации врача по телефону, сервису Яндекс.Здоровье и проч. — не являются медицинской деятельностью со всеми вытекающими. Поэтому посещение врача или его приезд домой единственный вариант получить врачебную помощь и консультацию законным путем.

1 января 2018 все несколько упроститься.
Представьте. Вы, или ваша подруга/жена/девушка этажом ниже, носит в себе прекрасного малыша. Чудное утро, вкусный завтрак и внезапные сильные спазмы внизу живота сильно до срока. Дама вызывает скорую и ее увозят в больницу для проведения дополнительных обследований. Обследовали. Все в целом нормально, явных патологий нет, но врача что-то беспокоит. Тогда варианта два: на свой страх и риск (или потому что нет мест в стационаре) отпускать беременную домой, авось ничего не случится; или класть на сохранение и наблюдать в стационаре сколько-потребуется (а это могут быть и недели, и месяцы).

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

image

В случае соответствия показателей норме, устройство тихо ведет запись и не тревожит никого (зеленый уровень). Через смартфон передает на облако, когда есть Wi-fi или нормальная мобильная связь. Как только начинает что то меняться — формируется сигнал тревоги (Alarm). Он может быть желтого и красного уровней.
Приведем пример. Будущая мама живет на 7 этаже и решила пройтись пешком. Пульс взлетел, сатурация (процент кислорода в крови) упала. Устройство «запищит» и даст информационные подсказки, что лучше поскорее прилечь отдохнуть, а также подключит дополнительные каналы для анализа в «усиленном» режиме, чтобы отследить нормализацию состояния.
А вот если будущая мама лежит, яркой двигательной активности не проявляет, а пульс резко поменялся (у нее или у плода), и сатурация еще критично поползла — что-то явно идет не так, нужно срочно звонить врачу. И тут-то вступает в работу блок оперативного формирования пакета данных о состоянии пациентки, носимое устройство коннектиться со смартфоном пациентки и отправляет сведения о текущем состоянии пациентки лечащему врачу. Тот открывает это на своем телефоне и уже принимает решения о дальнейших действиях — нужна ли срочная помощь и вызов скорой, или же нет.

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

image

Беременная при этом спокойно живет дома. Под удаленным присмотром врача. Не бегает по ЖК почем зря, не лежит в больнице. Красота.

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

Что касается аналогов. Уже немало подобных идей было реализовано, конечно же, но большинство на уровне рабочих прототипов и с регистрацией и анализом только ЭКГ плода. И без связи с врачом. И без оперативного выявления патологий. Реально модная штука — фетальный ЭКГ монитор Monica, но он применим только в стационаре. Радиус «дальности» — комната, передача данных с носимого устройства идет на стационарный блок по Bluetooth.
Кажется, что поток гаджетов для медицины и так огромен, но сейчас это в 90% игрушки по типу фитнес трекеров. Так что волна новых, «действительно медицинских», приборов наблюдения за разными заболеваниями уже близко. Мы хотим довести проект до ума. Тем более, совсем скоро такого рода наблюдение уже станет медицинской деятельностью, а значит позволит диагностировать и лечить патологии на ранних стадиях. Это, несомненно, вдохновляет.
Если у вас есть какие-то комментарии, мысли или желания по поводу развития проекта — будем только рады!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334128/


Метки:  

Автоматизация IP-сети. Часть3 – Мониторинг TCP аномалий

Вторник, 25 Июля 2017 г. 22:49 + в цитатник
image alt В предыдущей статье рассмотрен мониторинг скорости открытия Веб ресурсов. В качестве параллельного процесса при измерении скорости, для более глубокого понимания возможных причин низкой скорости открытия Веб страниц, было бы интересно провести измерение TCP аномалий. Эту задачу попробуем решить в этой статье.
TCP аномалиями будем считать пакеты, которые свидетельствуют о потери информации в процессе передачи. Пожалуй, наиболее популярным инструментом глубокого анализа сетевого трафика, является утилита Wireshark и ее консольная версия tshark. Поэтому в качестве исходного анализатора будем рассматривать именно ее.
К TCP аномалиям будем относить следующее:
— tcp retransmission – Происходит, когда отправитель повторно передает пакет по истечении срока подтверждения.
— tcp duplicate_ack – Происходит, когда отображается один и тот же номер ACK и он меньше последнего байта данных, отправленных отправителем. Если приемник обнаруживает пробел в порядковых номерах, он будет генерировать дубликат ACK для каждого последующего пакета, который он получает по этому соединению, до тех пор, пока недостающий пакет не будет успешно принят (повторно передан).
— tcp lost_segment — Происходит, когда есть разрыв в порядковых номерах пакетов. Потеря пакетов может привести к дублированию ACK, что приведет к повторным передачам.
— tcp.analysis.fast_retransmission — Возникает, когда отправители получают несколько пакетов, порядковый номер которых больше, чем подтвержденные пакеты, в этом случае отправитель повторно передает пакет до истечения таймера подтверждения.
— tcp ack_lost_segment — Происходит, когда есть разрыв в порядковых номерах подтверждающих пакетов.
Для анализа пакетов при помощи tshark будем использовать следующее выражение:
tshark -i bce0 -t ad -qz io,stat,5,"(ip.addr==1.1.1.1) && tcp","COUNT(tcp.analysis.retransmission)(ip.addr==1.1.1.1) && tcp.analysis.retransmission","COUNT(tcp.analysis.duplicate_ack)(ip.addr==1.1.1.1) && tcp.analysis.duplicate_ack","COUNT(tcp.analysis.lost_segment)(ip.addr==1.1.1.1) && tcp.analysis.lost_segment","COUNT(tcp.analysis.fast_retransmission)(ip.addr==1.1.1.1) && tcp.analysis.fast_retransmission","COUNT(tcp.analysis.lost_segment)(ip.addr==1.1.1.1) && tcp.analysis.ack_lost_segment")

, где
bce0 – это название интерфейса на которому будет производится анализ пакетов. Это название в linux/Unix система можно увидеть командой ifconfig.
1.1.1.1 – IP адрес исследуемого ресурса
В результате вывода команды получаем таблицу, которую в последствии будем обрабатывать и подгружать в базу для построения графиков:
таблица
======================================================================================================
| IO Statistics                                                                                      |
|                                                                                                    |
| Duration: 5. 40977 secs                                                                            |
| Interval: 5 secs                                                                                   |
|                                                                                                    |
| Col 1: (ip.addr==1.1.1.1) && tcp                                                            |
|     2: COUNT(tcp.analysis.retransmission)(ip.addr==1.1.1.1) && tcp.analysis.retransmission  |
|     3: COUNT(tcp.analysis.duplicate_ack)(ip.addr==1.1.1.1) && tcp.analysis.duplicate_ack    |
|     4: COUNT(tcp.analysis.lost_segment)(ip.addr==1.1.1.1) && tcp.analysis.lost_segment      |
|     5: COUNT(tcp.analysis.fast_retransmission)(ip.addr==1.1.1.1) &&                         |
|        tcp.analysis.fast_retransmission                                                            |
|     6: COUNT(tcp.analysis.lost_segment)(ip.addr==1.1.1.1) && tcp.analysis.ack_lost_segment  |
|----------------------------------------------------------------------------------------------------|
|                     |1                |2      |3      |4      |5      |6      |                    |
| Date and time       | Frames |  Bytes | COUNT | COUNT | COUNT | COUNT | COUNT |                    |
|-------------------------------------------------------------------------------|                    |
| 2017-07-10 15:00:45 |    507 | 481496 |     1 |     0 |     2 |     0 |     0 |                    |
| 2017-07-10 15:00:50 |      0 |      0 |     0 |     0 |     0 |     0 |     0 |                    |
======================================================================================================

В качесте инструментов как и в прошлой статье будем использовать Cacti и Python3. Модернизируем скрипт из предыдущей статьи, для измерения скорости и TCP аномалий:
Код Python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import datetime
import re
import os
import subprocess
import argparse
import time
import signal

parser = argparse.ArgumentParser()
parser.add_argument("-h_page", "--hostname_page", dest = "hostname_page")
args = parser.parse_args()

curent_time=str(datetime.datetime.now().strftime("%Y-%m-%d_%H:%M:%S_"))
pid=os.getpid()


##########start Table parser###############
def parser_tshark_output(open_time, parser_file):
        table_data = {'date':[],'1 frame':[],'2 frame':[],'retr':[],'dup_ack':[],'lost_seg':[],'fast_retr':[],'ack_lost_seg':[]}
        lines = open(parser_file, 'r').readlines()
        lookup = 'tcp.analysis.ack_lost_segment '
        number = 0
        for num in lines:
                if lookup in num:
                        number+=lines.index(num)
                        try:
                                del (lines[-1])
                        except:
                                pass
        L=open("/usr/TEST/TMP_FILES/test_tshark_temp_"+str(os.getpid())+".txt", 'w')
        L.writelines(lines)
        L.close()
        with open("/usr/TEST/TMP_FILES/test_tshark_temp_"+str(os.getpid())+".txt", 'r') as table:
                if number != 0:
                        for _ in range(int(number+5)):
                                next(table)  #skip header
                        for row in table:
                                row=row.strip('\n').split('|')
                                values = [r.strip() for r in row if r != '']
                                table_data['date'].append(values[0])
                                table_data['1 frame'].append(int(values[1]))
                                table_data['2 frame'].append(int(values[2]))
                                table_data['retr'].append(int(values[3]))
                                table_data['dup_ack'].append(int(values[4]))
                                table_data['lost_seg'].append(int(values[5]))
                                table_data['fast_retr'].append(int(values[6]))
                                table_data['ack_lost_seg'].append(int(values[7]))
                        else:
                                        pass
        if number !=0:
                frames=sum(table_data['2 frame'])
                print ('start-frames_' + str.format("{0:.2f}", frames)+'_end-frames')
                tcp_errors=sum(table_data['retr'])+sum(table_data['dup_ack'])++sum(table_data['fast_retr'])+sum(table_data['ack_lost_seg'])
                print ('start-tcp_errors_' + str(tcp_errors)+'_end-tcp_errors')
                if open_time != 'open_error' and frames != 0:
                        k=tcp_errors
                else:
                        k= 'no data'
        else:
                k= 'no data'
        os.remove("/usr/TEST/TMP_FILES/test_tshark_temp_"+str(os.getpid())+".txt")
        return (k)

###########end table parser###############
###########start tshark part 1###########
resault_temp=subprocess.Popen(['nslookup '+str(args.hostname_page)], bufsize=0, shell=True, stdout = subprocess.PIPE, stderr=subprocess.PIPE)
data=resault_temp.communicate()
ip_adr_temp=re.findall(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', str(re.findall(r'Address: (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', str(data))))
if ip_adr_temp != []:
        pass
else:
        ip_adr_temp = ['1.1.1.1']
ip_adr=''
for z in ip_adr_temp:
        if len(ip_adr_temp)-ip_adr_temp.index(z)==1:
                ip_adr+='ip.addr=='+str(z)+')'
        else:
                ip_adr+='ip.addr=='+str(z)+' or '

ftcp=open('/usr/TEST/TMP_FILES/1tshark_temp'+curent_time+str(pid)+'.txt', 'w')
tcp=subprocess.Popen(['timeout 180 tshark -i bce0 -t ad -qz io,stat,5,"('+str(ip_adr)+' && tcp","COUNT(tcp.analysis.retransmission)('+str(ip_adr)+' && tcp.analysis.retransmission","COUNT(tcp.analysis.duplicate_ack)('\
+str(ip_adr)+' && tcp.analysis.duplicate_ack","COUNT(tcp.analysis.lost_segment)('+str(ip_adr)+' && tcp.analysis.lost_segment","COUNT(tcp.analysis.fast_retransmission)('+str(ip_adr)+\
' && tcp.analysis.fast_retransmission","COUNT(tcp.analysis.lost_segment)('+str(ip_adr)+' && tcp.analysis.ack_lost_segment"']\
, bufsize=0, shell=True, stdout=(ftcp))#stdout = subprocess.PIPE, stderr=subprocess.PIPE)
time.sleep(2)

############start wget ################


fweb=open('/usr/TEST/TMP_FILES/web_temp'+curent_time+str(pid)+'.txt', 'w')
web=subprocess.call(["timeout 120 wget -E -H -p -Q300K --user-agent=Mozilla --no-cache --no-cookies --delete-after --timeout=15 --tries=2 "+args.hostname_page+" 2>&1 | grep '\([0-9.]\+ [KM]B/s\)'"], bufsize=0, shell=True, stdout=(fweb))
fweb.close()
fweb=open('/usr/TEST/TMP_FILES/web_temp'+curent_time+str(pid)+'.txt', 'r')
data=fweb.read()
os.remove('/usr/TEST/TMP_FILES/web_temp'+curent_time+str(pid)+'.txt')
speed_temp=re.findall(r's \((.*?)B/s', str(data))#[KM]B/s', str(data)))
speed_temp_si=re.findall(r's \((.*?) [KM]B/s', str(data))
try:
        if re.findall(r'M', str(speed_temp))==[] and re.findall(r'K', str(speed_temp))==[]:
                speed_="{0:.3f}".format(float(speed_temp_si[0])*0.001*8)
        elif re.findall(r'M', str(speed_temp))!=[]:
                speed_="{0:.3f}".format(float(speed_temp_si[0])*1000*8)
        elif re.findall(r'K', str(speed_temp))!=[]:
                speed_="{0:.3f}".format(float(speed_temp_si[0])*1*8)
except:
        speed_='no_data'
##############stop wget##############
##############start tshark part2#######

os.kill(tcp.pid, signal.SIGINT)
ftcp.close()
time.sleep(0.3)
tcp_error=parser_tshark_output('1', '/usr/TEST/TMP_FILES/1tshark_temp'+curent_time+str(pid)+'.txt')
os.remove('/usr/TEST/TMP_FILES/1tshark_temp'+curent_time+str(pid)+'.txt')
#########resault to DB###########
print ('web_speed_test:'+str(speed_)+' tcp_error:'+str(tcp_error))



Запуск скрипта должен показать следующее (в операционной системе должны быть установлены утилиты tshark, nslookup, wget):
$python3.3 web_open.py -h_page habrahabr.ru
web_speed_test:10960.000 tcp_error:2.0

Далее краткая инструкция как модернизировать данные в Cacti для получения двух графиков с одного RRA:
Cacti
1. Добавляем дополнительную output Fields в Data Input Methods:

2. Добавляем в Data Temlate дополнительную область tcp_error

3. Копируем Graph template и добавляем в него дополнительную информацию, при заведении новых графиков изначально нужно использовать этот Template:

4. Заводим график как показано в предыдущей статье с использование Template выше, график дублируем:

5. в итоге должно получится следующее:

6. Меняем данные в первом графике на правельные. Сначала меняем Template жмем save, затем проверяем что Data Source верный, при необходимости выбираем правильный:

7. Меняем данные для второго графика:



Если все сделано верно, должны получится следующие графики



На этом все, далее по плану при положительных отзывах, в следующих статьях рассмотрим модернизацию данной статистики:
— Добавление TCP и ICMP RTD (round trip delay).
— Вынос измерений на отедельные пробники под управлением головного сервера с системой визуализации и базой даных.
— Возможность тестирования ICMP RTD с любого маршрутизатора сети (Cisco, Juniper, Huawei).
Спасибо за Ваше время.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333768/


Метки:  

Простейший кейлоггер и безопасность в KeePass

Вторник, 25 Июля 2017 г. 22:32 + в цитатник

Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 1065 1064 [1063] 1062 1061 ..
.. 1 Календарь