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

Поиск сообщений в 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 ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

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

[recovery mode] Clonezilla жив

Понедельник, 24 Июля 2017 г. 11:32 + в цитатник
Стивен Шиау — среднестатистический житель Тайваня. Возможно, он живет в пригороде Синьчжу и, возможно, каждый день едва успевает на утренний автобус до института. А еще он — разработчик программы Clonezilla.

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

В марте 2010-ого Джесси Смит проводит с ним интервью. В интервью Стивен Шиау не избегает навязчивых расспросов Джесси об Clonezilla. Когда Джесси просит его объясниться, он знакомит ее с историей создания Clonezilla.

Утилита была разработана Стивеном Шиау в лаборатории свободного программного обеспечения в «Национальном центре высокопроизводительных вычислений» Тайваня.

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

Скриншоты


Интерфейс Clonezilla live мало в чем похож на бурные графические сцены лесбийского секса. Эта программа имеет расслабляющий и позитивный интерфейс. В современном Clonezilla Live есть возможность вызвать небольшое множество подпрограмм: тест ОЗУ Memtest, командный интерпретатор FreeDOS (для машин конца 1980-х) и загрузчик iPXE.


На мягкие, светлые цвета фона загрузочного меню Clonezilla Live можно смотреть с вниманием, или же игнорировать, в зависимости от выбора пользователя

В мире Linux для работы с жесткими дисками есть инструменты, имеющие интерфейс, похожий на интерфейс командной оболочки UNIX/Linux. На их фоне с Clonezilla Live не нужно столько терпения и внимания.


В нем присутствует четкое, прорывное исполнение

Если подруги обращают ваше внимание, что Clonezilla явно вызывает вашу симпатию, вероятно, dd-wrt вам тоже нравится. На следующем скриншоте встречайте веб-интерфейс этой прошивки.


Встретив веб-интерфейс dd-wrt, пользователь пребывает в растерянности

Четкий и жизненный план


Следующая часть статьи рассказывает о том, как сделать samba-сервер из роутера с dd-wrt и портом usb и с помощью загрузочной флешки Clonezilla live сохранить на нем образ раздела жесткого диска, а потом восстановить его из этого образа.

Обратите внимание: создать samba-сервер из роутера с портом usb позволяет и его официальная прошивка; хоть dd-wrt и добрая прошивка, переходить на нее в этой ситуации повода нет.

Как установить Clonezilla live на флеш-накопитель usb


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

Следующий абзац основан на переводе части официального веб-сайта Clonezilla.

Способы сделать это очень разные. Например, так: загрузив zip-файл Clonezilla live, распаковав его содержимое на NTFS- или FAT- раздел флеш-накопителя, имеющий объем не менее 200 Мб, найдя на нем в каталоге utils/linux скрипт makeboot.sh, запустив этот скрипт с правами суперпользователя и после этого следуя выводимым на экран инструкциям.

Здравствуй, dd-wrt


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


С головой уйдем в настройку dd-wrt

С этого момента — перевод из dd-wrt wiki.

Чтобы включить USB, идите в Services > USB и включите «Core USB Support»: это приведет к открытию новых параметров. После этого включите «USB Storage Support», «Automatic Drive Mount» и нажмите кнопку Save.

Подключите ваш флеш-накопитель. Ждите, пока он появится в пространстве Disk info. Обратите внимание на путь монтирования (скорее всего /tmp/mnt/sda1).

Чтобы открыть сетевой доступ в вашему флеш-накопителю из сети Windows, идите в Services > NAS, включите «Samba» и введите имя вашей рабочей группы Windows. Под «File Sharing > Shares» нажмите кнопку Add Share, выберите «Path» (скорее всего /mnt/sda1) и дайте вашему флеш-накопителю имя. Под «File Sharing > Users» нажмите кнопку Add User, введите «User Name», «Password» и выберите имя устройства, которое вы дали ему ранее. Нажмите кнопку Apply Settings.

Конец перевода из dd-wrt wiki.

Наконец, запустим Clonezilla live и сохраним образ на samba-сервере. Проходит несколько минут.

Чтобы отвлечься, перейду к PXE

PXE


Clonezilla live можно загрузить не только с помощью загрузочной флешки, но и с помощью загрузочного сервера по сети — об этом написано на Хабре в статье «Загрузочный сервер — как загрузочная флешка, только сервер и по сети».

Представьте, — написано в статье, — что вы выбрали в BIOS загрузку по сети и можете (идет перечисление того, что можно сделать) с помошью PXE Boot сервера — «ведь это куда удобнее, нежели бегать с флешкой от машины к машине». В комментарии к Trinity Rescue Kit CD упоминается о клонировании компьютера по сети на несколько компьютеров одновременно — по-видимому, с помощью clonezilla.

В статье сервер устанавливается и настраивается по пунктам. Вначале его загрузочное меню содержит один пункт Boot from first HDD. После того, как основа готова, добавляется возможность загружать различные дисковые утилиты и тест памяти, в том числе clonezilla live: идет новый конфиг главного меню сервера и «несколько слов» о них.

Если все сделано правильно, то при загрузке какой-либо BIOS-машины с этого DHCP/PXE/TFTP сервера мы увидим, — написано в статье ServerClub'а, — загрузочное меню. Однако мы не увидим его при загрузке какой-либо UEFI-машины. В статье об этом ничего нет.

Про загрузку UEFI-машин написано в комментариях к статье.

Заключение


Раздел, данные с которого были сохранены в образе на samba-сервере, успешно отформатирован… Окончательное осознание потери приходит и с этого момента начинаем восстанавливать данные. В итоге «самый теплый» роутер загружает с подключенного к нему флеш-накопителя usb образ на компьютер, а программа Clonezilla live восстанавливает с его помощью систему.

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

https://habrahabr.ru/post/312116/


Метки:  

Еще один breakpad сервер. Часть 1

Понедельник, 24 Июля 2017 г. 11:12 + в цитатник


В прошлом квартале делали MVP сервиса по обработке крешей. Аналог Socorro от Mozilla, но с учетом своих требований. Код сервиса будет выкладываться на GitHub по мере рефакторинга. Утилиты, о которых пойдет речь в этой статье, доступны тут.


У нас были следующие требования:


  • получение отчета с Windows, Mac OS X, GNU/Linux;
  • получение отчета о падения с веба(собираем через emscripten);
  • сбор данных об оборудовании(CPU, GPU, Memory);
  • группировка падений по версии, платформе, пользователю, причине;
  • приложение ведет логи, нужно вместе с отчетом хранить и лог.

Содержание:


  • Breakpad: файлы символов и отчеты о падениях;
  • Emscripten: параметры компиляции, файлы символов, обработка ошибок;
  • UI.

Breakpad


В составе breakpad есть утилита извлекающая файлы символов из elf/pdb. Вот описание формата файла. Это текстовый файл, но нас интересует первая строка имеет формат MODULE operatingsystem architecture id name, у нас она выглядит так:


MODULE windows x86 9E8FC13F1B3F448B89FF7C940AC054A21 IQ Option.pdb
MODULE Linux x86_64 4FC3EB040E16C7C75481BC5AA03EC8F50 IQOption
MODULE mac x86_64 B25BF49C9270383E8DE34560730689030 IQOption

Далее эти файлы следует расположить в особом порядке: base_dir/name/id/name.sym, выглядит это так:


base_dir/IQ Option/9E8FC13F1B3F448B89FF7C940AC054A21/IQ Option.sym
base_dir/IQOption/4FC3EB040E16C7C75481BC5AA03EC8F50/IQOption.sym
base_dir/IQOption/B25BF49C9270383E8DE34560730689030/IQOption.sym

Для получения отчета о падения можно воспользоваться утилитой minidump_stackwalk из поставки breakpad:


$ minidump_stackwalk path_to_crash base_dir

Данная утилита может выводить как в человеко читаемым виде так и в machine-readable формате.


Но это не очень удобно. В Mozilla Socorro входит утилита stackwalker которая выдает json(пример на crash-stats.mozilla.com)


Emscripten


Ловить падения можно через глобальный обработчик window.onerror. В зависимости от браузера, сообщения будут отличаться:


Uncaught abort() at Error
    at jsStackTrace (http://localhost/traderoom/glengine.js?v=1485951440.84:1258:13)
    at Object.abort (http://localhost/traderoom/glengine.js?v=1485951440.84:776417:44)
    at _abort (http://localhost/traderoom/glengine.js?v=1485951440.84:9914:22)
    at _free (http://localhost/traderoom/glengine.js?v=1485951440.84:232487:38)
    at __ZN2F28ViewMain13setFullscreenEb (http://localhost/traderoom/glengine.js?v=1485951440.84:533436:2)
    at Array.__ZNSt3__210__function6__funcIZN2F28ViewMainC1EvE4__13NS_9allocatorIS4_EEFbPNS2_9UIElementEEEclEOS8_ (http://localhost/traderoom/glengine.js?v=1485951440.84:658644:2)
    at __ZNKSt3__28functionIFllEEclEl (http://localhost/traderoom/glengine.js?v=1485951440.84:673406:75)
    at __ZNK2F26detail23multicast_function_baseIFbPNS_9UIElementEENS_24multicast_result_reducerIFbRKNSt3__26vectorIbNS6_9allocatorIbEEEEEXadL_ZNS_10atLeastOneESC_EEEEiLin1EEclERKS3_ (http://localhost/traderoom/glengine.js?v=1485951440.84:476310:12)
    at __ZN2F29UIElement14processTouchUpERKNS_6vec2_tIfEE (http://localhost/traderoom/glengine.js?v=1485951440.84:471241:9)
If this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.

uncaught exception: abort() at jsStackTrace@http://localhost/traderoom/glengine.js?v=1485951440.84:1258:13
stackTrace@http://localhost/traderoom/glengine.js?v=1485951440.84:1275:12
abort@http://localhost/traderoom/glengine.js?v=1485951440.84:776417:44
_abort@http://localhost/traderoom/glengine.js?v=1485951440.84:9914:7
_free@http://localhost/traderoom/glengine.js?v=1485951440.84:232487:38
__ZN2F28ViewMain13setFullscreenEb@http://localhost/traderoom/glengine.js?v=1485951440.84:533436:2
__ZNSt3__210__function6__funcIZN2F28ViewMainC1EvE4__13NS_9allocatorIS4_EEFbPNS2_9UIElementEEEclEOS8_@http://localhost/traderoom/glengine.js?v=1485951440.84:658644:2
__ZNKSt3__28functionIFllEEclEl@http://localhost/traderoom/glengine.js?v=1485951440.84:673406:9
__ZNK2F26detail23multicast_function_baseIFbPNS_9UIElementEENS_24multicast_result_reducerIFbRKNSt3__26vectorIbNS6_9allocatorIbEEEEEXadL_ZNS_10atLeastOneESC_EEEEiLin1EEclERKS3_@http://localhost/traderoom/glengine.js?v=1485951440.84:476310:12
__ZN2F29UIElement14processTouchUpERKNS_6vec2_tIfEE@http://localhost/traderoom/glengine.js?v=1485951440.84:471241:9
__ZN2F29UIElement17processTouchEventERNSt3__26vectorINS1_4pairIPS0_NS_6vec2_tIfEEEENS1_9allocatorIS7_EEEEjNS_15UI_TOUCH_ACTIONE@http://localhost/traderoom/glengine.js?v=1485951440.84:468018:35
__ZN2F29UIElement5touchEffNS_15UI_TOUCH_ACTIONEj@http://localhost/traderoom/glengine.js?v=1485951440.84:598797:8
__ZN2F213MVApplication5touchEffNS_15UI_TOUCH_ACTIONEj@http://localhost/traderoom/    at stackTrace (http://localhost/traderoom/glengine.js?v=1485951440.84:1275:12)
glengine.js?v=1485951440.84:360629:11
__ZN2F27UIInput7processEj@http://localhost/traderoom/glengine.js?v=1485951440.84:273450:6
__Z14on_mouse_eventiPK20EmscriptenMouseEventPv@http://localhost/traderoom/glengine.js?v=1485951440.84:446769:5
dynCall_iiii@http://localhost/traderoom/glengine.js?v=1485951440.84:767912:9
dynCall@http://localhost/traderoom/glengine.js?v=1485951440.84:501:14
handlerFunc@http://localhost/traderoom/glengine.js?v=1485951440.84:2526:30
jsEventHandler@http://localhost/traderoom/glengine.js?v=1485951440.84:2429:11

If this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.

Такое сообщение создаются если при компиляции использовать ключ -g. На нашем проекте размер выходного asm.js кода раза в 3 больше. Поэтому у нас используется --emit-symbol-map.
На выходе получаем файл с символами в простом формате key:value:


$cc:__ZNSt3__210__function6__funcIZN2F28ViewMain17animateLeftPannelEbE4__36NS_9allocatorIS4_EEFvvEEclEv
f8d:__ZNKSt3__210__function6__funcIZN2F218MVMessageQueueImpl4sendINS2_26EventSocialProfileReceivedEJiEEEvDpRKT0_EUlvE_NS_9allocatorISA_EEFvvEE7__cloneEPNS0_6__baseISD_EE
Z1:__ZN2F211recognizers24UIPinchGestureRecognizer6updateEPNS_9UIElementERKNS_6vec2_tIfEEj

а сообщения теперь имеют вид:


Uncaught abort() at Error
    at jsStackTrace (http://10.10.1.247:8080/main.js:1:17947)
    at stackTrace (http://10.10.1.247:8080/main.js:1:18118)
    at Object.abort (http://10.10.1.247:8080/main.js:12:6480)
    at _abort (http://10.10.1.247:8080/main.js:1:37453)
    at Eb (http://10.10.1.247:8080/main.js:5:22979)
    at Xc (http://10.10.1.247:8080/main.js:5:53767)
    at rc (http://10.10.1.247:8080/main.js:5:47782)
    at Array.$c (http://10.10.1.247:8080/main.js:5:54228)
    at Pc (http://10.10.1.247:8080/main.js:5:52663)
    at Array.Wb (http://10.10.1.247:8080/main.js:5:40899)
If this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.

Для получения получения стека вызовов была написана вспомогательная утилита:


webstackwalker
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include writer.h>
#include stringbuffer.h>

namespace
{

struct Deleter
{
    void operator()(char *data) const
    {
        free((void *) data);
    }
};

using CharPtr = std::unique_ptr;
}

std::string demangle(const std::string &mangledName)
{
    int status = 0;

    int shift = 0;
    if (mangledName[1] == '_')
    {
        shift = 1;
    }

    CharPtr realname(abi::__cxa_demangle(mangledName.data() + shift, 0, 0, &status));

    if (status == 0)
    {
        return std::string(realname.get());
    } else
    {
        if (mangledName[0] == '_')
        {
            const auto str = mangledName.substr(1, mangledName.size() - 1);
            int status = 0;
            CharPtr realname(abi::__cxa_demangle(str.data(), 0, 0, &status));
            if (status == 0)
            {
                return std::string(realname.get());
            }

            return mangledName;
        }

        return mangledName;
    }
}

void printUsage()
{
    std::cout << "webstackwalker crash_dump symbol_file" << std::endl;
}

std::map SYMBOL_MAP;

void readSymbols(const std::string &path);

void flushUnParseLine(const std::string &line);

int main(int argc, char **argv)
{
    if (argc < 2)
    {
        printUsage();
        return 1;
    }

    readSymbols(std::string(argv[2]));

    const std::string inputFile(argv[1]);
    std::ifstream input(inputFile);
    const std::regex re("^(?:\\s{4}at\\s){0,1}(?:Array\\.){0,1}([\\w\\d\\$]+)(?: \\(|@).+\\){0,1}");

    rapidjson::StringBuffer buffer;
    rapidjson::Writer writer(buffer);
    writer.StartArray();

    const std::set skip = {"jsStackTrace", "stackTrace", "abort"};

    while (!input.eof())
    {
        std::smatch match;
        std::string line;
        std::getline(input, line);

        if (std::regex_search(line, match, re))
        {
            if (skip.count(match[1]))
            {
                continue;
            }

            auto iter = SYMBOL_MAP.find(match[1]);
            std::string function;
            if (iter != SYMBOL_MAP.cend())
            {
                function = demangle(iter->second);
            } else
            {
                function = demangle(match[1]);
            }

            writer.String(function.c_str());
        }
    }
    writer.EndArray();

    std::cout << buffer.GetString() << std::endl;

    return 0;
}

void readSymbols(const std::string &path)
{
    std::ifstream input(path);

    if (!input.is_open())
    {
        std::cerr << "Can't open symbols file: " << path << std::endl;
        exit(2);
    }

    const std::regex re("^([\\d\\w$]+):([\\d\\w]+)$");

    while (!input.eof())
    {
        std::smatch match;
        std::string line;
        std::getline(input, line);
        if (std::regex_search(line, match, re))
        {
            SYMBOL_MAP[match[1]] = match[2];
        }
    }
}

Утилита использует demangle, для преобразования:


_ZN2F211recognizers24UIPinchGestureRecognizer6updateEPNS_9UIElementERKNS_6vec2_tIfEEj

в


F2::recognizers::UIPinchGestureRecognizer::update(F2::UIElement*, F2::vec2_t const&, unsigned int)

UI


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


  • дашборды с автоматическим обновлением;
  • визуализации:
    • грифики и диаграммы;
    • таблицы.

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


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

Примененные фильтры можно перенести на вкладку discover, где можно посмотреть подробности падения. Как оказалось кибана имеет модульную структуру, что позволяет расширять её возможности. Был написан простой плагин, добавляющий рендер отчета, что намного удобней стандартного Table и JSon.




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

https://habrahabr.ru/post/333448/


Метки:  

[Перевод] Куда уйти из IT: 3 сферы, которые нуждаются в технических специалистах

Понедельник, 24 Июля 2017 г. 10:56 + в цитатник
Современный рынок направлен на технологические компании и стартапы. Поэтому легко забыть, что существует множество рабочих мест в инновационных областях в других сферах. Почти везде возможно найти применение своему таланту. Если ищите место под солнцем, нужно просто выйти за привычные рамки и рассмотреть другие отрасли, на которые вы обычно не обращаете внимание.





Специалист по маркетингу из нью-йоркской рекрутинговой фирмы «The Hired Guns» Марк Нэйшн так прокомментировал проблему: «Существует много причин, по которым профессионал технического профиля может захотеть покинуть привычную среду обитания. Стартапы – это достаточно рискованно, однако в других отраслях вам могут предложить не только стабильную работу – возможно, именно там вы сможете реализоваться и – кто знает? – повлиять на будущее целого мира».

Рассмотрим 3 варианта возможного карьерного пути:

Сфера #1: Финансы





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

Java-разработчик

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

Что нужно для работы Java-разработчиком

  1. Специальность в области информатики или в аналогичной сфере
  2. Опыт работы с программами Hibernate или Spring
  3. Знание SQL, CSS или HTML5
  4. И бонусом будет опыт работы с клиентами и в команде.


Разработчик мобильных приложений

Если умеете создавать приложения для Android или iOS, то расслабьтесь — у вас всё будет хорошо :D Большинство крупных финансовых компаний работают над улучшением программного обеспечения в сфере мобильных технологий, а остальные стремятся наверстать упущенное и ухватить свой кусок пирога. Поэтому разработчики приложений в этой сфере пользуются большим спросом. Весомый плюс — тут не нужна научная степень в области компьютерных технологий – просто докажите, что вы в состоянии создать отличную программу для смартфона – и вуаля, цены вам нет.

Что нужно для работы IOS/Android-разработчиком

  1. Портфолио опубликованных приложений в магазине Google Play или магазине приложений Apple, который вы либо создали, либо дополнили
  2. Рабочие знания языков программирования на базе Android или iOS
  3. Бонусные баллы: опыт работы в рамках разработки Agile


Специалист по информационной безопасности

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

Что нужно для работы специалистом по ИБ

  1. Опыт разработки и управления стратегиями в сфере кибербезопасности
  2. Знания в области информационной безопасности, особенно в финансовой сфере
  3. Умение работать со скриптами (Python, Ruby, Perl и т. д.)
  4. Опыт работы от 5 до 7 лет в области IT-безопасности
  5. Умение работать с методами выявления рисков и моделирования потенциальных киберугроз
  6. Бонусные баллы: навыки презентации и общения с клиентами


Сфера #2: Здравоохранение





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

Системный администратор

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

Что нужно для работы системным администратором

  1. Опыт установки и настройки ПО и прокси-серверов
  2. Опыт работы в смешанной операционной среде, например, в вариантах UNIX и Windows
  3. Знания в области сетевого администрирования
  4. Степень бакалавра в области информатики или информационных технологий
  5. Бонусные баллы: опыт работы и умение помогать технически неграмотным коллегам

Специалист по анализу данных

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

Что нужно для работы специалистом по анализу данных

  1. Отличное понимание статистического анализа и опыт работы в этой сфере
  2. Опыт работы с приложениями машинного обучения
  3. Знание базы данных, работающей на платформах SQL или Hive
  4. Знание инструментов анализа данных, таких как SAS
  5. Отличные навыки работы с Excel
  6. Бонусные баллы: способность писать профессиональные отчеты и документы для сотрудников


Сфера #3: Образование





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

UX–дизайнер

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

Что нужно для работы UX-дизайнером

1. Опыт проектирования и опыт в сфере взаимодействия с пользователями
2. Опыт работы с мобильным дизайном
3. Умение воплощать бизнес-цели в программном обеспечении
4. Навыки в сфере письменной и визуальной коммуникации
5. Бонусные очки: навык работы в сфере графического дизайна

Менеджер по продукции

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

Что нужно для работы менеджера по продукции

  1. Опыт работы менеджером по продукции или внутренним предпринимателем в компании
  2. Возможность выделять и анализировать потребности бизнес-структуры и клиентов, а затем переводить их в план-график проекта разработки программного обеспечения
  3. Навыки работы с Agile
  4. Бонусные баллы: умение находить общий язык с сотрудниками и клиентами и способность работать в нескольких командах


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

Перевод выполнен с любовью, оригинал смотрите тут: goo.gl/JxDMcY
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333964/


Метки:  

«Познай самого себя»: social media mining-проекты в Университете ИТМО

Понедельник, 24 Июля 2017 г. 10:11 + в цитатник
Социальные сети — не только таймкиллер и источник новостей, но и поле для разнообразных исследований. О том, что ученые и студенты Университета ИТМО научились узнавать по нашим постам в Facebook и Instagram, расскажем ниже.

/ Фотография perzon seo CC-BY

«Что хочет покупатель»: профилирование в соцсетях


Этим проектом занималась группа магистрантов кафедры Компьютерных технологий Университета ИТМО во время стажировки в Национальном университете Сингапура. Задача проекта — создать систему, которая помогала бы компаниям лучше разбираться в потребностях их аудитории — с учетом того, что эта аудитория рассказывает о себе в социальных сетях.

Пример: компания хочет разобраться в том, что объединяет людей, довольных (или, наоборот, недовольных) ее продуктом. Разработка студентов Университета ИТМО позволяет сформировать портрет такого [довольного/недовольного] покупателя по данным из социальных сетей, и предложить подходящее решение: кого-то может заинтересовать скидка, а кому-то понадобится предложить другой продукт.

Как это работает: алгоритм, предложенный командой Университета ИТМО, анализирует открытые данные, которые оставляет пользователь социальных сетей: метки геолокации, общедоступные сообщения, фотографии и подписи к ним. Эти данные преобразуются в набор параметров (средний размер твита, наиболее частые объекты на фото, распределение чекинов и т.д.), который далее передается нейронной сети.

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

О чем говорит Twitter Дональда Трампа


Более ранняя разработка магистрантов Университета ИТМО, работавших над проектом профилирования потребителей, — система, угадывающая семейное положение человека по данным из Twitter, Instagram и Foursquare. По данным исследователей, комбинация из трех соцсетей обеспечивает точность предсказания до 86%, в то время как по информации только из одной соцести алгоритм угадывает семейное положение с точностью на 17% ниже.

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

Кстати, по итогам данного исследования программисты Университета ИТМО выступили с докладом на конференции AAAI по искусственному интеллекту (AAAI Conference on Artificial Intelligence, AAAI-2017), которая объединяет ученых, занимающихся вопросами создания и обучения ИИ.




Эмоции и безопасность: как почувствовать настроение толпы


Еще один пример исследования, в основе которого лежат данные соцсетей, — система анализа эмоций, разработка сотрудников НИИ наукоемких компьютерных технологий (НИИ НКТ) Университета ИТМО.

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

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

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

Другой пример использования алгоритма — возможность распознать очаги напряженности на футбольных матчах (о том, какие еще разработки Университета ИТМО были использованы при подготовке к Кубку конфедераций и предстоящему ЧМ-2018, мы рассказывали здесь).

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

За экстремальные ситуации, помимо драк, также считались использование пиротехники, бросание предметов на трибуны и поле стадиона, демонстрация оскорбительных баннеров, скандирование нетолерантных кричалок и другое. Мы рассматривали матчи [ФК «Зенит»] в период с 2013 по 2015 годы. Получилось около десяти игр, после чего мы брали и другие команды.

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

– Василий Бойчук, инженер НИИ НКТ




Социальные сквозняки и распространение информации


Другая разработка НИИ НКТ, использующая данные соцсетей, — система поиска «социальных сквозняков» и оценки общественного мнения. Этот проект позволяет в соответствии с заданной стратегией проанализировать общедоступные материалы пользователей «Вконтакте», Twitter, Instagram, Live Journal, определить наиболее важные содержательные элементы, тему и эмоциональный настрой сообщения и разметить пост в соответствии с заданными характеристиками, включая количество лайков, репостов, цитирований, комментариев и т.д.

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

Панчи, скетчи, вайны


Социальные сети могут не только рассказать о точках напряженности в обществе и существующих проблемах. Не менее часто пользователи делятся со своими друзьями тем, что вызывает у них вдохновение, интерес или просто улыбку. Поэтому для посетителей фестивалей VK Fest и Geek Picnic Университет ИТМО часто готовит демонстрацию своих разработок в неклассическом — развлекательном формате.

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


Ричард Докинз. Фотография Университета ИТМО

А для фестиваля Geek Picnic-2017 Университет ИТМО подготовил еще один пример анализа соцсетей — мемокуб с самыми узнаваемыми мемами: от «Wat» до всем известного кадра из «Великого Гэтсби». Рядом с ним состоялась автограф-сессия хедлайнера фестиваля, эволюционного биолога и популяризатора науки Ричарда Докинза.

Кстати, на фестиваль Geek Picnic Университет ИТМО привез не только мемокуб, но и многие свои разработки — от системы работы умного дома до функциональной еды. О том, чем еще запомнилась посетителям Geek Picnic интерактивная зона Университета — читайте здесь.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333962/


Метки:  

[Перевод] Полезные команды и советы при работе с Kubernetes через консольную утилиту kubectl

Понедельник, 24 Июля 2017 г. 09:23 + в цитатник
Предисловие переводчика: Эта статья — комбинация из перевода двух материалов от проекта CoreOS (см. ссылки в конце публикации), посвящённых работе с консольным инструментом для выполнения команд на кластерах Kubernetes — kubectl. Листинг, приведённый автором оригинала для Mac OS X, был адаптирован под Linux, в других листингах было исправлено форматирование YAML, а для удобства чтения всего материала в него были добавлены подзаголовки.



Kubectl — инструмент, который знаком пользователям Kubernetes и обладает широкими функциональными возможностями. Овладение ими занимает время, но позволяет увидеть, что это более мощный инструмент, чем многие предполагали. Представляю набор советов, позволяющих улучшить ваши возможности при работе с kubectl. Не забудьте также посмотреть на cheat sheet в секции официальной документации Kubernetes!

Автоматическое дополнение в shell


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


# Подключить код автодополнения для текущего сеанса в Bash
source <(kubectl completion bash)
# … или добавить код автодополнения в файл и подключить его к .bashrc
mkdir ~/.kube
kubectl completion bash > ~/.kube/completion.bash.inc
printf "\n# Kubectl shell completion\nsource '$HOME/.kube/completion.bash.inc'\n" >> $HOME/.bashrc
source $HOME/.bashrc
# Альтернатива — подключить код автодополнения для текущего сеанса в Zsh
source <(kubectl completion zsh)

Слияние конфигов с контекстами через KUBECONFIG


Слияние конфигураций Kubernetes — популярный паттерн, если вы взаимодействуете со множеством кластеров Kubernetes. При работе с разными конфигами используется концепция контекста (context), указывающего на параметры, которые kubectl будет использовать для поиска конкретного, целевого кластера. Но добиться нужного результата с контекстами бывает сложно. Чтобы упростить себе жизнь, воспользуйтесь переменной окружения KUBECONFIG — она позволяет указать на конфигурационные файлы, которые используются при слиянии. Подробнее о KUBECONFIG можно прочитать в официальной документации.

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

Конфиг первого кластера:
$ kubectl config view --minify > cluster1-config

apiVersion: v1
clusters:
- cluster:
    certificate-authority: cluster1_ca.crt
    server: https://cluster1
  name: cluster1
contexts:
- context:
    cluster: cluster1
    user: cluster1
  name: cluster1
current-context: cluster1
kind: Config
preferences: {}
users:
- name: cluster1
  user:
    client-certificate: cluster1_apiserver.crt
    client-key: cluster1_apiserver.key

Конфиг второго кластера:
$ cat cluster2-config

apiVersion: v1
clusters:
- cluster:
    certificate-authority: cluster2_ca.crt
    server: https://cluster2
  name: cluster2
contexts:
- context:
    cluster: cluster2
    user: cluster2
  name: cluster2
current-context: cluster2
kind: Config
preferences: {}
users:
- name: cluster2
  user:
    client-certificate: cluster2_apiserver.crt
    client-key: cluster2_apiserver.key

Их слияние можно выполнить с помощью KUBECONFIG. Преимуществом такого слияния станет возможность динамически переключаться между контекстами. Контекст — это «сопоставление» (map), включающее в себя описания кластера и пользователя, а также название, с помощью которого на конфигурацию можно ссылаться для аутентификации кластера и взаимодействия с ним. Флаг --kubeconfig позволяет посмотреть на контекст для каждого файла:
$ kubectl --kubeconfig=cluster1-config config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* cluster1 cluster1 cluster1
$ kubectl --kubeconfig=cluster2-config config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* cluster2 cluster2 cluster2

У каждого конфигурационного файла есть единственный контекст, так что они не конфликтуют между собой. Слияние двух файлов через KUBECONFIG показывает оба контекста. Для сохранения текущего контекста создайте новый пустой файл с названием cluster-merge:
$ export KUBECONFIG=cluster-merge:cluster-config:cluster2-config
dcooley@lynx ~
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* cluster1 cluster1 cluster1
cluster2 cluster2 cluster2

Список файлов, экспортируемых с KUBECONFIG, загружается в строгом порядке. Поэтому контекст, который выбирается, соответствует указанному как current-context в первом конфиге. Изменение контекста на cluster2 смещает знак текущего (*) к этому контексту в списке, и команды kubectl начинают применяться к этому (второму) контексту:
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* cluster1 cluster1 cluster1
cluster2 cluster2 cluster2
$ kubectl config use-context cluster2
Switched to context "cluster2".
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
cluster1 cluster1 cluster1
* cluster2 cluster2 cluster2
$ cat cluster-merge

apiVersion: v1
clusters: []
contexts: []
current-context: cluster2
kind: Config
preferences: {}
users: []

Остаётся только поддерживать правильное значение current-context. Использовать контексты Kubernetes и осуществлять их слияние можно разными способами. Например, вы можете создать контекст (cluster1_kube-system), который будет определять пространство имён (kube-system) для всех исполняемых команд kubectl:
$ kubectl config set-context cluster1_kube-system --cluster=cluster1 --namespace=kube-system --user=cluster1
Context "cluster1_kube-system" set.
$ cat cluster-merge

apiVersion: v1
clusters: []
contexts:
- context:
    cluster: cluster1
    namespace: kube-system
    user: cluster1
  name: cluster1_kube-system
current-context: cluster2
kind: Config
preferences: {}
users: []

Новый контекст можно использовать так:
$ kubectl config use-context cluster1_kube-system
Switched to context "cluster1_kube-system".
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
default-http-backend-fwx3g 1/1 Running 0 28m
kube-addon-manager-cluster 1/1 Running 0 28m
kube-dns-268032401-snq3h 3/3 Running 0 28m
kubernetes-dashboard-b0thj 1/1 Running 0 28m
nginx-ingress-controller-b15xz 1/1 Running 0 28m

Изучение Kubernetes API


Чтобы узнать больше о возможностях, предоставляемых Kubernetes API, запросите файл swagger.json:
$ kubectl proxy
$ curl -O 127.0.0.1:8001/swagger.json

Можно также зайти на http://localhost:8001/api/ и посмотреть на имеющиеся в Kubernetes API пути.

Поскольку swagger.json — это документ в формате JSON, можно его просмотреть с помощью jq. Утилита jq — лёгкий обработчик JSON-файлов, позволяющий выполнять сравнения и другие операции. Подробнее читайте здесь.

Просмотр swagger.json поможет понять Kubernetes API. Это сложный API, функции в котором разбиты на группы, что затрудняет его восприятие:
$ cat swagger.json | jq '.paths | keys[]'
"/api/"
"/api/v1/"
"/api/v1/configmaps"
"/api/v1/endpoints"
"/api/v1/events"
"/api/v1/namespaces"
"/api/v1/nodes"
"/api/v1/persistentvolumeclaims"
"/api/v1/persistentvolumes"
"/api/v1/pods"
"/api/v1/podtemplates"
"/api/v1/replicationcontrollers"
"/api/v1/resourcequotas"
"/api/v1/secrets"
"/api/v1/serviceaccounts"
"/api/v1/services"
"/apis/"
"/apis/apps/"
"/apis/apps/v1beta1/"
"/apis/apps/v1beta1/statefulsets"
"/apis/autoscaling/"
"/apis/batch/"
"/apis/certificates.k8s.io/"
"/apis/extensions/"
"/apis/extensions/v1beta1/"
"/apis/extensions/v1beta1/daemonsets"
"/apis/extensions/v1beta1/deployments"
"/apis/extensions/v1beta1/horizontalpodautoscalers"
"/apis/extensions/v1beta1/ingresses"
"/apis/extensions/v1beta1/jobs"
"/apis/extensions/v1beta1/networkpolicies"
"/apis/extensions/v1beta1/replicasets"
"/apis/extensions/v1beta1/thirdpartyresources"
"/apis/policy/"
"/apis/policy/v1beta1/poddisruptionbudgets"
"/apis/rbac.authorization.k8s.io/"
"/apis/storage.k8s.io/"
"/logs/"
"/version/"

А вот следующая команда описывает API, доступные в кластере Kubernetes и к которым у вас есть доступ. Команда в примере ниже выполнена под пользователем-администратором. Если у вас включён контроль доступа по RBAC, вывод может отличаться:
$ kubectl api-versions
apps/v1beta1
authentication.k8s.io/v1beta1
authorization.k8s.io/v1beta1
autoscaling/v1
batch/v1
batch/v2alpha1
certificates.k8s.io/v1alpha1
coreos.com/v1
etcd.coreos.com/v1beta1
extensions/v1beta1
oidc.coreos.com/v1
policy/v1beta1
rbac.authorization.k8s.io/v1alpha1
storage.k8s.io/v1beta1
v1

Команда kubectl explain помогает лучше понять, что делают разные компоненты API:
$ kubectl explain
You must specify the type of resource to explain. Valid resource types include:
* all
* certificatesigningrequests (aka 'csr')
* clusters (valid only for federation apiservers)
* clusterrolebindings
* clusterroles
* componentstatuses (aka 'cs')
* configmaps (aka 'cm')
* daemonsets (aka 'ds')
* deployments (aka 'deploy')
* endpoints (aka 'ep')
* events (aka 'ev')
* horizontalpodautoscalers (aka 'hpa')
* ingresses (aka 'ing')
* jobs
* limitranges (aka 'limits')
* namespaces (aka 'ns')
* networkpolicies
* nodes (aka 'no')
* persistentvolumeclaims (aka 'pvc')
* persistentvolumes (aka 'pv')
* pods (aka 'po')
* poddisruptionbudgets (aka 'pdb')
* podsecuritypolicies (aka 'psp')
* podtemplates
* replicasets (aka 'rs')
* replicationcontrollers (aka 'rc')
* resourcequotas (aka 'quota')
* rolebindings
* roles
* secrets
* serviceaccounts (aka 'sa')
* services (aka 'svc')
* statefulsets
* storageclasses
* thirdpartyresources
error: Required resource not specified.
See 'kubectl explain -h' for help and examples.

Попробуйте выполнить kubectl explain deploy. Команда explain работает с разными уровнями вложенности, что позволяет вам также ссылаться на зависимые объекты:
$ kubectl explain deploy.spec.template.spec.containers.livenessProbe.exec
RESOURCE: exec 
DESCRIPTION:
One and only one of the following should be specified. Exec specifies the
action to take.
ExecAction describes a "run in container" action.
FIELDS:
command <[]string>
Command is the command line to execute inside the container, the working
directory for the command is root ('/') in the container's filesystem. The
command is simply exec'd, it is not run inside a shell, so traditional shell
instructions ('|', etc) won't work. To use a shell, you need to explicitly
call out to that shell. Exit status of 0 is treated as live/healthy and
non-zero is unhealthy.

Операции с подами через kubectl


Все последующие примеры используют Kubernetes API, чтобы узнать что-либо о подах. Одним из способов получения нужных данных — построить запрос и понять, какое его выражение потребуется в терминах jsonpath. Например, можно выполнить kubectl get pods --all-namespaces -o json, чтобы увидеть весь вывод, из которого мы можем потом отфильтровать нужные данные для примера с сортировкой подов по времени (см. ниже).

Если у вас нет запущенного приложения, для знакомства с примерами можно создать поды с лейблом run=shop и запустить их как сервис на порту 80:
$ kubectl run shop --replicas=2 --image quay.io/coreos/example-app:v1.0 --port 80 --expose

Теперь можно посмотреть, что мы будем делать с jsonpath. Более подробную информацию по нему можно получить из официальной документации.

Фильтрация подов Kubernetes по времени их создания


$ kubectl get pods --all-namespaces --sort-by='.metadata.creationTimestamp' -o jsonpath='{range .items[]}{.metadata.name}, {.metadata.creationTimestamp}{"\n"}{end}'


Поиск пода Kubernetes по селектору лейбла и просмотр его логов


Укажите пространство имён (your-namespace) и свой запрос на наличие лейбла, который поможет найти нужные поды, и получите логи этих подов. Если под не единственный, логи будут получены из всех подов параллельно:
$ ns='' label='=' kubectl get pods -n $ns -l $label -o jsonpath='{range .items[]}{.metadata.name}{"\n"}{end}' | xargs -I {} kubectl -n $ns logs {}


Поиск пода Kubernetes по селектору лейбла и подключение к нему


Укажите пространство имён (your-namespace) и свой запрос на наличие лейбла, который поможет найти нужные поды, и подключитесь к нему по имени (к первому из найденных подов). Замените 8080 на нужный порт пода:
$ ns='' label='=' kubectl -n $ns get pod -l $label -o jsonpath='{.items[1].metadata.name}' | xargs -I{} kubectl -n $ns port-forward {} 8080:80

Операции с узлами (нодами) через kubectl


Комбинация jq и JSON-вывода kubectl позволяет делать сложные запросы, такие как фильтрация всех ресурсов по времени их создания.

Подсчёт количества подов в узле Kubernetes


Зачастую высокоуровневая статистика помогает в отладке. Эта команда подсчитает количество всех подов на каждом из узлов:
$ kubectl get pods --all-namespaces -o json | jq '.items[] | .spec.nodeName' -r | sort | uniq -c

Фильтрация узлов по лейблу


Запросы с лейблами можно использовать и для узлов. Такой подход часто применяется при конфигурации deployments, нуждающихся в определённых ограничениях. Для получения подробной информации о селекторах смотрите вывод kubectl explain deployment.spec.selector.
$ kubectl get nodes -l 'master' or kubectl get nodes -l '!master'

Вывести все лейблы можно с помощью аргумента --show-labels для любого объекта Kubernetes:
$ kubectl get nodes --all-namespaces --show-labels

Список всех подов для каждого узла


Генерируется JSON-документ с названием узла Kubernetes и список всех названий подов, запущенных на этом узле. Очень полезная команда при отладке:
$ kubectl get pods --all-namespaces -o json | jq '.items | map({podName: .metadata.name, nodeName: .spec.nodeName}) | group_by(.nodeName) | map({nodeName: .[0].nodeName, pods: map(.podName)})'

Получение внешних IP для узлов Kubernetes


$ kubectl get nodes -o jsonpath='{range .items[]}{.metadata.name} {.status.addresses[?(@.type=="ExternalIP")].address}{"\n"}{end}'


Примечание: Читайте в нашем блоге перевод другой статьи от CoreOS про работу с Kubernetes из консоли: «Автоматизация SSH-доступа к нодам Kubernetes с помощью Fabric и интеграции от CoreOS», а также заметку «Полезные утилиты при работе с Kubernetes» (в ней представлены преимущественно консольные инструменты).

Источники


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

https://habrahabr.ru/post/333956/


Метки:  

[recovery mode] Маршрутизация входящих вызовов в 3CX в зависимости от времени суток

Понедельник, 24 Июля 2017 г. 08:51 + в цитатник

Введение


В этой статье мы покажем, как создавать голосовое приложение 3CX Call Flow Designer, которое маршрутизирует входящие вызовы с 3CX в зависимости от времени суток.


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


Это простое приложение поможет вам освоиться в среде разработки и получить базовые навыки использования CFD.


Обратите внимание — утилита 3CX CFD бесплатно доступна для пользователей 3CX Phone System Pro.


Для вашего удобства, 3CX включила это приложение в набор демо-приложений CFD. Вы можете открыть и изучить его более детально. Готовый рабочий проект приложения размещается в папке Documents\3CX Call Flow Designer Demos при установке CFD.


Создание проекта


Создадим новый проект CFD. Откройте среду разработки, перейдите в File > New > Project, укажите папку, где будет сохранен проект, и укажите имя проекта, например, TimeBasedRouting.

3CX Call Flow Designer

Добавьте компонент Create a condition


Чтобы добавить компонент:


  1. Перетащите компонент Create a condition из Панели компонентов слева в рабочую область под зеленую стрелку, оборзачающую начало работы голосового приложения. Дайте компоненту понятное название, например, selectTimeRange. Для этого кликните по компоненту и измените название в правом нижнем окне Properties Window.
  2. Создайте 4 ветвления приложения и назовите их from0to9, from9to12, from12to18 и from18to0. Для этого кликните по компоненту правой кнопкой мыши и выберите Add branch.
  3. Теперь для каждого ветвления следует создать соответствующие условия. Условия — это логические выражения на C#, которые должны вернуть ИСТИНУ, чтобы сработал компонент, находящийся внутри ветвления (визуально — под условием). Условия проверяются слева направо, т.е. если первое условие вернуло ЛОЖЬ, проверяется второе условие и т.д. Определим условия:
    • Для ветвления from0to9: DateTime.Now.Hour < 9
    • Для ветвления from9to12: DateTime.Now.Hour >= 9 && DateTime.Now.Hour < 12
    • Для ветвления from12to18: DateTime.Now.Hour >= 12 && DateTime.Now.Hour < 18
    • Для ветвления from18to0: оставляем пустым. Это ветвление будет выполняться, если не “сработали” другие ветвления.


Создание ветвлений в 3CX Call Flow Designer

Добавьте компоненты Transfer


Создав условия для ветвлении, добавим в каждое ветвление компонент Transfer. Таким образом, при “срабатывании” условия, вызов будет переводиться на соответствующий добавочный номер.


Для этого перетащите компонент Transfer в каждое из ветвлений. Настройте каждый компонент для перевода вызова на разный добавочный номер. Для этого кликните на компоненте и установите свойство Destination на добавочные номера 101, 102, 103 и 104, соответственно.


Добавление элементов Transfer в Call Flow Designer

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


Добавление добавочного номера для перевода вызова


Компиляция и установка приложения на сервер 3CX


Голосовое приложение готово! Теперь его следует скомпилировать и загрузить на сервер 3CX. Для этого:


  1. Перейдите в меню Build > Build All,и CFD создаст файл TimeBasedRouting.tcxvoiceapp.
  2. Перейдите в интерфейс управления 3CX, в раздел Очереди вызовов. Создайте новую Очередь вызовов, укажите название и добавочный номер Очереди, а затем установите опцию Голосовые приложения и загрузите скомпилированный файл.
  3. Сохраните изменения в Очереди вызовов. Голосовое приложение готово к работе. Теперь, при поступлении вызова на эту Очередь, он будет переведен на соответствующий добавочный номер в зависимости от времени суток.

Загрузка голосового приложения на сервер 3CX

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


Загрузки и документация


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

https://habrahabr.ru/post/333958/


Квантовый протокол распределения ключей BB84

Понедельник, 24 Июля 2017 г. 01:44 + в цитатник

Метки:  

Тестирование БД мобильного Delphi-приложения

Понедельник, 24 Июля 2017 г. 00:08 + в цитатник

Метки:  

Дайджест свежих материалов из мира фронтенда за последнюю неделю №272 (17 — 23 июля 2017)

Воскресенье, 23 Июля 2017 г. 23:26 + в цитатник
Предлагаем вашему вниманию подборку с ссылками на новые материалы из области фронтенда и около него.

Веб-разработка
CSS
Javascript
Браузеры
Занимательное

Веб-разработка



CSS



JavaScript



Браузеры



Занимательное



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



Дайджест за прошлую неделю.
Материал подготовили dersmoll и alekskorovin.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333948/


[Из песочницы] Будь в курсе

Воскресенье, 23 Июля 2017 г. 20:39 + в цитатник

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

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

Давайте напишем бота для телеграмма с оповещением о записях в ВК.

Получаем новости


Для начала нужно создать приложение в ВК и взять из настроек сервисный ключ



Для передачи данных используется протокол WebSocket. Испольхуем библиотеку «websocket».

import websocket

Перед соединением используйте метод streaming.getServerUrl. В качестве результата метод возвращает URL для дальнейших запросов в поле endpoint (string) и ключ доступа в поле key (string).

Получаем урл и ключ

def get_streaming_server_key(token):
    request_url = "https://api.vk.com/method/streaming.getServerUrl?access_token={}&v=5.64".format(token)
    r = requests.get(request_url)
    data = r.json()
    return {"server":data["response"]["endpoint"],"key":data["response"]["key"]}

Слушаем сервер

def listen_stream():
    websocket.enableTrace(True)
    ws = websocket.WebSocketApp("wss://{}/stream?key={} ".format(stream["server"], stream["key"]),
                                on_message=on_message,
                                on_error=on_error,
                                on_close=on_close)
    ws.on_open = on_open
    ws.run_forever()

def on_message(ws, message):
    print(">>>> receive message:", message)

def on_error(ws, error):
    print(">>>> error thead:",error)

def on_close(ws):
    print(">>>> close thead")

def on_open(ws):
    print(">>>> open thead")


stream = get_streaming_server_key(my_servise_token)
listen_stream()

После запуска в консоли должно появиться примерно следующее
— request header — GET /stream?key=e6290ba04916a314c398c331f60224d012fabeb1 HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: streaming.vk.com
Origin: streaming.vk.com
Sec-WebSocket-Key: vG40A5bwbPaVBS+DLBOyog==
Sec-WebSocket-Version: 13
— — response header — HTTP/1.1 101 Switching Protocols
Server: Apache
Date: Thu, 20 Jul 2017 22:06:55 GMT
Connection: upgrade
Upgrade: websocket
Sec-WebSocket-Accept: QRJNqD8K7vWNMcQesYKo64q8MfA=
— >>>> open thead
send: b"\x8a\x80d')\x90"
send: b'\x8a\x80\xfcmp\xe6'
send: b'\x8a\x80s\x9f6{'
send: b'\x8a\x80\xc9\xfa.\xd4'
send: b'\x8a\x80fU<\xed'
send: b'\x8a\x80\xc6Ji\x19'
send: b'\x8a\x80\xd2D\x08!'

Работа с правилами


Добавление

Метод HTTP POST
Content Type application/json
URL запроса https://{endpoint}/rules?key={key}


def set_my_rules(value):
    rule_params = {"rule":{"value":value,"tag":'tag_'+str(random.randint(11111, 99999))}}
    headers = {'content-type': 'application/json'}
    r = requests.post("https://{}/rules?key={}".format(stream["server"], stream["key"]), data=json.dumps(rule_params), headers=headers)
    data = r.json()

    return data['code'] == 200

Получение

Метод HTTP GET
URL запроса https://{endpoint}/rules?key={key}



def get_my_rules():
    r = requests.get("https://{}/rules?key={}".format(stream["server"], stream["key"]))
    data = r.json()
    if data['code'] != 200:
        return False

    return data['rules']

Удаление

Метод HTTP DELETE
Content Type application/json
URL запроса https://{endpoint}/rules?key={key}


def del_my_rules(tag):
    headers = {'content-type': 'application/json'}
    rule_params = {"tag":tag}
    r = requests.delete("https://{}/rules?key={}".format(stream["server"], stream["key"]), data=json.dumps(rule_params), headers=headers)
    data = r.json()

    return data['code'] == 200

Пробуем получить новости

stream = get_streaming_server_key(my_servise_token)
set_my_rules('кот')
listen_stream()

В консоли должно появиться примерно следующее
send: b'\x8a\x80\xc9\xfa.\xd4'
send: b'\x8a\x80fU<\xed'
send: b'\x8a\x80\xc6Ji\x19'
send: b'\x8a\x80\xd2D\x08!'
{«code»:100,«event»:{«event_type»:«post»,«event_id»:{«post_owner_id»:-35708825,«post_id»:4560},«event_url»:«vk.com/wall-35708825_4560»,«text»:«vk.com/small.dolly
Пропал кот. В г.Электросталь на улице Загонова в районе 16 школы. Молодой мальчик, 2 года кастрирован. Обычного серого окраса с полосками. На подбородке и грудке белое пятно. Кот крупный около 7 кг. Пропал 27 июня. Если кто-то его видел пожалуйста сообщите 89250506596 или 89251527466. Мы его очень любим и хотим чтобы он вернулся домой»,«creation_time»:1498942995,«tags»:[«test_cats»],«author»:{«id»:-35708825}}} — наша новсть

Телеграм


Используем библиотеку «telebot».


import telebot

TELEGRAM_API_TOKEN = '3277332...' # токен выдаваемый при создании бота
bot = telebot.TeleBot(TELEGRAM_API_TOKEN)

Старт бота


def _send(msg):
    markup = types.ReplyKeyboardMarkup(row_width=1, resize_keyboard=True)
    markup.add('Мои интересы', 'Очистить список интересов', 'Добавить')

    msg = bot.send_message(chatID, msg, reply_markup=markup) # шлем текст с вариантами ответа
    bot.register_next_step_handler(msg, process_step) # устанавливаем обработчик для наших ответов

# обработчик для 'help', 'start'
@bot.message_handler(commands=['help', 'start'])
def send_welcome(message):
    global chatID
    chatID = message.chat.id
    hello_test = 'Привет, %s! Я бот использующий VK Streaming API!' % message.from_user.first_name
    _send(hello_test)

# обработчик для наших ответов
def process_step(message):
    if message.text == 'Мои интересы':
        _send(get_rules_list())

    if message.text == 'Очистить список интересов':
        _send(clear_rules_list())

    if message.text == 'Добавить':
        msg = bot.send_message(chatID, "Что добавить?")
        bot.register_next_step_handler(msg, add_rule_handler)

Добавить




if message.text == 'Добавить':
        msg = bot.send_message(chatID, "Что добавить?")
        bot.register_next_step_handler(msg, add_rule_handler)
.....
def add_rule_handler(message):
    new_rule = set_my_rules(message.text)
    if new_rule:
        _send("Successful")
    else:
        logging.debug("Error add rules")
        _send("Error")

Мои интересы

def get_rules_list():
    rules = get_my_rules()
    if rules:
        return "\n".join([str(rule['value']) for rule in rules])
    else:
        logging.debug("Error get rules list")
        return 'Error'

Очистить список интересов
def clear_rules_list():
    rules = get_my_rules()
    if rules:
        for rule in rules:
            del_my_rules(rule['tag'])

        return "Successful"

    else:
        logging.debug("Error clear rules list")
        return 'Error'

Отправка новостей

def on_message(ws, message):
    print(">>>> receive message:", message)
    message = json.loads(message)

    if not message['code']:
        return

    if not message['event']['event_type'] or message['event']['event_type'] != 'post':
        return # выходим, если запись не отдельный пост

    post = message['event']['event_type'] +"\n"+message['event']['text'].replace("
", "\n") +"\n\n"+ message['event']['event_url'] _send_post(post)

Запускаем все вместе


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

def listen_stream():
    websocket.enableTrace(True)
    ws = websocket.WebSocketApp("wss://{}/stream?key={} ".format(stream["server"], stream["key"]),
                                on_message=on_message,
                                on_error=on_error,
                                on_close=on_close)
    ws.on_open = on_open
    #ws.run_forever()

    wst = threading.Thread(target=ws.run_forever)
    wst.daemon = True
    wst.start()

Запускаем

if __name__ == '__main__':
    try:
        chatID = 0
        stream = get_streaming_server_key(my_servise_token)
        listen_stream()

        bot.polling(none_stop=True)
    except Exception as e:
        logging.exception("error start")





На этом все, спасибо.

полный код скрипта
Streaming API docs
Telegram API docs
Python websocket-client
Python TelegramBotAPI
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333942/


Метки:  

[Перевод] Как объяснить дизайн четырехлетним?

Воскресенье, 23 Июля 2017 г. 18:56 + в цитатник
image

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

Я планировал пообщаться со старшими ребятами, рассказать то, что считал действительно крутым в своей работе, поделиться каким-то интересным опытом, но в итоге меня попросили провести урок с учениками подготовительной группы (примерно 4-5 лет). Несмотря на то что сначала я был скорее разочарован, это оказалось очень интересной задачей!

Главная особенность работы с детьми такого возраста в том, что ты не можешь ничего рассказать о брендах с которыми работал. Четырехлетние дети не будут восторженно реагировать на истории о работе на Channel 4, BBC и Disel. «Я получал награды BRIT, и даже разработал веб-сайт, на котором получил запись imdb!» — дети не поймут, о чем я вообще говорю. Поэтому нужно было в самых простых выражениях объяснить то, что я сделал, и почему это так важно. Я подумал: было бы здорово показать детям дизайн во всех его формах.

Что я сделал?


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

Затем я объяснил, что существуют разные дизайнеры: есть те, которые решают,
как увеличить количество комнат и где расположить двери и окна, бывают дизайнеры,
которые создают книги, которые вы читаете. Еще есть дизайнеры игр которые решают,
как сделать игру Angry Birds забавной, и где расположить кнопки чтобы нам было удобно играть. Дизайнеры мебели, они определяют, какого размера будут стулья,
и как сделать их удобными.

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

После этого, мы выполнили упражнение «да/нет». У меня был список разных вещей,
а дети должны были отвечать, делали ли эту вещь дизайнеры или нет? Мы начали:

— Лужа («неееет!»)
— Книга («даааа!»)
— Белка («неееет!»)
— Автомобиль («дааааа!»)
… и так далее.


Теперь, когда дети узнали о том, что такое дизайн, мне надо объяснить им, что такое графический дизайн.
Я задумался, как сделать свое объяснение легким для их восприятия? И через какое-то время пришел к простому выводу — надо использовать цвета, буквы и рисунки, чтобы помочь людям понять, что-то чего они не знают. Уф! После долгой карьеры, в которой приходилось отталкиваться от комментариев о «раскраске» и «создании вещей, которые выглядят хорошо» мне наконец удалось попасть в точку. Эта формулировка оказалась прекрасной в своей ясности,
я даже мог бы цитировать её на своих визитках.

Я начал с того, что спросил у класса: какой цвет помогает понять что перед нами кран с горячей водой?

image

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

— «Дети, что бывает голубым и холодным?»
— «Лед!»
— «Да, иногда лед может выглядеть голубым и холодным, вот почему платье Эльзы из мультфильма морозно-голубого цвета.»


Пришло время поговорить о главном! Я сам отец двоих детей, поэтому знаю, что дети в таком возрасте не будут сидеть долго. Мой напарник (учитель начальной школы), сделал несколько небольших книг с образцами цветов, чтобы раздавать их детям, и попросил класс выбрать цвета на основе вопросов.

— Выберите цвет, который напоминает вам о ночи.
— Выберите цвет, который заставляет вас думать о фруктах.
— Выберите цвет, который напоминает вам о Gruffalo!*


* Персонаж книги английской писательницы Джулии Дональдсон — мохнатый и клыкастый житель леса.

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

Затем, мы провели еще одно упражнение, в ходе которого я дал детям список слов, которые нужно было раскрасить определенным цветом. Так они смогли продемонстрировать свои знания на практике. Результаты были великолепны!
Множество красного цвета — для слова «сердитый», яркие цвета — для «сладостей», зеленые — для «травы». Потом я спрашивал у детей, почему они выбрали именно эти цвета? И получал очень убедительные ответы! Конечно, иногда они выбирали цвет «потому что мне это нравится», но ведь это тоже актуально :)

Типографика


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

image

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

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

image

А затем показал тоже предложение, но с выделенным словом «большая»:

image

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

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

image

Каждый раз дети соглашались, что новое слово ощущалось быстрее, чем названное до этого.

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

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

Через неделю я с радостью получил материал урока, по темам, которые мы затронули на в прошлый раз. Большинство детей остались довольными.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333888/


Метки:  

Дайджест интересных материалов для мобильного разработчика #213 (17 — 23 июля)

Воскресенье, 23 Июля 2017 г. 17:03 + в цитатник
В новом дайджесте мы исследуем локализацию, дизайн (для) пальцев, применение CallKit и ARKit, пропажу букв в Android Wear, тестирование приложений и силу минимализма, уроки роста Instagram и новый умный термостат Microsoft.



Локализацию можно автоматизировать: опыт использования Lokalise в боевых условиях

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

Дизайн для пальцев, касаний и людей

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

Дайджест доступен и в виде рассылки. Подписаться вы можете тут.

iOS


Android


Windows


Разработка


Аналитика, маркетинг и монетизация


Устройства, IoT, AI



< Предыдущий дайджест. Если у вас есть другие интересные материалы или вы нашли ошибку — пришлите, пожалуйста, в почту.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333938/


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

Воскресенье, 23 Июля 2017 г. 17:01 + в цитатник
Вашему вниманию предлагается перевод статьи Рэймонда Чена из блога The Old New Thing, посвященной проблемам кода, полагающегося на порядок вычисления выражений — и всем тем, кто пишет foo(i++, a[i]);
Порядок вычисления выражений определяется конкретной реализацией, за исключением случаев, когда язык гарантирует определенный порядок вычислений. Если же в дополнение к результату вычисление выражения вызывает изменения в среде выполнения, то говорят, что данное выражение имеет побочные эффекты.
MSDN

В нашей внутренней рассылке про C# регулярно возникает дискуссионный вопрос, который касается корректной интерпретации подобных конструкций:
a -= a *= a;
p[x++] = ++x;

В ответ я спрашиваю:
Да кто вообще пишет такой код с невозмутимым видом? Одно дело, когда такое пишешь, пытаясь победить в «Международном Конкурсе запутывания кода на Си» (IOCCC, International Obfuscated C Code Contest), или если хочешь написать головоломку — но в обоих случаях понимаешь, что ты занимаешься чем-то нестандартным. Что, реально есть кто-то, кто пишет a -= a *= a и p[x++] = ++x; и думает про себя «Чёрт возьми, да я пишу действительно классный код!»
На что Эрик Липперт отвечает мне: «Да, такие люди определенно встречаются». В качестве примера он привел одну успешную книгу популярного автора, который свято верил в то, что чем короче код, тем быстрее он работает. Так вот, представьте себе — продажи этой книги составляют уже свыше 4 миллионов копий и продолжают расти. Автор этой книги постарался впихнуть в каждое выражение несколько побочных эффектов сразу, плотно усеяв их условными тернарными операторами; всё дело в том, что он искренне верил в то, что скорость выполнения программы пропорциональна количеству использованных в ней точек с запятыми — и что каждый раз, когда программист объявляет новую переменную, Бог убивает щеночка.

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

Во-первых, будет большое количество ложных срабатываний. Допустим, вы напишете следующий код:
total_cost = p->base_price + p->calculate_tax();

Этот код вызовет предупреждение: компилятор увидит, что метод calculate_tax не является константным (const), поэтому он обеспокоится тем, что метод может изменить переменную base_price — и в этом случае иметь значение будет то, считаете ли вы налог по оригинальной base_price базовой цене, или по уже измененной. Теперь, допустим, что вы знаете (и эти знания компилятору недоступны), что метод подсчета налога calculate_tax обновляет значение локальной переменной налог (tax) в объекте, но не изменяет базовую цену; итак, для вас это предупреждение будет ложной тревогой.

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

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

Возьмём супер-умного программиста Эксперта Джо: он знает, что его код безупречен, а компилятор — слабак. «Хорошо, да это же очевидно, что сначала делается инкремент переменной, затем она используется для вычисления индекса массива, а затем результат поиска в массиве сохраняется обратно в переменную. Здесь нет конфликта порядка вычисления. Тупой компилятор!». В результате супер-умный программист Эксперт Джо отключит это предупреждение, сочтя его бесполезным. Что ж, наш Эксперт Джо — это всё-таки безнадежный случай, и за него мы не беспокоимся.

Но возьмем другого программиста, Новичка Джо — на деле, он даже не поймёт сути этого предупреждения. «Ну ок, давайте посмотрим. Я компилировал эту функцию пять раз, и каждый раз я получал одинаковый результат. Результат выглядит для меня надежным. Похоже на то, что предупреждение было ложным». Таким образом, как раз те, кто должен был получить пользу от этого предупреждения, не всегда обладает достаточными знаниями, чтобы понять его.

Конечно же, проходит некоторое время, и этот вопрос всплывает в рассылке вновь. Кто-нибудь обязательно спросит, почему выражение x ^= y ^= x ^= y не работает в C#, хотя работает в С++. Вот вам ещё одно доказательство того, что некоторые всё-таки пишут код, который полагается на несколько побочных эффектов сразу — и эти же люди искренне считают, что их код очевиден и гарантировано будет работать.

Ссылка на оригинал
Ссылка на обсуждение
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333936/


Метки:  

[Перевод] Торгуем ASCII: результаты продаж традиционной Roguelike в раннем доступе

Воскресенье, 23 Июля 2017 г. 16:09 + в цитатник
image

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

Это интересная веха, потому что она более-менее совпадает с завершением первичного контента Cogmind, представленного в бета-релизе в прошлом месяце. Это значит, что для перехода от Alpha 1 к Beta 1 игре понадобилось два года. И по-прежнему удивительно, что оказанной поддержки достаточно для дальнейшей фулл-тайм разработки — доход от Cogmind за весь срок её жизни превысил в апреле отметку в 100 тысяч долларов. Поэтому я благодарен всем, кто позволил мне достичь этого этапа!


@ празднуют бету

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

Доход


Сразу к делу: за второй год Cogmind заработала 40 325 долларов. Если смотреть только на цифры, то это всего две трети того, что она заработала в годом ранее, но важно заметить, что 25 тысяч долларов из доходов первого года были получены в первый месяц альфы. Это стало результатом повышенного интереса из-за двух лет открытой разработки pre-alpha. С учётом этого, технически второй год с точки зрения дохода был немного лучше: рост на 8%, с 37 до 40 тысяч.


Ежедневный валовый доход Cogmind за второй год с комментариями (график первого года находится здесь).

Второй год начался с небольшого снижения цены: с 30 до 24,99 долларов (был добавлен новый вариант низкой цены без всяких преимуществ с сохранением старого варианта). Естественно, это привело к кратковременному скачку продаж, который со временем постепенно спал. Рост количества игроков вернулся к нормальному после того, как игру приобрели все покупатели, ждавшие этой скидки. На этом этапе изменение цены, похоже, не оказало длительного влияния, но перейдём к данным о нём позже.

Следующий заметный подъём совпадает с Roguelike Celebration, потрясающим мероприятием, на котором я выступал с докладом, и после которого начали распространяться новости о Cogmind. Эффект этого события длился добрых две недели.

Потом последовал очевидный пик. Rock, Paper, Shotgun (RPS) следил за Cogmind ещё с pre-alpha, и я не ждал, что они опубликуют ещё что-то после альфы. Поэтому внезапно появившаяся статья стала для меня приятным сюрпризом.

С середины ноября покупатели из Евросоюза наконец смогли получить Cogmind без НДС (VAT), что, в сущности, означало для меня убытки, несмотря на то, что в игровой индустрии НДС обычно включается в цену. Я осознавал, что всё равно теряю деньги в процессе разработки, но мне потребовалось полтора года, чтобы созреть для отказа от 20% доходов в этом регионе. После таких изменений с 15 ноября до 6 июня из стран ЕС я получил 5 085 долларов, а 1 271 долларов ушло на дополнительные налоги (нижняя оценка). Все эти деньги я мог бы получить на разработку, если бы Cogmind была выпущена до 2015 года, когда ЕС ввёл НДС на онлайн-покупки!

На Новый год я сделал GIF с фейерверком из ASCII (первый вариант того, что показано в самом начале поста) и это привлекло внимание, которое почти всегда приводит к увеличению продаж. Я делал анимацию не для этого, она была просто забавным побочным проектом, проверкой возможностей движка, но приятно, что возник такой дополнительный эффект.

В феврале Valve предварительно объявила о завершении программы Greenlight. Поскольку я 1) не был уверен, понравится ли мне её замена, 2) знал, что небольшая кампания в Greenlight сама по себе привлечёт какое-то внимание, и 3) на моём веб-сайте всё равно уже были все нужные ресурсы, то решил выставить Cogmind на голосование. Между принятием этого решения и нажатием на «Опубликовать» прошло всего два дня. Игру одобрили почти сразу же, но целью было не это — заметьте небольшой пик на графике. Неплохо получить немного бесплатного продвижения на Steam: люди, которым не терпелось, уже могли купить игру на моём сайте! Вывод Cogmind в Greenlight мгновенно принёс мне около 750 долларов.

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

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

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


Самое важное — счётчик заказов

В течение второго года я сильнее стремился к тому, чтобы мне было что показать по крайней мере раз в неделю, и я считаю, что это отразилось на относительно малом количестве нулевых дней: в первом годе было 9,8% (36) нулевых дней, а во втором — 4,9% (18). На самом деле, с технической точки зрения результат ещё лучше: заметьте, что треть нулевых дней второго года случилась почти одновременно, примерно летом 2016 года, во время моего месячного отпуска. Нет работы — нет оплаты.


Дни нулевого дохода Cogmind во втором году.

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


Ежемесячный валовый доход Cogmind с комментариями.

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


Ежемесячный доход от Cogmind за второй год по странам.

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

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

Ценообразование


Но у нас есть ещё интересные для анализа данные второго года продаж Cogmind — теперь у нас есть несколько категорий и цен!

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

Напомню, базовая цена Cogmind равнялась 30 долларам в течение первых 12 месяцев, 24,99 долларов в течение 11 последующих месяцев, а затем 19,88 долларов в течение последнего месяца второго года (и до сего момента). Выше, в контексте ежедневного дохода, я уже говорил о некоторых мгновенных эффектах таких изменений цен, но в подробной картине есть и другие детали. Одна из них: мне наконец хватило данных, чтобы исследовать показатель конверсии Cogmind.


Показатель конверсии Cogmind за весь срок жизни (май 2015 ~ май 2017), на основании данных о посетителях buy.html.

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

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

Поэтому эти исходные данные определённо сдвигают показатель конверсии вверх, потому что все, попавшие на эту страницу, уже сильнее заинтересованы в покупке, чем обычный покупатель. (Заметьте, что по стандартным данным индустрии эти показатели высоки.) Для сравнения я сделал то же самое с /cogmind/index.html.


Показатель конверсии всего срока жизни Cogmind (май 2015 ~ май 2017) на основании данных о посетителях index.html.

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

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

Кроме того, я предпочитаю основываться на данных со страницы покупки потому, что многие люди, долгое время следившие за разработкой (иногда годами), однажды принимают решение о покупке в удобный для них момент. Причиной может быть снижение цены, подходящее время или другое сочетание личностных факторов. Я считаю, что есть довольно стабильный поток людей, попадающих в эту категорию. Они просто заходят на страницу покупки и… покупают. Часто это происходит после получения информации об игре по одному из каналов, которые я использую, например Twitter, r/Cogmind, форумы, блог разработки, TIGS, Bay 12, Facebook и т.д…

По поводу тенденции увеличения показателя конверсии: она логична, если связать её с падением цены в этот период. Думаю, эта тенденция гораздо меньше значима при разбивке среднего количества ежедневных посетителей. Мне интересно, откуда берутся такие числа. Например, в первый год выпуска игру Cogmind демонстрировали на множестве крупных сайтов, поэтому посетители с этих сайтов, скорее всего, не будут целевой аудиторией. Наибольшим средним показателем было 71,8 посетителей в день. Во второй период, когда рекламы по общим каналам было меньше, количество посещений значительно снизилось: до 47,5 посетителей в день. А в последний период с самой низкой ценой зарегистрировано всего 43,5 посетителей в день, но при этом показатель конверсии был самым высоким.

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

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


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

После первого года, когда самой низкой ценой была 30 долларов («Prime Tier»), я добавил новый Alpha Tier за 24,99 долларов, не дававший каких-то преимуществ. В течение следующих 11 месяцев покупатели могли выбирать, хотят ли они просто купить игру или вложат ещё немного, чтобы их имя появилось в титрах. Удивительно, но 13,8% индивидуальных покупателей всё равно выбирали Prime tier!

Частично причиной этого была относительно небольшая процентная разница в ценах. Всего на 20% больше за дополнительные преимущества и чтобы помочь любимому проекту? Почему бы и нет? Сравните с показателями, когда цена снизилась до 19,88 долларов, то есть за Prime нужно было платить на 50% (!) больше: процент покупателей, выбирающих этот вариант, уменьшился почти вдвое. Многие из давних поклонников, желающих заплатить больше для поддержки проекта, в любом случае уже сделали это. (Стоит однако заметить, что данные за последний период собирались всего около месяца, потому что от Prime tier я отказался при выпуске беты. Не думаю, что разница стала бы больше, если бы я продолжил продавать этот вариант. Я избавился от него в основном потому, что разработка переходила в новую фазу, и сохранение варианта покупки для «помощников на ранних этапах» казалось уже не слишком подходящим.

В результате я очень доволен своим управлением вариантами покупок и ценами, потому что иначе Cogmind не добралась бы так далеко в процессе разработки до момента публикации в Steam! Если бы я снизил цену до 19,88 долларов раньше, это был бы плохой ход (судя по тому, что я вижу): в долгосрочной перспективе нет никакого значительного прироста общего количества покупателей. Для множества людей всё в промежутке 19-30 долларов относится к категории «слишком дорого». Кроме того, игра продаётся не в Steam, где удобство покупки могло бы простимулировать кого-нибудь превысить свой ценовой предел, или где можно было ввести скидку в качестве дополнительного стимула. (Я по-прежнему не стремлюсь охватить больше потребителей в ущерб доходу на игрока и всё ещё пользуюсь старыми добрыми соцсетями, но именно поэтому я выбрал для этого апрель-май, то есть примерное время перехода на Steam.)

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

Инвестиции


Так куда же уходили эти деньги? Ну, я разработчик-одиночка с относительно низкими затратами на ресурсы, поэтому бОльшая часть, естественно, тратилась на мою скромную «зарплату» за создание и продажу Cogmind.

Как всегда, я выкладывал подробные данные о времени разработки. Они показали, что по сравнению с 3 065 часами разработки pre-alpha и 2 177 часами первого года альфы, второй год продолжался со стабильными 2 192 часами работы. Эти числа не очень приятны, ведь они показывают, что за такой доход это большой объём работы. В экономическом отношении он определённо того не стоит того, но пока стабильность дохода вполне меня устраивала.


Время разработки Cogmind, июль 2013 — апрель 2017 (за исключением работы для джема 7DRL в 2012).

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

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


Разбивка по основным категориям времени разработки Cogmind Alpha.

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


Процентное соотношение времени разработки Cogmind по основным областям, июль 2013 — апрель 2017 (за исключением работы для 7DRL 2012 года).

То есть в целом 66,7% потрачено на саму игру и 33,3% — на сообщество/маркетинг. Это действительно самый минимум, но он устраивает меня, потому что сообщество поклонников традиционных roguelike довольно плотно связано и пообщаться с игроками можно всего на нескольких сайтах, что упрощает мою работу. Другие опытные разработчики заявляют буквально: половину или даже больше времени и усилий нужно тратить на то, чтобы вашу игру каким-то образом заметили (или, что по-моему, столь же важно, на общение с уже образовавшейся базой игроков).

После завершения разработки Cogmind я смогу поделиться ещё более подробной внутренней статистикой разработки и точным анализом. Здесь я просто хотел немного приоткрыть контекст доходов. (В последнем ежегодном обзоре есть также помесячная разбивка времени разработки.)

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

Cogmind пока всё ещё не покрывает расходы, но надеюсь, это исправится после выпуска в Steam.

Следующий шаг


Это был интересный двухлетний марафон альфа-релизов (см. историю), и возможность продления разработки в раннем доступе до публикации в Steam была очень удобна для наполнения исходного видения конкретикой. Некоторые добавленные мной части, даже целые карты, с самого начала совершенно не планировались! И в результате значительной поддержки, несмотря на высокие цены в начале, базу игроков удалось уберечь от разрастания и «разбредания» (как упомянуто в моей статье о ценообразовании). В то же время я получал постоянные отзывы о новых функциях и механиках.

Теперь, когда выпущена бета, и дальнейшая разработка почти полностью заключается в необязательном развитии ради интереса, настало время искать дополнительные каналы продвижения и выпускать Cogmind в Steam. Здесь показатели будут очень важны для будущего Grid Sage Games… поэтому, надеюсь, они дадут хорошие результаты.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332748/


Метки:  

learnopengl. Урок 2.2 — Основы освещения

Воскресенье, 23 Июля 2017 г. 14:22 + в цитатник

Метки:  

Orchid CMS — ещё одна CMS на Laravel

Воскресенье, 23 Июля 2017 г. 13:09 + в цитатник


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



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

В начале


Первым же делом, я отказался, от свойственных для CMS решений вроде: “Тем оформления”, “Плагинов” и “Контроля маршрутизации”. Просто давайте сразу на чистоту, не так часто рабочему сайту нужна смена оформления, а плагин так или иначе должен ставить разработчик, которому composer будет милее. Редактор шаблонов или других параметров тоже нет, так как в действительности это конфликтовало с системой контроля версий.

Основные моменты


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

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

Пример формы которую можно расширить


Поле этого надо было начинать думать, о том как хранить данные. Размышляя о структуре, сложно было не заметить, что на большинстве сайтов (Которые разрабатывала компания), данные по структуре были очень сильно похожие, да и иногда требовался хранения перевода. Это дало мне повод задуматься о EAV формате, но ответ на вопрос как хранить, я нашёл у разработчиков из соседнего отдела, они использовали не реляционные базы данных для мобильных приложений. Перенеся это на MySQL и PostgreSQL, система уже использовала JSON тип, для хранения данных, продолжая вопрос хранения и простоты использования, воспроизвёл wordpress структуру, то есть создал таблицу записи, а данные хранились в ней в JSON формате. Для проведения манипуляций использовалось отдельное поле обозначающее его тип. С помощью которого, можно было бы управлять самой записью.

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

Пример управления записью
namespace DummyNamespace;

use Orchid\Behaviors\Many;

class DummyClass extends Many
{

    /**
     * @var string
     */
    public $name = '';

    /**
     * @var string
     */
    public $slug = '';

    /**
     * @var string
     */
    public $icon = '';

    /**
     * Slug url /news/{name}.
     * @var string
     */
    public $slugFields = '';

    /**
     * Rules Validation.
     * @return array
     */
    public function rules()
    {
        return [];
    }

    /**
     * @return array
     */
    public function fields()
    {
        return [];
    }

    /**
     * Grid View for post type.
     */
    public function grid()
    {
        return [];
    }

    /**
     * @return array
     */
    public function modules()
    {
        return [];
    }
}


Поля и поведения указываются отдельно, что позволяет использовать лишь ключ, например в записи мы хотим wysing редактор, а значением будет класс. Это позволяет менять редактор с summernote на tinymce или ckeditor почти в один клик.
'types' => [
    App\Core\Behaviors\Many\DemoPost::class,
],

'fields' => [
     'textarea' => Orchid\Fields\TextAreaField::class,
     'input'    => Orchid\Fields\InputField::class,
     'tags'     => Orchid\Fields\TagsField::class,
     'robot'    => Orchid\Fields\RobotField::class,
     'place'    => Orchid\Fields\PlaceField::class,
     'datetime' => Orchid\Fields\DateTimerField::class,
     'checkbox' => Orchid\Fields\CheckBoxField::class,
     'path'     => Orchid\Fields\PathField::class,
     'code'     => Orchid\Fields\CodeField::class,
     'wysiwyg'  => \Orchid\Fields\SummernoteField::class,
 ],


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

Пример формы добавления записи


Отдельный момент, касающийся дизайна, на начало разработки, да и скорее всего даже сейчас, практически каждая панель администрирования использовала AdminLTE, не хочу говорить, что она плоха или ещё что либо, но если честно — она надоела, поговорив с дизайнером о цене, понял, что это не мой вариант. Единственным выходом была сеть, тогда я пошёл искать красивые PSD макеты, и нашёл Dashboard60 UI Kit, купив его, я начал не в точности или даже грубо воспроизводить основные моменты (Что бы не получить по ушам).

На этом этапе вся “уникальность” заканчиваться, и начинаются стандартные вещи:
  • Разделение прав доступа на основе ролей
  • Виджеты
  • Теггирование
  • Загрузка файлов
  • Меню
  • Настройки


Итог


Если подвести итоги, то система, будет интересна только тем, кто уже работал с Laravel и хочет с его помощью сделать “простые сайты” с быстрым стартом, это можно увидеть даже на этапе установки, что отличается от многих других похожих приложений, которые делают свой стартер пакет для развёртывания, Orchid же идёт в качестве пакета, то есть сначала необходимо развернуть сам фреймворк и уже после добавлять пакет в зависимости.

Весь код опубликован на github.com
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333926/


Метки:  

Интеграция Apache CloudStack со сторонними системами. Подписка на события с помощью Apache Kafka

Воскресенье, 23 Июля 2017 г. 13:02 + в цитатник


В данной статье рассматривается подход к интеграции Apache CloudStack (ACS) со сторонними системами посредством экспорта событий в брокер очередей сообщений Apache Kafka.


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



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


В разрезе ACS данные функции реализуются следующими возможностями:


  1. Стандартный API — позволяет взаимодействовать с ACS типовым способом.
  2. Плагины API — позволяют разработчикам описывать свои расширения API, предназначенные для реализации специфических взаимодействий.
  3. Экспорт событий — позволяет взаимодействовать с внешними системами при возникновении событий внутри ACS, которые требуют действий от внешних систем.

Итак, ACS предоставляет нам все необходимые способы взаимодействия. В рамках статьи освещается третий способ взаимодействия — Экспорт событий. Вариантов, когда такой способ взаимодействия является полезным достаточно много, приведем несколько примеров:


  • уведомление пользователя посредством сторонних средств, например (SMS, IM) о некоторых событиях, например, событии остановки виртуальной машины;
  • уведомление биллинговой системы о выделении или удалении ресурсов (аккаунтинг, учет, списания);
  • уведомление биллинговой системы о новых аккаунтах ACS.

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

ACS позволяет экспортировать события в брокеры очередей сообщений двумя способами — с применением протокола AMPQ в RabbitMQ и по протоколу Apache Kafka в Apache Kafka, соответственно. Мы широко используем в своей практике Apache Kafka, поэтому в данной статье рассмотрим как подключить к серверу ACS экспорт событий в эту систему.


Экспорт событий в брокер очередей сообщений VS явный вызов API сторонней системы


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


  1. отказоустойчивость;
  2. высокая производительность и масштабируемость;
  3. возможность отложенной или запаздывающей обработки.

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


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

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


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


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


Настройка экспорта событий ACS в Apache Kafka


В рамках настоящего руководства не уделяется внимание как настроить Apache Kafka для использования в "боевой" среде. Этому посвящено немало профильных руководств. Мы же уделим основное внимание тому, каким образом подключить Kafka к ACS и протестировать экспорт событий.


Для развертывания Kafka будем использовать Docker-контейнер spotify/kafka, который включает в себя все необходимые компоненты (Apache Zookeeper и Kafka) и поэтому отлично подходит для целей разработки.


Установка Docker (из официального гайда для установки в CentOS 7) выполняется элементарно:


# yum install -y yum-utils device-mapper-persistent-data lvm2
# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# yum makecache fast
# yum install docker-ce

Настройка Apache Kafka


Развернем контейнер с Apache Kafka:


# docker run -d -p 2181:2181 -p 9092:9092 --env ADVERTISED_HOST=10.0.0.66 --env ADVERTISED_PORT=9092 spotify/kafka
c660741b512a

Таким образом, Kafka будет доступен по адресу 10.0.0.66:9092, а Apache Zookeeper по адресу 10.0.0.66:2181.
Протестировать Kafka и Zookeeper можно следующим образом:


Создадим и запишем в топик "cs" строку "test":


# docker exec -i -t c660741b512a bash -c "echo 'test' | /opt/kafka_2.11-0.10.1.0/bin/kafka-console-producer.sh --broker-list 10.0.0.66:9092 --topic cs"
[2017-07-23 08:48:11,222] WARN Error while fetching metadata with correlation id 0 : {cs=LEADER_NOT_AVAILABLE} (org.apache.kafka.clients.NetworkClient)

Прочитаем ее же:


# docker exec -i -t c660741b512a /opt/kafka_2.11-0.10.1.0/bin/kafka-console-consumer.sh --bootstrap-server=10.0.0.66:9092 --topic cs --offset=earliest --partition=0
test
^CProcessed a total of 1 messages

Если все произошло так, как отображено на врезках кода выше, значит Kafka исправно функционирует.


Настройка Apache CloudStack


Следующим шагом настроим экспорт событий в ACS (оригинал документации здесь). Создадим файл настроек (/etc/cloudstack/management/kafka.producer.properties) для продюсера Kafka, который использоваться ACS со следующим содержимым:


bootstrap.servers=10.0.0.66:9092
acks=all
topic=cs
retries=1

Детальное описание настроек Kafka можно найти на странице официальной документации.


При использовании реплицируемого кластера Kafka в строке bootstrap.servers необходимо указать все известные серверы.

Создадим каталог для java bean, активирующего экспорт событий в Kafka:


# mkdir -p /etc/cloudstack/management/META-INF/cloudstack/core

И сам файл конфигурации для bean-a (/etc/cloudstack/management/META-INF/cloudstack/core/spring-event-bus-context.xml) со следующим содержимым:



   
     
   

Перезагрузим управляющий сервер ACS:


# systemctl restart cloudstack-management

Экспортируемые события теперь попадают в топик cs, при этом имеют формат JSON, пример событий отображен далее (отформатирован для удобства):


{
 "Role":"e767a39b-6b93-11e7-81e3-06565200012c",
 "Account":"54d5f55c-5311-48db-bbb8-c44c5175cb2a",
 "eventDateTime":"2017-07-23 14:09:08 +0700",
 "entityuuid":"54d5f55c-5311-48db-bbb8-c44c5175cb2a",
 "description":"Successfully completed creating Account. Account Name: null, Domain Id:1",
 "event":"ACCOUNT.CREATE",
 "Domain":"8a90b067-6b93-11e7-81e3-06565200012c",
 "user":"f484a624-6b93-11e7-81e3-06565200012c",
 "account":"f4849ae2-6b93-11e7-81e3-06565200012c",
 "entity":"com.cloud.user.Account","status":"Completed"
}

{
 "Role":"e767a39b-6b93-11e7-81e3-06565200012c",
 "Account":"54d5f55c-5311-48db-bbb8-c44c5175cb2a",
 "eventDateTime":"2017-07-23 14:09:08 +0700",
 "entityuuid":"4de64270-7bd7-4932-811a-c7ca7916cd2d",
 "description":"Successfully completed creating User. Account Name: null, DomainId:1",
 "event":"USER.CREATE",
 "Domain":"8a90b067-6b93-11e7-81e3-06565200012c",
 "user":"f484a624-6b93-11e7-81e3-06565200012c",
 "account":"f4849ae2-6b93-11e7-81e3-06565200012c",
 "entity":"com.cloud.user.User","status":"Completed"
}

{
 "eventDateTime":"2017-07-23 14:14:13 +0700",
 "entityuuid":"0f8ffffa-ae04-4d03-902a-d80ef0223b7b",
 "description":"Successfully completed creating User. UserName: test2, FirstName :test2, LastName: test2",
 "event":"USER.CREATE",
 "Domain":"8a90b067-6b93-11e7-81e3-06565200012c",
 "user":"f484a624-6b93-11e7-81e3-06565200012c",
 "account":"f4849ae2-6b93-11e7-81e3-06565200012c",
 "entity":"com.cloud.user.User","status":"Completed"
}

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


# docker exec -i -t c660741b512a \
    /opt/kafka_2.11-0.10.1.0/bin/kafka-console-consumer.sh --bootstrap-server=10.0.0.66:9092 --topic cs --offset=earliest --partition=0

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


В случае настройки экспорта событий для "боевой" среды необходимо помнить о следующем:


  1. Настройка должна быть выполнена для каждого управляющего сервера ACS;
  2. Kafka должен быть настроен в реплицируемом варианте (обычно, 3 сервера и репликация x3);
  3. Apache Zookeeper должен быть настроен в реплицируемом варианте (обычно, 3 сервера);
  4. Настройки /etc/cloudstack/management/kafka.producer.properties должны быть подобраны с учетом требуемого уровня надежности доставки событий.
  5. Не забудьте настроить период удаления старых данных для Kafka (например, 1 месяц).

Вместо заключения


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


  1. Когда я начал заниматься применением ACS на практике, то не обнаружил подобный материал, в итоге, в одном из облаков используется поллинг для связи с биллинговой системой.
  2. Проведена проверка работоспособности для самого нового ACS 4.9.2, которая подтверждает, что функциональность исправна в данной версии продукта.
  3. Статья на русском языке, что может быть полезно для ряда администраторов.
  4. В настоящее время основное внимание уделяется Openstack и складывается впечатление, что это это безальтернативный продукт, хотя основное благо он несет, зачастую, только внедряющему. Хотелось обратить внимание на альтернативные продукт, который весьма применяется рядом крупных организаций и предоставляет удобные инструменты для интеграции.

Надеюсь, что читатели найдут материал интересным и полезным для себя.

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

https://habrahabr.ru/post/333928/


Поднимаем Linux на MIPSfpga и ПЛИС Altera

Воскресенье, 23 Июля 2017 г. 00:56 + в цитатник

КДПВ


Предоставленная Imagination Technologies документация на MIPSfpga очень хорошо и подробно описывает развертывание Linux. Но используемая при этом система на кристалле построена с помощью Xilinx-специфических периферийных модулей. Потому ее повторение на отладочной плате с ПЛИС Altera в исходном виде представляется невозможным. Решением является система на кристалле MIPSfpga-plus с ее платформонезависимой периферией. О том, как запустить на ней Linux, читайте в этой статье.


Введение


Сразу отметим, что получаемой в результате описанных ниже действий конфигурации пока что далеко от идеала. На данный момент не поддерживается загрузка с внешнего носителя, а в числе поддерживаемых устройств можно упомянуть только UART и GPIO. Поэтому фронт дальнейшей работы по развитию системы MIPSfpga-plus представляется очень широким.
Далее предполагается, что читатель:


  • знаком с предметной областью в объеме учебника Харрис-энд-Харрис [L1];
  • имеет доступ к исходным кодам MIPSfpga [L2] и mipsfpga-plus [L3];
  • настроил и проверил работу MIPSfpga-plus с SDRAM [L5] и UART [L6], а также в режиме удаленной отладки [L4];
  • имеет некоторые навыки использования средств разработки ОС Linux, опыт работы с git;

В описываемом случае используется следующая конфигурация:


  • отладочная плата Terasic DE10-Lite с ПЛИС Altera MAX10 и SDRAM 64Mб на борту;
  • плата Pinboard II в качестве отладчика и UART-конвертера. Вы можете использовать любую плату с FTDI USB-чипом, поддерживающим MPSSE, пример такой конфигурации описан в [L4];
  • компьютер Windows 7 (x64) и Quartus Prime 16.1 для синтеза и программирования ПЛИС;
  • виртуальная машина с Ubuntu 17.04 (x64) для сборки ядра и RAM-образа файловой системы;
  • доступ в Интернет;

В случае, если вы планируете серьезно и глубоко погрузиться в магию ядра Linux, настойчиво рекомендуется ознакомится с материалами [L7], в частности, с презентациями [L8] и [L9].
Если все перечисленные требования выполнены, начнем!


Синтез конфигурации и программирование ПЛИС


  • в настройках MIPSfpga-plus (файл mfp_ahb_lite_matrix_config.vh) должны быть включены периферийные модули работы с SDRAM и UART, а также отладка через MPSSE — если используется механизм отладки, описанный в [L4]:


    `define MFP_USE_SDRAM_MEMORY
    `define MFP_USE_DUPLEX_UART
    `define MFP_USE_MPSSE_DEBUGGER

  • с помощью Quartus выполнить сборку MIPSfpga-plus и программирование ПЛИС;

Сборка ядра и RAM-диска


Предполагается, что дальнейшие действия выполняются на машине под управлением Linux.


  • обновить список доступных для системы пакетов:


    sudo apt-get update

  • установить утилиты и библиотеки, необходимые для конфигурирования и сборки:


    sudo apt-get install -y build-essential git libncurses5-dev bc unzip

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


    mkdir ~/mipsfpga
    cd ~/mipsfpga

  • выполнить загрузку toolchain с сайта Imagination Technologies:


    wget http://codescape-mips-sdk.imgtec.com/components/toolchain/2016.05-06/Codescape.GNU.Tools.Package.2016.05-06.for.MIPS.MTI.Linux.CentOS-5.x86_64.tar.gz

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


    mkdir ~/mipsfpga/toolchain
    tar -xvf Codescape.GNU.Tools.Package.2016.05-06.for.MIPS.MTI.Linux.CentOS-5.x86_64.tar.gz -C ~/mipsfpga/toolchain

  • желательно (но не обязательно) прописать путь к развернутым исполняемым файлам в переменную $PATH, это упростит работу с ними. Например, в ~/.profile


    pathadd() {
    if [ -d "$1" ] && [[ ":$PATH:" != *":$1:"* ]]; then
        PATH="$1${PATH:+":$PATH"}"
    fi
    }
    pathadd "$HOME/bin"
    pathadd "$HOME/.local/bin"
    pathadd "$HOME/mipsfpga/toolchain/mips-mti-linux-gnu/2016.05-06/bin"

  • получаем ядро Linux:


    git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git kernel

  • получаем buildroot, с помощью которого будет сформирован RAM-образа файловой системы:


    git clone git://git.buildroot.net/buildroot

  • создаем каталог для патчей buildroot и Linux, необходимых для развертывания на MIPSfpga-plus:


    mkdir patches

  • скачиваем патчи [L10], сохраняем их в только что созданном каталоге;


  • переходим в каталог с buildroot и откатываемся на версию 2017.05.1 (коммит f3d8beeb3694):


    cd buildroot
    git checkout 2017.05.1

  • применяем патч к buildroot:


    git apply ../patches/MIPSfpga_buildroot.patch

  • выполняем конфигурирование buildroot:


    make xilfpga_static_defconfig

  • при необходимости вносим изменения в конфигурацию:


    make menuconfig

  • запускаем сборку RAM-образа файловой системы и идем пить вкусный кофе (чай, пиво или кто что любит), т.к. процесс это весьма продолжительный:
    make


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


    cd ../kernel/
    ls -l ../buildroot/output/images/rootfs.cpio

  • откатываемся на версию v4.12.1 (коммит cb6621858813), т.к. именно от нее сформирован патч:


    git checkout v4.12.1

  • применяем патч:


    git apply ../patches/MIPSfpga_linux.patch

  • применяем базовую конфигурацию ядра MIPSfpga:


    make ARCH=mips xilfpga_de10lite_defconfig

  • запускаем редактор конфигурации:


    make ARCH=mips menuconfig

  • включаем поддержку RAM-диска и прописываем к нему путь (ранее мы проверяли существование этого файла):

RAM disk settings


  • сохраняем изменения, выходим из графического конфигуратора и запускаем сборку ядра:
    make ARCH=mips CROSS_COMPILE=~/mipsfpga/toolchain/mips-mti-linux-gnu/2016.05-06/bin/mips-mti-linux-gnu-

Загрузка ядра в память и запуск


  • на машине, к которой подключен аппаратный отладчик, запускаем OpenOCD, например так, как это описано в [L4];
  • на этой же машине запускаем терминал (например, PuTTY) и подключаемся к COM-порту (скорость 115200);
  • на Linux-компьютере, где мы выполняли сборку, запускаем gdb из состава MIPS toolchain. Предполагается, что мы находимся в каталоге с собранным ядром:


    mips-mti-linux-gnu-gdb ./vmlinux

    Дальнейшие действия выполняются в консоли gdb.


  • подключаемся к OpenOCD, который запущен на машине с аппаратным отладчиком:


    (gdb) target remote 192.168.Х.Х:3333

  • выполняем сброс системы MIPSfpga:


    (gdb) mo reset halt

  • сообщаем отладчику, что наша система Little Endian:


    (gdb) set endian little

  • запускаем ядро на выполнение:


    (gdb) continue

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

Лог загрузки
Linux version 4.12.1+ (stas@ubuntu) (gcc version 4.9.2 (Codescape GNU Tools 2016.05-06 for MIPS MTI Linux) ) #1 Sat Jul 22 14:35:05 MSK 2017
CPU0 revision is: 00019e60 (MIPS M14KEc)
MIPS: machine is terasic,de10lite
Determined physical RAM map:
 memory: 04000000 @ 00000000 (usable)
Initrd not found or empty - disabling initrd
Primary instruction cache 4kB, VIPT, 2-way, linesize 16 bytes.
Primary data cache 4kB, 2-way, VIPT, no aliases, linesize 16 bytes
Zone ranges:
  Normal   [mem 0x0000000000000000-0x0000000003ffffff]
Movable zone start for each node
Early memory node ranges
  node   0: [mem 0x0000000000000000-0x0000000003ffffff]
Initmem setup node 0 [mem 0x0000000000000000-0x0000000003ffffff]
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 16256
Kernel command line: console=ttyS0,115200
PID hash table entries: 256 (order: -2, 1024 bytes)
Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
Memory: 60512K/65536K available (1830K kernel code, 99K rwdata, 320K rodata, 944K init, 185K bss, 5024K reserved, 0K cma-reserved)
NR_IRQS:8
clocksource: MIPS: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 38225208935 ns
sched_clock: 32 bits at 50MHz, resolution 20ns, wraps every 42949672950ns
Console: colour dummy device 80x25
Calibrating delay loop... 10.81 BogoMIPS (lpj=21632)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
devtmpfs: initialized
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
futex hash table entries: 256 (order: -1, 3072 bytes)
clocksource: Switched to clocksource MIPS
random: fast init done
workingset: timestamp_bits=30 max_order=14 bucket_order=0
Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
console [ttyS0] disabled
b0400000.serial: ttyS0 at MMIO 0xb0401000 (irq = 0, base_baud = 3125000) is a 16550A
console [ttyS0] enabled
Freeing unused kernel memory: 944K
This architecture does not have kernel memory protection.
mount: mounting devpts on /dev/pts failed: No such device
mount: mounting tmpfs on /dev/shm failed: Invalid argument
mount: mounting tmpfs on /tmp failed: Invalid argument
mount: mounting tmpfs on /run failed: Invalid argument
Starting logging: OK
Initializing random number generator... done.
Starting network: ip: socket: Function not implemented
ip: socket: Function not implemented
FAIL

Welcome to MIPSfpga
mipsfpga login:

Работа с GPIO


Воспользуемся возможностями Linux для того, чтобы поуправлять той периферией, которая нам доступна (на момент написания статьи это GPIO, правда не в полном объеме):


  • проверяем, что драйвер GPIO загружен и устройство доступно:


    ls /sys/class/gpio/
    export       gpiochip480  unexport

  • для того, чтобы определить доступный диапазон выводов (в текущей конфигурации подключены светодиоды на плате), монтируем debugfs и с ее помощью получаем необходимую информацию:


    mount -t debugfs none /sys/kernel/debug
    cat /sys/kernel/debug/gpio
    gpiochip0: GPIOs 480-511, parent: platform/bf800000.gpio, bf800000.gpio:

  • активируем LED0 (в текущем случае это gpio480):


    echo 480 > /sys/class/gpio/export

  • переводим его в режим вывода:


    echo out > /sys/class/gpio/gpio480/direction

  • переводим его в высокий уровень:


    echo 1 > /sys/class/gpio/gpio480/value

  • если все сделано правильно, то светодиод LED0 должен светиться.

Что дальше


Описанная конфигурация — это, по сути, только начало портирования Linux на систему MIPSfpga-plus. К числу работ, которые необходимо выполнить, чтобы система могла нормально использоваться для практических задач, можно отнести:


  • поддержка существующих периферийных устройств: контроллер прерываний, более полная поддержка GPIO, Altera ADC;
  • поддержка периферийных устройств MIPSfpga-plus, включая отсутствующие на данный момент PWM, интерфейсы SPI (присутствует ограниченно), I2C, DDR и Ethernet;
  • поддержка внешних носителей (mmc/sdram) и возможности загрузки с них;
    По этой причине, если в текущей конфигурации вы столкнетесь с какими-то ошибками (багами), то не удивляйтесь — работы еще много.

Благодарности


Автор выражает благодарность коллективу переводчиков учебника Дэвида Харриса и Сары Харрис «Цифровая схемотехника и архитектура компьютера» [L1], компании Imagination Technologies за академическую лицензию на современное процессорное ядро и образовательные материалы, а также персонально Юрию Панчулу YuriPanchul за его работу по популяризации MIPSfpga.


Ссылки


[L1] — Цифровая схемотехника и архитектура компьютера
[L2] — Как начать работать с MIPSfpga;
[L3] — Проект MIPSfpga-plus на github;
[L4] — MIPSfpga и внутрисхемная отладка;
[L5] — MIPSfpga и SDRAM. Часть 1;
[L6] — MIPSfpga и UART;
[L7] — Free Electrons. Free training materials and conference presentations;
[L8] — Free Electrons. Embedded Linux system development course;
[L9] — Free Electrons. Linux kernel and driver development course;
[L10] — Патчи для buildroot и Linux, необходимые для развертывания на MIPSfpga-plus.

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

https://habrahabr.ru/post/333920/


Метки:  

[Из песочницы] Релизный цикл для Infrastructure as Code

Воскресенье, 23 Июля 2017 г. 00:00 + в цитатник

Метки:  

Neural conversational models: как научить нейронную сеть светской беседе. Лекция в Яндексе

Суббота, 22 Июля 2017 г. 16:48 + в цитатник
Хороший виртуальный ассистент должен не только решать задачи пользователя, но и разумно отвечать на вопрос «Как дела?». Реплик без явной цели очень много, и заготовить ответ на каждую проблематично. Neural Conversational Models — сравнительно новый способ создания диалоговых систем для свободного общения. Его основа — сети, обученные на больших корпусах диалогов из интернета. Борис hr0nix Янгель рассказывает, чем хороши такие модели и как их нужно строить.




Под катом — расшифровка и основная часть слайдов.



Спасибо, что пришли. Меня зовут Боря Янгель, я в Яндексе занимаюсь применением deep learning к текстам на естественном языке и диалоговыми системами. Я сегодня вам хочу рассказать про Neural Conversational Models. Это сравнительно новая область исследований в deep learning, задача которой — научиться разрабатывать нейронные сети, которые с собеседником разговаривают на некоторые общие темы, то есть ведут то, что можно условно назвать светской беседой. Говорят «Привет», обсуждают, как у тебя дела, ужасную погоду или фильм, который ты недавно посмотрел. И сегодня я хочу рассказать, что в этой области уже было сделано, что можно делать на практике, пользуясь результатами, и какие остались проблемы, которые только предстоит решить.

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

Зачем учить сети разговаривать? Кто-то может подумать, что мы учим, чтобы сделать искусственный интеллект, который кого-нибудь когда-нибудь поработит.

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

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

Как их можно делать?

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

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

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

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

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

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

В литературе, то есть в статьях про Neural Conversational Models, очень любят два датасета.

Первый из них — Open Subtitles. Это просто субтитры из огромного числа американских фильмов и сериалов. Какие плюсы этого датасета? В нем очень много жизненных диалогов, прямо таких, которые нам нужны, потому что это фильмы, сериалы, там люди часто говорят друг другу: «Привет! Как дела?», обсуждают какие-то жизненные вопросы. Но поскольку это фильмы и сериалы, то здесь же кроется и минус датасета. Там много фантастики, много фэнтези, которое аккуратно нужно вычищать, и много довольно своеобразных диалогов. Я помню, первая модель, которую мы обучили на Open Subtitles, она к месту и не к месту очень много про вампиров почему-то говорила. На вопрос «Откуда ты?» иногда отвечала: «Я, мать твою, из ФБР». Кажется, что не каждый захочет, чтобы его диалоговый продукт вел себя таким образом.

Это не единственная проблема датасета с субтитрами. Он как сформирован? Надеюсь, многие из вас знают, что такое srt-файлы. Фактически авторы датасета просто взяли srt-файлы этих фильмов и сериалов, все реплики оттуда и записали в огромный текстовый файл. Вообще говоря, в srt-файлах ничего не понятно о том, кто какую реплику говорит и где заканчивается один диалог и начинается другой. Можно пользоваться разными эвристиками: например, предполагать, что две последовательные реплики всегда говорят разные спикеры, или, например, что если между репликами прошло больше 10 секунд, то это разные диалоги. Но подобные предположения выполняются в 70% случаев, и это создает много шума в датасете.

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

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

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

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

Мы это выяснили следующим образом. Мы обучили какую-то модель на Твиттере в первый раз и задали ей несколько простых вопросов типа «Ты где?» и «Сколько тебе лет?».

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

Эти два датасета любят в научной литературе. А если вы собираетесь делать что-то на практике, то вы во многом ограничены разве что своей фантазией и названием компании, на которую вы работаете. Например, если вы Facebook, то вам повезло иметь свой мессенджер, где огромное количество диалогов как раз на те темы, которые нас интересуют. Если вы не Facebook, у вас все еще есть какие-то возможности. Например, можно достать данные из публичных чатов в Telegram, в Slack, в каких-то IRC-каналах, можно распарсить какие-то форумы, поскрепить какие-то комментарии в социальных сетях. Можно скачать сценарии фильмов, которые на самом деле следуют некоторому формату, который в принципе можно распарсить автоматически — и даже понять, где там кончается одна сцена, где кончается другая и кто автор конкретной реплики. Наконец, можно какие-то транскрипты телепередач найти в интернете, и я на самом деле уверен, что я перечислил только малую часть всевозможных источников для диалогового корпуса.

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

Сперва поговорим про первый подход — порождающий.

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

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

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

На самом деле такими формулами обновления никто не пользуется, потому что если обучать такие нейронные сети, возникает очень много неприятных проблем. Пользуются более продвинутыми архитектурами. Например, LSTM (Long short-term memory) и GRU (Gated recurrent units). Дальше, когда мы будем говорить «рекуррентная сеть», мы будем предполагать что-то более продвинутое, чем простые рекуррентные сети.

Порождающий подход. О нашей задаче генерации реплики в диалоге по контексту можно думать как о задаче генерации строки по строке. То есть представим, что мы возьмем весь контекст, все предыдущие сказанные реплики, и просто сконкатенируем их, разделяя реплики разных спикеров некоторым специальным символом. Получается задача генерации строки по строке, а такие задачи неплохо изучены в машинном обучении, в частности — в машинном переводе. И стандартная архитектура в машинном переводе — так называемая sequence-to-sequence. И state of the art в машинном переводе — это все еще модификация подхода sequence-to-sequence. Он был предложен Суцкевером в 2014 году, а позже как раз адаптирован его соавторами для нашей задачи, Neural Conversational Models.

Что такое sequence-to-sequence? Это рекуррентная архитектура encoder-decoder, то есть это две рекуррентных сети: encoder и decoder. Encoder прочитывает исходную строку и генерирует некоторое ее конденсированное представление. Это конденсированное представление подается на вход декодеру, который уже должен сгенерировать выходную строку или для каждой выходной строки сказать, какая же у нее вероятность в этом условном распределении, которое мы пытаемся смоделировать.

Выглядит это следующим образом. Желтенькое — сеть encoder. Допустим, у нас есть диалог двух спикеров из двух реплик «Привет» и «Здаров», для которого мы хотим сгенерировать ответ. Реплики спикеров мы разделим специальным символом end-of-sentense, eos. На самом деле не всегда разделяют предложение, но исторически его называют именно так. Каждое слово мы сперва погрузим в некоторое векторное пространство, сделаем то, что называется vector embedding. Затем этот вектор для каждого слова мы подадим на вход сети encoder, и последнее состояние сети encoder после того, как она обработает последнее слово, как раз и будет нашим конденсированным представлением контекста, которое мы подадим на вход в decoder. Мы можем, например, инициализировать первое скрытое состояние сети decoder этим вектором или, в качестве альтернативы, например, подать его на каждый timestamp вместе со словами. Сеть decoder на каждом шаге генерирует очередное слово реплики и на вход получает предыдущее слово, которое она сгенерировала. Это позволяет действительно лучше моделировать условное распределение. Почему? Я не хочу вдаваться сейчас в детали.

Генерирует decoder все до тех пор, пока не сгенерирует токен end-of-sentence. Это значит, что «Все, хватит». А на вход на первом шаге decoder, как правило, тоже получает токен end-of-sentence. И непонятно, что ему на вход нужно подать.

Обычно такие архитектуры обучаются с помощью обучения maximum likelihood. То есть мы берем условное распределение на ответы при известных нам контекстах в обучающей выборке и пытаемся сделать известные нам ответы как можно более вероятными. То есть максимизируем, допустим, логарифм такой вероятности по параметрам нейронной сети. А когда нам нужно сгенерировать реплику, у нас параметры нейронной сети уже известны, потому что мы их обучили и зафиксировали. И мы просто максимизируем условное распределение по ответу или сэмплируем из него. На самом деле точно его промаксимизировать нельзя, поэтому приходится пользоваться некоторыми приближенными методами. Например, есть метод стохастического поиска максимума в таких архитектурах encoder-decoder. Называется beam search. Что это такое, я тоже сейчас рассказать не успею, но ответ на данный вопрос легко найти в интернете.

Все модификации этой архитектуры, которые были придуманы для машинного перевода, можно попробовать применить и для Neural Conversational Models. Например, encoder и decoder, как правило, многослойные. Они работают лучше, чем однослойная архитектура. Как я уже сказал, это, скорее всего, LSTM- или GRU-сети, а не обычные RNN.

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

Потом в машинном переводе есть такой трюк, прием, который называется attention. Его идея примерно в следующем. Каждый раз, когда ваш декодер генерирует очередное слово, вы можете еще дополнительно посмотреть на все слова или на скрытое представление на каждом timestamp в encoder и как-то их взвесить согласно тому, что вам сейчас нужно. Например, для генерации очередного слова вам нужно найти какой-нибудь следующий предлог во входной последовательности или понять, какая именованная сущность там определялась. Механизм attention помогает это сделать, и он немного помогает в Neural Conversational Models, но на самом деле намного меньше, чем в машинном переводе. Кажется, так происходит потому, что в машинном переводе в большинстве случаев для перевода очередного слова нужно посмотреть на одно слово в исходной последовательности. А при генерации реплики нужно посмотреть на много слов. И возможно, здесь будут работать лучше какие-то приемы, аналогичные тем, которые используются в memory networks. Типа multi-hole potential.

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

Первая проблема, которую вы увидите, — так называемая проблема слишком «общих» реплик. Это известная проблема модели encoder-decoder sequence-to-sequence, которая заключается в следующем. Такие модели склонны генерировать некие очень общие короткие по длине фразы, которые подходят к большому числу контекстов. Например, «Я не знаю», «Окей», «Я не могу сказать» и т. д. Почему так происходит? Можно, например, почитать статью, где авторы попытались формализовать некоторым образом это явление и показали, что в таких архитектурах оно будет происходить неизбежно.

В литературе про Neural Conversational Models предложен ряд решений или, я бы сказал, «костылей» для решения этой проблемы. Все они основаны на том, что мы по-прежнему обучаем модели в режиме максимизации правдоподобия, но когда генерируем реплику, то максимизируем не правдоподобие, а некоторый модифицированный функционал, который в себе это правдоподобие содержит.

Первая идея, которая появилась в литературе, — вместо правдоподобия максимизировать взаимную информацию между ответом и контекстом.

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

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

Чтобы этим методом воспользоваться, вам теперь нужно не только обучить модель sequence-to-sequence, которая выдает указанную вероятность, но и обучить некоторую языковую модель на всевозможных ответах — чтобы получить эту вероятность. То есть возникает минус — нужно две модели.

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

Сравнительно недавно в статье, которую подали на ICLR, был предложен метод, в котором нужна всего одна модель. Тут идея такая. Мы при генерации реплики случайно выбираем сколько-то контекстов из нашего пула — допустим, из обучающей выборки. Затем наш функционал меняется следующим образом. Мы вычитаем из него такую пронормированную вероятность ответа при условии случайного контекста. Тут идея примерно такая же, как и на предыдущем слайде. Если наш ответ уместен для какого-то значительного числа случайных контекстов — это плохо, это значит, что он слишком общий. И на самом деле, если посмотреть на это формально, то перед нами всего лишь оценка Monte Carlo для MMI, который был записан на предыдущем слайде. Но ее прелесть в том, что дополнительная модель вам не нужна, и эмпирически почему-то это работает даже лучше, чем честный MMI.

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

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

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

Вот одно из решений, которое было предложено в литературе, в статье «A Persona-Based Neural Conversation Model»: давайте мы каждому спикеру дополнительно сопоставим вектор в некотором латентном пространстве спикеров. Так же, как мы слова погружаем в латентное пространство, мы и этот вектор будем подавать на вход декодеру в надежде, что при обучении мы туда запишем какую-то информацию, которая нужна, чтобы генерировать ответы от имени данного спикера. То есть, грубо говоря, запишем туда его пол, возраст, какие-то лексические особенности и т. д. И тут же у нас появится некий инструмент контроля поведения модели. Другими словами, мы компоненты этого вектора потом как-то сможем настраивать и, возможно, добиваться от сети желаемого поведения.

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

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

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

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

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

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

Тут идея такая: вместо того, чтобы генерировать ответ с помощью какого-то вероятностного распределения, мы будем ранжировать ответы из некоторого пула согласно функции уместности ответа при условии контекста, которую мы обучим. Какие плюсы у такого подхода? Вы полностью контролируете пул ответов. Вы можете исключить грамматически некорректные ответы или ответы с обсценной лексикой, например. Тогда вы их никогда не сгенерируете, и вы меньше рискуете, чем при использовании порождающей модели, о которой я говорил раньше. Обучение таких архитектур происходит на порядки быстрее, и меньше проявляется проблема общих ответов — потому что она, скорее, свойственна архитектурам sequence-to-sequence encoder-decoder.

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

Как обычно устроены ранжирующие модели? Примерно следующим образом. Есть две сети, которые тут уже называются — и та сеть, и другая — encoder. Задача одной сети — получить некоторое конденсированное векторное представление контекста, другой — векторное представление ответа. Дальше уместность контекста при условии ответа считается с помощью некоторой функции сравнения двух векторов, но и получается в итоге некоторое число, которое говорит об уместности. Такая архитектура стала популярной после статьи Microsoft Research про DSSM, Deep Structure Semantic Models, в 2013 году. И впоследствии указанная архитектура тоже была не раз адаптирована во множестве разных статей для Neural Conversational Models.

Сети encoder, в принципе, могут быть любыми, если они по набору слов могут получить вектор. Например, это тоже могут быть рекуррентные сети — как и в архитектурах sequence-to-sequence. Или можно пойти более простым путем: это могут быть полносвязанные сети поверх усредненных эмбединговых слов. Тоже на удивление неплохо работает.

Как правило, функция уместности ответа в контексте — что-то простое, ведь нам нужно просто сравнить два вектора, скалярное произведение или косинусное расстояние, например.

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

Где брать отрицательные примеры? Классический подход — random sampling, когда вы просто берете случайные реплики в вашем датасете, говорите, что с большой вероятностью они неуместны и на это предположение опираетесь. Есть чуть более нетривиальный подход, который называется hard negative mining. Там идея такая: вы выбираете случайные реплики, но потом из случайных выбираете те, на которых сейчас модель сильнее всего ошибается.

С недавних пор в веб-ранжировании Яндекса существует алгоритм «Палех». Он во многом опирается на аналогичную архитектуру, и в статье на Хабрахабре написано, как этот hard negative mining может работать.

Теперь у вас есть положительные и отрицательные примеры. Что со всем этим делать? Нужна какая-то функция штрафа. Как правило, поступают очень просто: берут выходы этой функции Sim, которая является скалярным произведением или косинусным расстоянием, прогоняют через softmax и получают вероятностное распределение на ваш положительный пример и сколько-то отрицательных примеров, которые вы нагенерировали. А потом, как и в порождающих моделях, просто пользуются кроссэнтропийным лоссом, то есть хотят, чтобы вероятность правильного ответа была большой по сравнению с вероятностью неправильных. Есть всякие модификации на основе tripletloss. Это что-то типа подходов max margin, когда вы хотите, чтобы уместность вашего ответа при условии контакта была больше, чем уместность случайного ответа при условии контекста на некоторый margin, как в SVN. Про это тоже в интернете можно много всего интересного найти.

Как узнать, какая модель лучше? Как в машинном обучении обычно решают этот вопрос? У вас есть тестовая выборка, и вы по ней считаете какую-то метрику. Проблема в том, что здесь это не сработает, поскольку если ответ вашей модели не похож на ответ из тестовой выборки, это не говорит вообще ни о чем. Другими словами, даже на банальное «Привет» можно придумать десятки ответов, которые уместны, но у которых с ответом в тестовой выборке пара общих букв, не более того. Поэтому изначально все пытались использовать метрики из машинного перевода для решения этой задачи, которая сравнивает как-то ваш ответ с тем, что у вас было написано в тестовой выборке. Но все эти попытки провалились. Есть даже такая статья, где считается корреляция метрик, используемых в машинном переводе, с воспринимаемой людьми уместностью ответов. Корреляцию можно посчитать по тестовой выборке. И оказывается, что корреляции практически нет. Значит, этим способом лучше не пользоваться.

Каким же способом пользоваться тогда? Сейчас State of the art, если можно так сказать, подход — использовать краудсорсинг, то есть брать условный mechanical turk, и спрашивать у тёркеров: «Уместен ли данный ответ в данном контексте? Оцените по шкале от 0 до 5». Или: «Какой из данных ответов более уместен в этом контексте?». Если вы посмотрите литературу, в конечном итоге всем приходится сравнивать модели именно так.

А что лучше: порождающие или ранжирующие модели? Вот мы взяли некоторую модель, которую обучили сами на Твиттере sequence-to-sequence, взяли ранжирующую DSSM-подобную модель и дальше на нашей краудсорсинговой платформе попросили работников оценить уместность каждого ответа при данном контексте, поставить одну из трех меток: bad, neutral или good. Bad значит, что ответ синтаксически некорректен, абсолютно неуместен или, например, содержит обсценную лексику. Neutral значит, что он уместен, но является общим и неинтересным. А good — что это синтаксически корректный и уместный ответ. И еще мы попросили людей сгенерировать сколько-то ответов, чтобы у нас был некий baseline, к которому можно стремиться. Вот какие получились цифры.

Что интересно, у людей есть 10% плохих ответов. Почему так происходит? Оказывается, в большинстве случаев люди пытались пошутить, но работники на краудсорсинговой платформе их шутку не поняли. Там, по-моему, в пуле был вопрос: «Какой главный ответ на все?». Ответ был «42», и видимо, никто не понял, что это значит. Там 9 из 10 — bad.

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

В заключение повторю основные поинты своего доклада. В последние пару лет Neural Conversational Models — по-настоящему горячая область исследований в deep learning, одна из таких областей. Ей очень много занимаются, в том числе крупные компании: Facebook, Google. Там происходит много интересного. В принципе, какими-то ее плодами можно пользоваться уже сейчас, но не следует ожидать, что у вас сразу получится искусственный интеллект. Осталось очень-очень много проблем, которые предстоит решать. И если у вас есть значительный опыт работы с текстами на естественном языке, опыт работы с диалоговыми системами или с deep learning в этой области — скорее всего, мы найдем что вам предложить.

Если вам интересно, вы можете, например, мне написать. Вот мои контакты. Только, пожалуйста, не звоните ночью. У меня все. Спасибо.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333912/


Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 1061 1060 [1059] 1058 1057 ..
.. 1 Календарь