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

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

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

InnoDB cluster — оно работает, и вроде бы именно так, как обещали

Четверг, 06 Июля 2017 г. 03:13 + в цитатник

Я занимаюсь АТСками. И как-то так сложилась, что с самого первого заказа от меня хотели отказоустойчивости. Одним из ключевых компонентов современной АТС (как и любой информационной системы, наверное) является БД, где хранятся как данные о текущем состоянии системы, так и всякие конфигурационные параметры. Естественно, падение БД приводит к поломке всей системы. Начиналось все с MASTER-MASTER репликации в MySQL (исключительно для оперативности переключения), потом были эксперименты с MySQL over DRBD. Все это жило в pacemaker/corosync инфраструктуре. Там ездили IP-адреса, шлюзы и прочая лабудень. Со временем оно даже стало работать как-то более-менее устойчиво. Но тут мне попалась пара серверов, на которых DRBD сделать было нельзя, в MASTER-MASTER я разочаровался довольно давно (постоянно она у меня ломается, такая репликация), а без отказоустойчивой БД терялся весь смысл решения. На глаза мне попалось название InnoDB cluster и я решил: "была-не-была". Что из этого получилось — смотрите под катом.


Я все делаю на Debian Jessie. В других системах отличия будут, но не очень существенные.
Нам понадобятся:


  • MySQL APT репозиторий
  • MySQL Shell — для Debain пользователй в самом низу есть ссылка, по которой можно скачать скомпилированные бинарники, по какой причине они не попали в пакет именно для Debain для меня осталось загадкой
  • терпение
  • терпение
  • и еще раз терпение

Скачиваем (это можно сделать только вручную, пройдя регистрацию на сайте Оракла) и устанавливаем файл репозитория, обновляем наш кэш, устанавливаем MySQL Router (интересный зверь, познакомимся ниже) и MySQL Client:


dpkg -i mysql-apt-config_0.8.6-1_all.deb
apt-get update
apt-get install mysql-router
apt-get install mysql-client

Распаковываем и раскладываем по местам MySQL Shell из архива. Двигаемся дальше, ставим сервер:


apt-get install mysql-server

Тут устанавливаем ВСЕ предложенные компоненты (обратите внимание, третий компонент в списке по-умолчанию не выбран, а он понадобится). И останавливаем запущенный сразу ретивым установщиком сервер:


systemctl stop mysql

Далее, идем в
/etc/mysql/mysql.conf.d/mysqld.cnf и пишем туда что-то типа:


[mysqld]
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql
log-error       = /var/log/mysql/error.log
bind-address    = 0.0.0.0
port                    = 3300
symbolic-links=0
# Replication part
server_id=3
gtid_mode=ON
enforce_gtid_consistency=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
log_slave_updates=ON
log_bin=binlog
binlog_format=ROW
# Group replication part
transaction_write_set_extraction=XXHASH64
loose-group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
loose-group_replication_start_on_boot=off
loose-group_replication_local_address= "1.1.1.1:33061"
loose-group_replication_group_seeds= "1.1.1.1:33061,1.1.1.2:33061,1.1.1.3:33061"
loose-group_replication_bootstrap_group= off

Здесь уже надо остановиться подробнее.


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


Следующая: server_id. Для каждого сервера mysql в кластере это значение должно быть уникальным.


Опция, которая съела пару часов моего времени — безобидная (казалось бы) group_replication_local_address. Эта опция говорит о том, на каком адресе/порту слушать обращения за репликами с локальной БД. Алгоритм, по которому MySQL определяет, является ли указанный в этом поле IP-адрес локальным, мне угадать не удалось. На машине с 2-мя активными интерфейсами и тремя IP-адресами, подвешенными на эти интерфейсы только один адрес устроил MySQL.


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


За подробностями можно обратиться на страничку с официальной документацией по GROUP REPLICATION


Итак, развернув на машине MySQL и настроив его таким образом двигаемся дальше. Удаляем все содержимое /var/lib/mysql Я серьезно. Взяли себя в руки, пошли и удалили. Если там лежит что-то, что дорого Вам как память — сделайте предварительно бэкап. Можно. Запускаем mysql:


systemctl start mysql

В общем-то, все подготовительные манипуляции завершены. Описанную процедуру надо будет повторить на всех серверах, которые планируется объединять в кластер.


Теперь особенности для первого сервера. Для начала объявляем root:


mysql
> create user 'root'@'%' identified by 'ochen-strashniy-parol';
> grant all to 'root'@'%' on *.* with grant option;
> flush privileges;
> \q

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


Потом подгружаем модуль X. Честно-честно, именно так его и зовут:


mysqlsh --classic --dba enableXProtocol

И в этот момент модные брюки превращаются… превращаются… превращаются в элегантные шорты. То бишь, MySQL уже не совсем SQL, а вовсе даже Document Store


Но нас это никак не расстраивает, поэтому двигаемся дальше:


mysqlsh

Теперь мы можем общаться с MySQL на JavaScript. Для начала подключимся к нашему серверу:


\c root@1.1.1.1:3300

Введем пароль и проверим, все ли в порядке с нашим сервером, подходит ли его конфигурация для кластеризации:


dba.checkInstanceConfiguration('root@1.1.1.1:3300')

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


dba.configureLocalInstance('localhost:3300', {password:'somePwd', mycnfPath:'some path'})

Однако, у меня этот вариант сходу не заработал, потребовались допиливания напильником конфига до состояния, указанного в начале заметки. Естественно, что после каждого перепиливания конфига, сервер надо перезапускать. Например, при помощи systemctl restart mysq. Ну или как вам больше нравится…
Создаем кластер (предполагаю, что вы все еще в mysqlsh и сессия не обрывалась):


var cl = dba.createCluster('moyCluster')

Ну и добавляем в него только что настроенный сервер:


cl.addInstance('root@1.1.1.1:3300')

Начиная с этого момента рекомендую на какой-нибудь отдельной консоли держать


tail -f /var/log/mysql/error.log

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


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


mysqldump --all-databases  --triggers --routines --events > dump.sql

Теперь займемся остальными. Для этого на всех машинах повторяем манипуляции, описанные от начал статьи и до


systemctl start mysql

Не забываем поправить значения server_id и group_replication_local_address. После этого:


mysql
> reset master;
mysql < dump.sql

Да-да, заливаем в машину дамп с работающего в кластере сервера. Теперь с локальной машины (той, на которой крутится инстанс mysql-server`а, который мы будем подключать к кластеру) делаем:


mysql
> set GLOBAL group_replication_allow_local_disjoint_gtids_join=ON;
mysqlsh
> dba.checkInstanceConfiguration('root@1.1.1.2:3300')
> \c root@1.1.1.1:3300
> var cl = getCluster('moyCluster')
> cl.addInstance('root@1.1.1.2:3300',{ipWhitelist: '1.1.1.0/24, 127.0.0.1/8'})

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


В данный момент у нас есть кластер, который сам за собой присматривает, выбирает мастера и реплицируется на слэйвы. К каждому серверу можно обратиться на его порт 3300 и, если вы обратитесь к мастеру, то вы сможете читать и писать, а если к слейву — то только читать. Выяснить, мастером является сервер или слейвом можно из вывода cluster.status(). Но это еще не очень удобно. Хотелось бы обращаться всегда в одно и то же место, на один и тот же ip/port и не зависеть от внутреннего состояния кластера. Для этого используем MySQL Router Прямо в доке есть пример его начального конфигурирования, который делает почти все, что нам нужно. Изменим его немного:


mysqlrouter --bootstrap 1.1.1.1:3300 --user mysqlrouter

Теперь идем в /etc/mysqlrouter/mysqlrouter.conf и исправляем там порты как-нибудь так:


[routing:moyCluster_default_rw]
...
bind_port=3306
...

[routing:moyCluster_default_ro]
...
bind_port=3307
...

После этого можно делать


systemctl start mysqlrouter

И теперь у вас на порту 3306 отвечает обычный mysql с поддержкой чтения/записи вне зависимости от того, какая из машин кластера сейчас мастером, а какая слейвом. На 3307 — всегда read-only. Количество экземпляров mysqlrouter никак не ограничено, вы можете на каждой клиентской машине запустить свой экземпляр и повесить его на внутренний интерфейс 127.0.0.1:3306. mysqlrouter сам отслеживает изменения в кластере (как добавления, так и пропадания нод в нем) и актуализирует маршрутизацию. Происходит это раз в пять минут (если верить логам). Если в этом промежутке возникает обращение которое не может быть обработано (нода выпала или была целенаправленно выведена из кластера), то роутер дает отказ в исполнении транзакции и перечитывает состояние кластера во внеочередном порядке.


Кстати, если по какой-то причине нода отвалилась от кластера, её можно вернуть в семью командой


mysqlsh
> \c root@
> var cl = dba.getCluster('moyCluster')
> cl.rejoinInstance('root@ip:port-отвалившейся_ноды')

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

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

https://habrahabr.ru/post/332518/


Метки:  

Константин Кривопустов и Алексей Стукалов о CUBA Platform на jug.msk.ru

Среда, 05 Июля 2017 г. 23:58 + в цитатник
На прошедшей 29 июня 2017 года в офисе компании КРОК встрече московского сообщества Java-разработчиков jug.msk.ru Константин Кривопустов и Алексей Стукалов из компании Haulmont рассказали о CUBA Platform, платформе для создания корпоративных систем.



Компания Haulmont является разработчиком CUBA Platform и созданных на её основе нескольких продуктов, наиболее крупными из которых являются Sherlock и ТЕЗИС. Год назад код ядра CUBA Platform стал доступным на GitHub.

Компания была серебряным спонсором конференций JUG.ru: JPoint 2014, JPoint 2017 и Joker 2016. Также её работники участвовали в конференциях JavaOne 2015 (с докладом и являясь серебряным спонсором) и JavaOne 2016 (с мастер-классами).

О докладчиках


Константин является техническим директором и соучредителем компании Haulmont. Традиционно принимает активное участие в представлении компании как на конференциях, так и на страницах Хабра.

Доклады Константина:
  • «Выбор фреймворков реализации ORM и пользовательского интерфейса для корпоративного приложения» (JEEConf 2013: презентация, видео)
  • «Выбор технологий для корпоративного приложения» (JPoint 2014: презентация, видео)

Прочие ссылки: Хабрахабр, GitHub, SlideShare.

Алексей ранее принимал непосредственное участие в разработке, в настоящий момент занимает позицию developer advocate.

Доклады Алексея:
  • «Interviewing Aleksey Stukalov about Cuba platform» (JavaOne 2016: видео)

Прочие ссылки: Хабрахабр, GitHub, SlideShare.

О докладах


Андрей Когунь перед началом встречи с Алексеем и Константином.



Всего было два доклада. В первой части, до перерыва, Константин подробно остановился на архитектуре CUBA Platform, её составных частях, используемом технологическом стеке (более наглядно технологии перечислены здесь), конфигурировании. Приведены доводы, почему используется именно EclipseLink в качестве ORM. Показался интересным рассказ про Polymer UI и упоминание про CUBA Studio.



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



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



Доступны файлы презентаций Константина и Алексея. Фотографии со встречи уже появились здесь. Видео скоро ожидается на YouTube (с анонсом в VK и G+).

Подписаться на рассылку анонсов следующих встреч jug.msk.ru.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332140/


Метки:  

Proxmox 5 и частичная запись в блочных устройствах эффективного хранения Ceph

Среда, 05 Июля 2017 г. 22:56 + в цитатник
Официальный выпуск Ceph Luminous от производителя мы ждём в ноябре 2017, однако Proxmox 5 уже позволяет использовать в промышленных решениях некую редакцию Ceph Luminous, которая, как и полагается, в качестве основного файлового хранилища по умолчанию предлагает BlueStore. Последнее полноценно поддерживает транзакции с операциями хранения объектов, что делает возможными большое число вкусностей. Одной из них является способность осуществления частичной перезаписи данных в блочных устройствах на основе пулов с удаляющим кодированием (Erasure Coding). Такие пулы, в частности, способны (при наличии достаточного числа физических дисков и серверов) приближать использование имеющегося сырого дискового пространства сколь угодно близко к 100%.
Et voil`a!


Методы хранения данных и блочные устройства


Ceph предлагает два вида пулов хранения:
  1. с репликациями
  2. с удаляющим кодированием

При стандарте допустимости двух отказавших устройств хранения, первый метод предполагает необходимость утроения сырого объема хранилища, в то время как второй допускает впечатляющее повышение эффективности использования пространства, например, до 90% при наличии возможности использовании 20 osd для расщепления данных (18 частей исходных данных + 2 части с избыточным кодом).

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

До сих пор предлагалось два способа решения проблемы применимости пулов с удаляющим кодированием под блочные объекты:
  1. использование объекта для записи только целиком
  2. применение многоуровневости с пулом удаляющего кодирования в основе и пула репликаций поверх него

Оба метода имеют ограничения вариантов использования.

BlueStore как новое решение основы хранения


В основе хранения объектов Ceph в конечном итоге лежит некая файловая система на физическом диске (или разделе диска), которым управляет некий демон. Для решения множества возникающих по ходу дела проблем может применяться журнал в который и записываются данные, прежде чем клиент получит подтверждение о совершении своей операции. Помимо этого демон выполняет необходимые действия в одноранговой сети пула хранения по поддержанию необходимого числа копий данных (стандартно — трёх), причём с подразделением ролей хозяин — подчинённый. Всё это, собственно, и составляет osd (object storage device). Но в конечном итоге сами данные объекта хранятся в «обычном» файле на диске. Несколько осложняет задачу тот факт, что теоретически, сам объект может сопровождаться практически неограниченным числом метаданных. Как то: имя объекта, дата его создания, дата последнего изменения, контрольная сумма, сила вашей привязанности к этим данным и всё что вы можете придумать в добавление к тем метаданным, которыми снабжает этот объект ваш инструмент хранения — файловая система, система управления блочными устройствами или объектами и т.п. Причём изменение метаданных и самого объекта хранения тоже атомарно (всё или ничего).
Долгое время сообщество Ceph пребывало в уверенности, что решить проблемы с транзакциями его объектов на нижнем уровне позволит решить btrfs, которая должна была заменить xfs и ext4, применявшиеся в основной массе случаев для оконечного хранения на физических дисках.
Время шло, проблема оставалась.
Ceph Kraken предлагает вам поэкспериментировать с BlueStore, а Ceph Luminious ставит его по умолчанию. На мой личный вкус это второе существенное новшество помимо ставшей основной в Kraken асинхронной системы обмена сообщениями, которая делает возможной, например, Распределённые вычисления поверх Ceph RADOS и AsyncMessenger и применение RDMA.

Что и как подробнее...

Материалы:
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332514/


Тестирование и обзор Core ML

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

Как запутать аналитика. Часть третья. Глаголы и числителные

Среда, 05 Июля 2017 г. 19:03 + в цитатник
В прошлой статье я предложил подход к моделированию существительных и прилагательных таким способом, чтобы получить хранилище предметной области, не требующее изменения его структуры при добавлении в него новых знаний. Получилось следующее:

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


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

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

Сначала уточним наши представления. До сего момента мы считали наш мир статичным. Если это автомобиль, то навсегда, если он желтый, то навсегда. В реальности, конечно, все не так. Один и тот же объект учета в разное время одним и тем же субъектом может быть классифицирован по-разному. В этом заключается учет жизненного цикла объекта. Поэтому, объектами учета, которые мы моделируем в ИС, являются не объекты в целом, а их темпоральные части. Например, мы моделируем не весь автомобиль, который существовал с 1990-го по 2010-й год, а только его темпоральную часть — состояние автомобиля, когда он был желтым: с 1995-го по 1999-ый. Темпоральные части объекта учета – тоже объекты учета, Это значит, что любой объект учета может быть разделен на части, которые также являются объектами учета.

Что стоит за глаголами?



Высказывание: «Мартынов продал станок» кажется очевидным и естественным. Кто? Мартынов. Что сделал? Продал. Что продал Мартынов? Станок. Прямо, как в 6-ом классе школы. И всем кажется, что тут ничего странного в этом нет. Кажется, что субъект выполнил действие, и это нормально. Но вот вопрос: может ли субъект совершать действия? И это вопрос не философский, на который ответил Декарт. Это вопрос из области моделирования. Могу ли я строить модели, исходя из гипотезы о том, что объекты и субъекты совершают действия, например, могу ли я предполагать, что машина едет?

Похожий вопрос я задавал в прошлой статье: могу ли я строить модели, исходя из гипотезы о том, что объекты обладают атрибутами? Ответом было – нет. Это объясняется просто: если объект обладает свойством, то можно подумать, будто объект обладает свойством по своей природе. Однако, свойствами его наделяет субъект. При этом разные субъекты наделят один объект учета разными свойствами.

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

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

Продолжим мысленный эксперимент.

Пусть есть два хранилища моделей, в одном из которых записано: Мартынов продал станок. Во втором хранилище сказано: Гаврилов купил станок. Как объединить хранилища, чтобы было ясно, что это была одна операция?

В ООП действия моделируются методами. Создается класс, объекты которого способны что-то делать. Например, класс людей. Объекты этого класса способны продавать и покупать. И есть две записи о том, что Мартынов выполнил метод по продаже, а Гаврилов выполнил метод по покупке. Чтобы объединить эти две записи в одну, должна быть одна запись, которая выглядит с точки зрения Мартынова как исполнение метода продать, а с точки зрения Гаврилова как исполнение метода купить. Чтобы это сделать, мы можем создать метод, участниками которого сделаем Мартынова, Гаврилова и станок, классифицируем этот метод для Мартынова как продажу, а для Гаврилова – как покупку. Таким образом, мы уравняем степень участия участников операции, отказав участникам в праве что-то выполнять, заодно изобрели функциональное программирование.

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

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

Чуть более внимательно исследуем понятие операции. Операция – это объект учета. Только в отличие от «статичных» объектов учета таких как станок, операция динамична и быстротечна. С другой стороны, в операции могут участвовать «статичные» объекты, например, Мартынов и станок. Иначе говоря, есть объект учета, частями которого являются Мартынов и станок, который трактуется автором модели как операция по продаже. Но частями операции Мартынов и станок были не полностью, а лишь частично. Операция длилась всего один час, а все участники живут гораздо дольше, поэтому в операции участвуют не Мартынов и станок, а их темпоральные части. Поэтому модель операции выглядит так: есть объект учета, трактуемый автором как операция по продаже. Этот объект учета включает в себя темпоральные части объектов учета, которые трактуются как Мартынов и станок. Темпоральная часть Мартынова, являющаяся частью объекта учета, трактуемого как операция, трактуется как исполнитель операции. Все трактовки субъективны. Такая модель операции расширяема. Если появятся ее новые трактовки, например, как покупка, или новые участники, например, Гаврилов, не составит никакого труда добавить их в модель.

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

Числовые атрибуты


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

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

  • Длины (длин волн, если вы занимаетесь волновой оптикой)
  • Частоты (частот волн, если вы радиофизик)
  • Энергии (энергий квантов, если вы занимаетесь квантовой оптикой)

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

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

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

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

https://habrahabr.ru/post/332506/


Метки:  

Книга «Машинное обучение»

Среда, 05 Июля 2017 г. 18:35 + в цитатник
image Привет, Хаброжители к нам из типография наконец-то пришла новинка от Хенрика Бринка, Джозефа Ричардса и Марка Февероволофа.

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


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

Структура книги


Часть I «Последовательность действий при машинном обучении» знакомит с пятью этапами основной последовательности машинного обучения:

• В главе 1 «Что такое машинное обучение?» рассказывается, что представляет собой машинное обучение и для чего оно нужно.

• В главе 2 «Реальные данные» подробно рассматриваются характерные стадии подготовки данных для моделей с машинным обучением.

• Глава 3 «Моделирование и прогнозирование» обучает с помощью распространенных алгоритмов и библиотек созданию простых ML-моделей и генерированию прогнозов.

• В главе 4 «Оценка и оптимизация модели» ML-модели подробно рассматриваются с целью оценки и оптимизации их производительности.

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

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

• Глава 6 «Пример: чаевые для таксистов» — первая, полностью посвященная рассмотрению примера. Мы попытаемся предсказать шансы таксиста на получение чаевых.

• Глава 7 «Усовершенствованное проектирование признаков» знакомит с более сложными техниками проектирования признаков, предназначенными для извлечения значений из текстов, изображений и временных рядов.

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

• Глава 9 «Масштабирование процесса машинного обучения» знакомит с техниками, дающими ML-системам возможность работать с большими объемами данных, обеспечивающими более высокую скорость прогнозирования и уменьшающими время их ожидания.

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

Как читать эту книгу


Тех, кто пока не имеет опыта в области машинного обучения, главы с 1-й по 5-ю познакомят с процессами подготовки и исследования данных, проектированием признаков, моделированием и оценкой моделей. В примерах кода на языке Python используются такие популярные библиотеки, как pandas и scikit-learn. Главы с 6-й по 10-ю включают в себя три практических примера машинного обучения наряду с такими продвинутыми темами, как проектирование признаков и оптимизация. Так как основная вычислительная сложность инкапсулирована в библиотеках, приведенные фрагменты кода легко адаптировать к вашим собственным ML-приложениям.

Об авторах


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

Джозеф Ричардс — старший научный сотрудник в области прикладной статистики и предсказательной аналитики. Хенрик и Джозеф совместно основали компанию Wise.io, которая занимается разработкой решений с машинным обучением для промышленности.

Марк Феверолф — основатель и президент компании Numinary Data Science, специализирующейся в области управления данными и предсказательной аналитики. Он работал статистиком и разработчиком аналитических баз данных в области социальных наук, химической инженерии, производительности информационных систем, планирования объема производства, кабельного телевидения и приложений для рекламы в Интернете.

» Более подробно с книгой можно ознакомиться на сайте издательства
» Оглавление
» Отрывок

Для Хаброжителей скидка 25% по купону — Машинное обучение
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332392/


Метки:  

Кто владеет данными, генерируемыми устройствами из интернета вещей?

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


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

Любопытно, что не существует установленной схемы определения, как присваивается право собственности, и ещё хуже обстоят дела с правильным лицензированием IoT-данных. Давайте рассмотрим ситуацию чуть подробнее.

Владение данными в западном мире


По сути, владелец машинно-генерируемых данных (МГД), к которым относятся практически всё, что генерируется в IoT, это субъект, владеющий устройством, которое записало эти данные. Иными словами, субъект, владеющий IoT-устройством, также владеет и данными, которые устройство генерирует.

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

С одной стороны, данные принадлежат собственнику устройства. То есть право собственности на данные сродни документу на владение землёй. МГД также могут содержать метаданные, что можно сравнить с владением полезными ископаемыми и водой на территории этой земли.
С другой стороны, одна сторона может владеть данными, а другая — контролировать их. Обладание данными не всегда эквивалентно праву на них. Обладание — это контроль. Право — это собственность. Проводя аналогию с правами на использование, каждый раз, когда данные копируются и передаются куда-то, то контроль над ними тоже передаётся. И наоборот — передача права собственности требует наличия легального механизма его оформления.



Я не юрист, но продолжим


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

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

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

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

Стороны контракта на передачу данных


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

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

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



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


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

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

Сложный мир данных, генерируемых транспортом


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

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

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



Энергетика и IoT


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

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

Нет универсального ответа


Как показано выше, вопрос принадлежности прав на IoT-данные сложен. Как правило, владелец оборудования владеет и данными. В разных сферах и компаниях применяются разные подходы к регулированию передачи контроля и прав на данные. Общим знаменателем является хорошо продуманный контракт, защищающий интересы потребителей и питающий растущую экосистему данных.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332504/


Big Data в Райффайзенбанке

Среда, 05 Июля 2017 г. 17:27 + в цитатник
Всем привет!

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



(Отметим, что несмотря на то, что данная схема выглядит достаточно просто, есть очень много «пограничных» случаев. Если они возникают, то мы прибегаем к экспертной оценке, чтобы оценить, нужны ли технологии Big Data для решения поступающих задач или можно обойтись решениями на базе «классических» технологий RDBMS).

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

Для начала пару слов о предпосылках интереса к технологиям. К моменту начала работ по Big Data в банке имелось несколько решений по работе с данными:
  • Data Warehouse (DWH, Корпоративное хранилище данных)
  • Operational Data Store (ODS, Хранилище операционных данных)


Что заставило нас смотреть в сторону Big Data?


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

На тот момент у DWH и ODS имелись некоторые ограничения, которые не позволяли развивать эти решения в качестве универсальных инструментов для анализа всех данных:
  1. Жесткие требования к качеству данных, предъявляемые к DWH, сильно влияют на актуальность данных в хранилище (данные доступны для анализа на следующий день).
  2. Отсутствие исторических данных в ODS (по определению).
  3. Использование реляционных СУБД в ODS и DWH позволяет работать только со структурированными данными. Необходимость определять модель данных еще при записи в DWH/ODS (Schema on write) влечет дополнительные расходы на разработку.
  4. Отсутствие возможности горизонтального масштабирования решения, ограниченность вертикального масштабирования.


Когда мы осознали эти ограничения, то решили смотреть в сторону технологий Big Data. В тот момент было понятно, что компетенции в этой области в перспективе дают конкурентное преимущество, поэтому необходимо наращивать внутреннюю экспертизу. Так как практическая компетенция в Банке на тот момент отсутствовала, у нас фактически было два варианта:
— или сформировать команду с рынка (извне);
— или найти энтузиастов за счет внутренних переходов, без фактического расширения.

Мы выбрали второй вариант, т.к. он нам показался более консервативным.

Далее мы пришли к пониманию, что Big Data это всего лишь инструмент, а вариантов решения конкретной задачи с помощью этого инструмента может быть множество.
Решаемая задача предъявляла следующие требования:
  1. Нужно иметь возможность вместе анализировать данные во всем многообразии их форм и форматов.
  2. Нужно иметь возможность решать широкий спектр аналитических задач – от плоских детерминированных отчетов до экзотических видов визуализации и предиктивной аналитики.
  3. Нужно найти компромисс между большими объемами данных и необходимостью анализировать их онлайн.
  4. Нужно иметь (в идеале) неограниченно масштабируемое решение, которое будет готово выполнять запросы от большого количества сотрудников.


Изучив литературу, почитав форумы и ознакомившись с доступной информацией, мы обнаружили, что решение, удовлетворяющее этим требованиям, уже существует в виде устоявшегося архитектурного шаблона и называется «Data Lake». Приняв решение о внедрении Data Lake, мы таким образом нацелились получить самодостаточную экосистему «DWH + ODS + Data Lake», способную решать любые задачи, связанные с данными, будь то управленческая отчетность, операционная интеграция или предиктивная аналитика.

Наш вариант Data Lake реализует типичную лямбда-архитектуру, в которой входные данные разделяются на два слоя:


— «быстрый» (speed) слой, в котором обрабатываются, в основном, потоковые данные, объемы данных небольшие, трансформации минимальные, но зато достигается минимальное время задержки (latency) между возникновением события и его отображением в аналитической системе. Для обработки данных мы используем Spark Streaming, а для хранения результата – Hbase.
— «пакетный» (batch) слой, в котором данные обрабатываются пакетами (батчами), которые могут включать несколько миллионов записей сразу (например, балансы по всем счетам по результатам закрытия операционного дня), это может занимать некоторое время, но зато мы можем обработать достаточно большие объемы данных (throughput). Данные в слое batch мы храним в HDFS, а для доступа к ним используем Hive или Spark, в зависимости от задачи.

Отдельно хочется отметить Spark. Мы широко его используем для обработки данных и для нас самые значимые преимущества – следующие:
  • Можно использовать в качестве ETL средства.
  • Более быстрый, чем стандартные джобы на MapReduce.
  • Выше скорость написания кода по сравнению с Hive/ MapReduce, т.к. код получается менее многословный, в том числе за счет DataFrame’ов и библиотеки SparkSQL.
  • Более гибкий, поддерживает более сложные пайплайны обработки, чем парадигма MapReduce.
  • Поддерживается Python и JVM-языки.
  • Встроенная библиотека машинного обучения.

Мы стараемся хранить данные в Data Lake в исходном, «сыром» виде, реализуя подход «schema on read». Для управления процессами в качестве планировщика задач мы используем Oozie.

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


Для витрин данных, с которыми будут работать пользователи через BI-средства, планируем использовать форматы Parquet или ORC, т.к. это в большинстве случаев позволит ускорить выборку данных за счет колоночного хранения.

В качестве сборки Hadoop рассматривали Cloudera и Hortonworks. выбрали Hortonworks, потому что его дистрибутив не содерджит проприетарных компонентов. К тому же, у Hortonworks из коробки доступна 2-я версия Spark, а у Cloudera – только 1.6.

Среди аналитических приложений, которые используют данные Data Lake, отметим два.

Первое – Jupyter Hub с Python и установленным библиотеками машинного обучения, которое наши Data Scientist’ы используют для предиктивной аналитики и построения моделей.

На роль второго мы сейчас рассматриваем приложение класса Self-Service BI, с помощью которого пользователи самостоятельно смогут подготовить большинство стандартных ретроспективных отчетов – таблицы, графики, круговые диаграммы, гистограммы и т.д. При этом подразумевается, что роль ИТ будет заключаться в том, чтобы добавить данные в Data Lake, предоставить для приложения и пользователей доступ к данным, и … все. Остальное пользователи смогут делать сами, за счет чего, в частности, мы ожидаем уменьшения конечного времени поиска ответов на интересующие вопросы.

В заключение хотелось бы рассказать, чего мы достигли на данный момент:
  • Вывели в Прод ветку Batch Layer, грузим данные, которые используются как для ретроспективного анализа (т.е. аналитики с помощью данных пытаются ответить на вопрос «как мы пришлю сюда»), так и предиктивного анализа: ежедневный прогноз на базе машинного обучения спроса на снятие наличных в банкоматах и оптимизация работы службы инкассации.
  • Подняли Jupyter Hub, дали пользователям возможность анализировать данные самыми современными инструментами: scikit learn, XGBoost, Vowpal Wabbit.
  • Активно разрабатываем и готовимся вывести в Прод ветку «Speed Layer», реализуя на Data Lake систему класса Real Time Decision Making.
  • Составили продуктовый бэк-лог, реализация которого позволит наибыстрейшим темпом повысить зрелость решения. В числе запланированного:
    1. Катастрофоустойчивость. Сейчас решение развернуто в одном дата центре, и по сути мы не гарантируем непрерывность сервиса, а также можем необратимо потерять накопленные данные, случись что с дата-центром (такая вероятность мала, но все же существует). Мы столкнулись с проблемой: встроенными средствами HDFS нельзя добиться гарантированного хранения данных в разных дата-центрах. Есть доработка на этот счет (https://issues.apache.org/jira/browse/HDFS-5442), ее судьба пока непонятна, планируем реализовывать собственное решение.
    2. Обогащение метаданных (Atlas), Data Management / Governance на основе метаданных, ролевой доступ на основе метаданных.
    3. Исследовать альтернативы выбранным архитектурным компонентам. Первые кандидаты: Airflow как альтернатива Oozie, более продвинутые CDC как альтернатива Scoop для выгрузки данных из реляционных СУБД.
    4. Внедрение конвейера CI/CD. При всем разнообразии используемых технологий и инструментов мы хотим добиться, чтобы любое изменение кода можно было в автоматическом режиме максимально быстро выкатывать в продуктивную среду, и при этом гарантировать качество поставки.


  • Планов на использование Big Data в Райффайзенбанке еще очень много и мы обязательно расскажем об этом.
    Спасибо за внимание!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332496/


Метки:  

Бэкап скриптами в облако Google Cloud Platform (GCP) за пять минут

Среда, 05 Июля 2017 г. 17:05 + в цитатник
Давно уже ребята из различных компаний задают вопросы, как организовать резервное копирование в облако, при этом не тратя много сил и времени. Поводом для написания статьи послужил очередной диалог на эту тему. По итогами долгой переписки с коллегами, объяснения теории и перебора вариантов практической реализации, я решил написать об этом.

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

Что мы имеем


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

Выбор облака


Кто-то посоветовал заказчику OneDrive или Google Drive. Этот вариант отпал сразу, ибо это бред, хранить около 10Тб бэкапов на облачном диске. Смотрели в сторону Azure — странное ценообразование и предоплата. AWS или Google Cloud… доверились более известному в массах :) Была еще пара облачных провайдеров, один даже выигрывал немного в цене, но последним аргументом стала оплата без банковской карты.

Два вида копирования


Да, нам нужно было применить две схемы резервирования различных данных:
  1. Репликация существующего набора копий на сервере
  2. Хранение копий длительное время только в облаке
Начнем с матчасти

Подготовка облака


Создаем триал на 300 долларов в Google Cloud Platform (Кому мало — стучите, обсудим).

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

Подготовка машины


С сервером все просто. Идем в раздел документации Google Cloud, открываем раздел Cloud SDK и действуем по инструкциям. В моем случае была машина с Windows Server, потому скачиваем, ставим. Достаточно стандартных параметров при установке, потому далее-далее-готово.
Открываем командную строку, пишем
gcloud init
нам будет предложено авторизоваться в окне браузера. Вводим логин-пароль от Google Cloud. Далее будет предложено выбрать в окне командной строки проект, выбираем созданный ранее. При вопросе включить ли API — Да, Хотим ли управлять Compute Engine — нет.

Репликация хранилища


В двух словах, зачем она нам была нужна. Есть машина на которой имеется набор резервных копий в определенном каталоге (c:\bak\). Это зашифрованные архивы и их нужно хранить где-то снаружи. Без проблем. Открываем командную строку, пишем
gsutil -m rsync -r -d -e -C file://c:\bak gs://bakwin
  • c:\bak — каталог с копиями для репликации в облако
  • bakwin — "Сегмент" в облачном хранилище Google Cloud Storage, который мы создали ранее

Тут стоит оговориться, что я экспериментирую с машиной Windows, но точно так-же это работает и на Linux, только путь к каталогу поправить нужно.

Команда выполнена, все улетело в облако. Сохраняем как скрипт, включаем в планировщик. Все! Реально пять минут.

Резервное копирование каталога


В этом случае нам потребовалось хранить данные за каждый день в отдельном каталоге в Google Cloud Storage. Тоже оказалось все просто, берем бутерброд и наливаем кофе.

Для любителей PowerShell, я делал именно на нем т.к. машина на Windows Server. Модули у нас установились в системе вместе с Cloud SDK. Потому для начала, кроме
Import-Module GoogleCloud
нам ничего не потребуется.

Показываем где у нас каталог для копирования и в какой сегмент его помещать:
$folder = "C:\Bak"
$bucket = "gs:\backupwin"

Тут можно дописать создание каталога по текущей дате копирования:
$date = Get-date -format dd.MM.yyyy
$bucket = $bucket + "\" + $date
mkdir $bucket

Собственно сам скрипт для копирования:
cd $folder
$files = Get-ChildItem -Recurse -Attributes !Directory
$data = @()
foreach ($file in $files) {
      $objectPath = $file | Resolve-Path -Relative
      $data += @{file = $file; objectPath = $objectPath} # 
}
cd $bucket
foreach($element in $data) {
      Write-Host $element.objectPath
      New-Item -ItemType File -Path $element.objectPath
}

Проверяем, работает. Составляем в скрипт, ставим в планировщик. Вот и вся любовь.

По стоимости хранения 10 Тб данных (в облачном хранилище) оплата будет от 70 долларов в месяц. В целом все работает. Тюнинг скриптов под конкретные условия не применялся.

Вообще резервное копирование в Google Cloud Storage можно использовать и вместе с таким ПО как Cloudberry, Veritas и др. и использовать облачное хранилище как дополнительное пространство для копий. В случае с железом, большинство вендоров уже на уровне хранилищ поддерживают их резервирование в Google Cloud.

Вывод: дешево, быстро, надежно, а перевод из пробной версии в коммерческую происходит без каких-либо перенастроек и банковских карт.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332474/


Опыт создания реалтайм видео-секвенсора на iOS

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

Привет, меня зовут Антон и я iOS-разработчик в Rosberry. Не так давно мне довелось работать над проектом Hype Type и решить несколько интересных задач по работе с видео, текстом и анимациями. В этой статье я расскажу о подводных камнях и возможных путях их обхода при написании реалтайм видео-секвенсора на iOS.


Немного о самом приложении…


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


image


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


image


Готовые решения?


“Почему бы не использовать AVMutableComposition?” — можете спросить вы, и, в большинстве
случаев, будете правы — это действительно достаточно удобный системный видео-секвенсор, но, увы, у него есть ограничения, которые не позволили нам его использовать. В первую очередь, это невозможность изменения и добавления треков на лету — чтобы получить измененный видеопоток потребуется пересоздавать AVPlayerItem и переинициализировать AVPlayer. Также в AVMutableComposition далеко не идеальна работа с изображениями — для того, чтобы добавить в таймлайн статичное изображение, придется использовать AVVideoCompositionCoreAnimationTool, который добавит изрядное количество оверхеда и значительно замедлит рендер.


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


Итак…


Для начала — немного о структуре render pipeline в проекте. Сразу скажу, я не буду слишком вдаваться в детали и буду считать что вы уже более-менее знакомы с этой темой, иначе этот материал разрастется до невероятных масштабов. Если же вы новичок — советую обратить внимание на достаточно известный фреймворк GPUImage (Obj-C, Swift) — это отличная стартовая точка для того, чтобы на наглядном примере разобраться в OpenGLES.


View, которая занимается отрисовкой полученного видео на экране по таймеру (CADisplayLink), запрашивает кадры у секвенсора. Так как приложение работает преимущественно с видео, то логичнее всего использовать YCbCr colorspace и передавать каждый кадр как CVPixelBufferRef. После получения кадра создаются luminance и chrominance текстуры, которые передаются в shader program. На выходе получается RGB изображения, которое и видит пользователь. Refresh loop в данном случае будет выглядеть примерно так:


- (void)onDisplayRefresh:(CADisplayLink *)sender {
    // advance position of sequencer
    [self.source advanceBy:sender.duration];
    // check for new pixel buffer
    if ([self.source hasNewPixelBuffer]) {
        // get one
        PixelBuffer *pixelBuffer = [self.source nextPixelBuffer];
        // dispatch to gl processing queue
        [self.context performAsync:^{
            // prepare textures
            self.luminanceTexture = [self.context.textureCache textureWithPixelBuffer:pixelBuffer planeIndex:0 glFormat:GL_LUMINANCE];
        self.chrominanceTexture = [self.context.textureCache textureWithPixelBuffer:pixelBuffer planeIndex:1 glFormat:GL_LUMINANCE_ALPHA];

            // prepare shader program, uniforms, etc
            self.program.orientation = pixelBuffer.orientation;
            // ...          

            // signal to draw
            [self setNeedsRedraw];
        }];
    }

    if ([self.source isFinished]) {
        // rewind if needed
        [self.source rewind];
    }
}

// ...

- (void)draw {
    [self.context performSync:^{
        // bind textures
        [self.luminanceTexture bind];
        [self.chrominanceTexture bind];

        // use shader program
        [self.program use];

        // unbind textures
        [self.luminanceTexture unbind];
        [self.chrominanceTexture unbind];
    }];
}

Практически все здесь построено на обертках (для CVPixelBufferRef, CVOpenGLESTexture и т.д.), что позволяет вынести основную low-level логику в отдельный слой и значительно упростить базовые моменты работы с OpenGL. Конечно, у этого есть свои минусы (в основном — небольшая потеря производительности и меньшая гибкость), однако они не столь критичны. Что стоит пояcнить: self.context — достаточно простая обертка над EAGLContext, облегчающая работу с CVOpenGLESTextureCache и многопоточными обращениями к OpenGL. self.source — секвенсор, который решает, какой кадр из какого трека отдать во view.


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


@protocol MovieSourceProtocol 

// start & stop reading methods
- (void)startReading;
- (void)cancelReading;

// methods for getting frame rate & current offset
- (float)frameRate;
- (float)offset;

// method to check if we already read everything...
- (BOOL)isFinished;

// ...and to rewind source if we did
- (void)rewind;

// method for scrubbing
- (void)seekToOffset:(CGFloat)offset;

// method for reading frames
- (PixelBuffer *)nextPixelBuffer;

@end

Логика того, как получать кадры, ложится на объекты, реализующие MovieSourceProtocol. Такая схема позволяет сделать систему универсальной и расширяемой, так как единственным отличием в обработке изображений и видео будет только способ получения кадров.
Таким образом, VideoSequencer становится совсем простым, и главной сложностью остается определение текущего трека и приведение всех треков к единому frame rate.


- (PixelBuffer *)nextPixelBuffer {
    // get current track
    VideoSequencerTrack *track = [self trackForPosition:self.position];
    // get track source
    id source = track.source; // Here's our source
    // get pixel buffer
    return [source nextPixelBuffer];
}

VideoSequencerTrack здесь — обертка над объектом, реализующим MovieSourceProtocol, содержащая различную метадату.


@interface FCCGLVideoSequencerTrack : NSObject

- (id) initWithSource:(id)source;

@property (nonatomic, assign) BOOL editable;
// ... and other metadata

@end

Работаем со статикой


Теперь перейдем непосредственно к получению кадров. Рассмотрим простейший случай — отображение одной картинки. Получить ее возможно либо с камеры, и тогда мы сразу можем получить CVPixelBufferRef в формате YCbCr, который достаточно просто скопировать (почему это важно, я объясню чуть позже) и отдавать по запросу; либо из медиа-библиотеки — в этом случае придется немного извернуться и вручную конвертировать изображение в нужный формат. Операцию конвертирования из RGB в YCbCr можно было вынести на GPU, однако на современных девайсах и CPU справляется с этой задачей достаточно быстро, особенно учитывая тот факт, что приложение дополнительно кропает и сжимает изображение перед тем, как его использовать. В остальном же все достаточно просто, все что нужно делать — отдавать один и тот же кадр в течение отведенного промежутка времени.


@implementation ImageSource

// init with pixel buffer from camera
- (id)initWithPixelBuffer:(PixelBuffer *)pixelBuffer orientation:(AVCaptureVideoOrientation)orientation duration:(NSTimeInterval)duration {
    if (self = [super init]) {
        self.orientation = orientation;
        self.pixelBuffer = [pixelBuffer copy];
        self.duration = duration;
    }
    return self;
}

// init with UIImage
- (id)initWithImage:(UIImage *)image duration:(NSTimeInterval)duration {
    if (self = [super init]) {
        self.duration = duration;
        self.orientation = AVCaptureVideoOrientationPortrait;

        // prepare empty pixel buffer
        self.pixelBuffer = [[PixelBuffer alloc] initWithSize:image.size pixelFormat:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange];

        // get base addresses of image planes
        uint8_t *yBaseAddress = self.pixelBuffer.yPlane.baseAddress;
        size_t yPitch = self.pixelBuffer.yPlane.bytesPerRow;

        uint8_t *uvBaseAddress = self.pixelBuffer.uvPlane.baseAddress;
        size_t uvPitch = self.pixelBuffer.uvPlane.bytesPerRow;

        // get image data
        CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
        uint8_t *data = (uint8_t *)CFDataGetBytePtr(pixelData);

        uint32_t imageWidth = image.size.width;
        uint32_t imageHeight = image.size.height;

        // do the magic (convert from RGB to YCbCr)
        for (int y = 0; y < imageHeight; ++y) {
            uint8_t *rgbBufferLine = &data[y * imageWidth * 4];
            uint8_t *yBufferLine = &yBaseAddress[y * yPitch];
            uint8_t *cbCrBufferLine = &uvBaseAddress[(y >> 1) * uvPitch];

            for (int x = 0; x < imageWidth; ++x) {

                uint8_t *rgbOutput = &rgbBufferLine[x * 4];
                int16_t red = rgbOutput[0];
                int16_t green = rgbOutput[1];
                int16_t blue = rgbOutput[2];

                int16_t y = 0.299 * red + 0.587 * green + 0.114 * blue;
                int16_t u = -0.147 * red - 0.289 * green + 0.436 * blue;
                int16_t v = 0.615 * red - 0.515 * green - 0.1 * blue;

                yBufferLine[x] = CLAMP(y, 0, 255);
                cbCrBufferLine[x & ~1] = CLAMP(u + 128, 0, 255);
                cbCrBufferLine[x | 1] = CLAMP(v + 128, 0, 255);
            }
        }

        CFRelease(pixelData);
    }
    return self;
}

// ...

- (BOOL)isFinished {
    return (self.offset > self.duration);
}

- (void)rewind {
    self.offset = 0.0;
}

- (PixelBuffer *)nextPixelBuffer {
    if ([self isFinished]) {
        return nil;
    }

    return self.pixelBuffer;
}

// ...

Работаем с видео


А теперь добавим видео. Для этого было решено использовать AVPlayer — в основном из-за того, что он имеет достаточно удобное API для получения кадров и полностью берет на себя работу со звуком. В общем, звучит достаточно просто, но есть и некоторые моменты, на которые стоит обратить внимание.
Начнем с очевидного:


- (void)setURL:(NSURL *)url withCompletion:(void(^)(BOOL success))completion {
    self.setupCompletion = completion;
    // prepare asset
    self.asset = [[AVURLAsset alloc] initWithURL:url options:@{
        AVURLAssetPreferPreciseDurationAndTimingKey : @(YES),
    }];
    // load asset tracks
    __weak VideoSource *weakSelf = self;
    [self.asset loadValuesAsynchronouslyForKeys:@[@"tracks"] completionHandler:^{
        // prepare player item 
        weakSelf.playerItem = [AVPlayerItem playerItemWithAsset:weakSelf.asset];
        [weakSelf.playerItem addObserver:weakSelf forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    }];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if(self.playerItem.status == AVPlayerItemStatusReadyToPlay) {
        // ready to play, prepare output
        NSDictionary *outputSettings = @{
            (id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange),
            (id)kCVPixelBufferOpenGLESCompatibilityKey: @(YES),
            (id)kCVPixelBufferOpenGLCompatibilityKey: @(YES),
            (id)kCVPixelBufferIOSurfacePropertiesKey: @{
                @"IOSurfaceOpenGLESFBOCompatibility": @(YES),
                @"IOSurfaceOpenGLESTextureCompatibility": @(YES),
            },
        };

        self.videoOutput = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:outputSettings]; 
        [self.playerItem addOutput:self.videoOutput];

        if (self.setupCompletion) {
            self.setupCompletion();
        }
      };
}

// ...

- (void) rewind {
    [self seekToOffset:0.0];
}

- (void)seekToOffset:(CGFloat)offset {
    [self.playerItem seekToTime:[self timeForOffset:offset] toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
}

- (PixelBuffer *)nextPixelBuffer {
    // check for new pixel buffer...
    CMTime time = self.playerItem.currentTime;
    if(![self.videoOutput hasNewPixelBufferForItemTime:time]) {
        return nil;
    }

    // ... and grab it if there is one
    CVPixelBufferRef bufferRef = [self.videoOutput copyPixelBufferForItemTime:time itemTimeForDisplay:nil];
    if (!bufferRef) {
        return nil;
    }

    PixelBuffer *pixelBuffer = [[FCCGLPixelBuffer alloc] initWithPixelBuffer:bufferRef];
    CVBufferRelease(bufferRef);

    return pixelBuffer;
}

Создаем AVURLAsset, подгружаем информацию о треках, создаем AVPlayerItem, дожидаемся нотификации о том, что он готов к воспроизведению и создаем AVPlayerItemVideoOutput с подходящими для рендера параметрами — все по-прежнему достаточно просто.
Однако тут же кроется и первая проблема — seekToTime работает недостаточно быстро, и при loop’е есть заметные задержки. Если же не изменять параметры toleranceBefore и toleranceAfter, то это мало что меняет, за исключением того, что, кроме задержки, добавляется еще и неточность позиционирования. Это ограничение системы и полностью его не решить, но можно обойти, для чего достаточно готовить 2 AVPlayerItem’a и использовать их по очереди — как только один из них заканчивает воспроизведение, тут же начинает играть другой, в то время как первый перематывается на начало. И так по кругу.
Еще одна неприятная, но решаемая проблема — AVFoundation как следует (seamless & smooth) поддерживает изменение скорости воспроизведения и reverse далеко не для всех типов файлов, и, если в случае с записи с камеры выходной формат мы контролируем, то в случае, если пользователь загружает видео из медиа-библиотеки, такой роскоши у нас нет. Заставлять пользователей ждать, пока видео сконвертируется — выход плохой, тем более далеко не факт, что они будут использовать эти настройки, поэтому было решено делать это в бэкграунде и незаметно подменять оригинальное видео на сконвертированное.


- (void)processAndReplace:(NSURL *)inputURL outputURL:(NSURL *)outputURL {
    [[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];

    // prepare reader
    MovieReader *reader = [[MovieReader alloc] initWithInputURL:inputURL];
    reader.timeRange = self.timeRange;

    // prepare writer
    MovieWriter *writer = [[FCCGLMovieWriter alloc] initWithOutputURL:outputURL];
    writer.videoSettings = @{
        AVVideoCodecKey: AVVideoCodecH264,
        AVVideoWidthKey: @(1280.0),
        AVVideoHeightKey: @(720.0),
    };
    writer.audioSettings = @{
        AVFormatIDKey: @(kAudioFormatMPEG4AAC),
        AVNumberOfChannelsKey: @(1),
        AVSampleRateKey: @(44100),
        AVEncoderBitRateStrategyKey: AVAudioBitRateStrategy_Variable,
        AVEncoderAudioQualityForVBRKey: @(90),
    };

    // fire up reencoding
    MovieProcessor *processor = [[MovieProcessor alloc] initWithReader:reader writer:writer];
    processor.processingSize = (CGSize){
        .width = 1280.0, 
        .height = 720.0
    };

    __weak FCCGLMovieStreamer *weakSelf = self;
    [processor processWithProgressBlock:nil andCompletion:^(NSError *error) {
        if(!error) {
            weakSelf.replacementURL = outputURL;
        }
    }];
}

MovieProcessor здесь — сервис, который получает кадры и аудио сэмплы от reader’а и отдает их writer’у. (На самом деле он также умеет и обрабатывать полученные от reader’а кадры на GPU, но это используется только при рендере всего проекта, для того, чтобы наложить на готовое видео кадры анимации)


А теперь посложнее


А что, если юзер захочет добавить в проект сразу 10-15 видеоклипов? Так как приложение не должно ограничивать пользователя в количестве клипов, которые он может использовать в приложении, нужно предусмотреть этот сценарий.


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


- (void) cleanupTrackSourcesIfNeeded {
    const NSUInteger cleanupDelta = 1;
    NSUInteger trackCount = [self.tracks count];
    NSUInteger currentIndex = [self.tracks indexOfObject:self.currentTrack];
    if (currentIndex == NSNotFound) {
        currentIndex = 0;
    }

    NSUInteger index = 0;
    for (FCCGLVideoSequencerTrack *track in self.tracks) {
        NSUInteger currentDelta = MAX(currentIndex, index) - MIN(currentIndex, index);
        currentDelta = MIN(currentDelta, index + (trackCount - currentIndex - 1));

        if (currentDelta > cleanupDelta) {
            track.playheadPosition = 0.0;
            [track.source cancelReading];
            [track.source cleanup];
        }
        else {
            [track.source startReading];
        }

        ++index;
    }
}

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


Подводные камни


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


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


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

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

https://habrahabr.ru/post/332416/


Метки:  

PHDays HackBattle: ломаем один на один

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


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

Отбор



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

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

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




Финал



Положение дел в отборочной таблице менялось на протяжении всего первого дня конференции, и лишь к вечеру там закрепились двое участников, которые и вышли в финал. Ими стали Влад “vos” Росков и Омар “Beched” Ганиев.



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



Финалистам было предложено атаковать одну и ту же инфраструктуру. По легенде это был департамент безопасности вымышленного города:



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

Битва была жаркой, до последнего момента было неясно, кто именно придет к финишу первым! Полную версию финала можно посмотреть на www.phdays.com/broadcast/, 24 мая, part 2 mix stream с 2:00:00. Если вы не хотите раньше времени знать победителя, то не читайте дальше, пока не посмотрите запись.



Победителем оказался Влад “vos” Росков! После конкурса мы взяли у финалистов небольшое интервью, чтобы они поделились впечатлениями от HackBattle.

Влад “vos” Росков:

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

Омар “Beched” Ганиев:

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

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

Задания для конкурса: попробуйте сами

Задания для отбора и финала вы можете скачать в формате OVA:

http://static.ptsecurity.com/phdays/2017/hackbattle/creds.txt — доступы к виртуальным машинам
static.ptsecurity.com/phdays/2017/hackbattle/1.ova
static.ptsecurity.com/phdays/2017/hackbattle/2.ova
static.ptsecurity.com/phdays/2017/hackbattle/3.ova
static.ptsecurity.com/phdays/2017/hackbattle/4.ova
static.ptsecurity.com/phdays/2017/hackbattle/5.ova
static.ptsecurity.com/phdays/2017/hackbattle/6.ova
static.ptsecurity.com/phdays/2017/hackbattle/7.ova
static.ptsecurity.com/phdays/2017/hackbattle/8.ova
static.ptsecurity.com/phdays/2017/hackbattle/9.ova
static.ptsecurity.com/phdays/2017/hackbattle/FINAL.ova

Задачи сильно различаются по сложности. Разбор одной из них (№ 3 по ссылке), за решение которой полагались скромные 100 баллов, можно найти ниже. Конечно, этот спойлер не стоит читать тому, кто хочет попробовать самостоятельно решить эту задачу.

Разбор задания № 3

При переходе по ссылке участник видел веб-приложение с приветственной надписью «User 1, you have been successfully logged in.»:


При клике по ссылке «My profile» открывалась страница профиля User 1:


Сообщение в строке Flag однозначно говорило, что флага тут нет.

Ссылка профиля имела вид «/profile/1», если попробовать перейти по ссылке «/profile/2», то отображался профиль User 2:



К большому сожалению, флага тут также не было, зато очевидно, что присутствует IDOR-уязвимость. Переберем первые 100 id с помощью Burp Intruder:







На id 72 видим аномалию в столбце Length, заходим:



Это то что надо! И флаг теперь выглядит вполне реалистично.

Авторы: Александр Морозов, Анатолий Иванов, Анна Вехтева, Positive Technologies
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332492/


Метки:  

Датацентр ВКонтакте

Среда, 05 Июля 2017 г. 16:27 + в цитатник
Все знают, что сердце ВКонтакте — дом Зингера на Невском проспекте. Сегодня мы расскажем и покажем, где находится и как выглядит его мозг — датацентр ИЦВА.

image

Как построить датацентр?


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

Нельзя просто поставить кучу серверов и коммутаторов. Нужно создать и поддерживать оптимальные условия для их работы. Если Вы хотите построить свой ЦОД, Вам потребуются:
  • Система электроснабжения. Тут всё ясно — серверы работают на электричестве, и их много. Стало быть, обычной розетки на 220В, скорее всего, будет маловато.
  • Система охлаждения. Даже игровая видеокарта в Вашем домашнем компьютере требует мощного кулера. Что уж говорить о сотнях и тысячах высокопроизводительных устройств.
  • Структурированная кабельная система (СКС). Что-то должно соединять все элементы в единое целое. Вам потребуется очень много кабелей и пылкая любовь к процессу их педантичной укладки.

Это основные системы «жизнеобеспечения», самый минимум, который нужен, чтобы просто запустить оборудование. Но для настоящего полноценного датацентра нужно кое-что ещё. А именно:
  • Система пожаротушения. Важно позаботиться о том, чтобы случайная искра не превратила Ваш новенький ЦОД в руины.
  • Система контроля и управления доступом (СКУД). Не стоит оставлять двери открытыми для всех желающих.
  • Система мониторинга. Вы должны вовремя узнать, если что-то пошло не так.
  • Охранная сигнализация. На случай, если вместо пропуска кто-то решит использовать лом.
  • Система видеонаблюдения.

Мы верим, что у Вас получится отличный датацентр. А пока посмотрим, как выглядит наш.

Добро пожаловать в ИЦВА


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

В четырёх машинных залах размещены 640 стоек — это более 20000 серверов и более 200 коммутаторов, роутеры и DWDM-системы ёмкостью свыше 4 Тб/c. Здесь установлен роутер ASR9000 с серийным номером 1 — в своё время это была первая коммерческая установка такого устройства во всём мире.

В пике датацентр генерирует более 1 Тб/c внешнего трафика. К нашим DWDM-системам подключены более 10 крупнейших международных провайдеров и международных центров обмена трафиком, а также около 40 крупных операторов РФ.

image

Первый машинный зал. Возможно, именно здесь лежит Ваше любимое видео.

Электроснабжение


Все элементы системы электроснабжения резервируются как минимум N+1.
Буквально напротив здания датацентра находится подстанция «Восточная», от которой питание подаётся в ЦОД по двум вводам 6кВ. Далее через распределительную подстанцию и автоматический ввод резерва питание подаётся по двум независимым вводам. Вот как это выглядит на схеме (для простоты — с одним машинным залом из четырёх):

image

Схема электропитания в штатном режиме

Каждый узел дублируется и в норме работает под половинной нагрузкой. В случае аварии питание дойдёт до машинного зала в обход вышедшего из строя участка. Например, мы потеряли один 6кВ ввод:

image

Схема электропитания при аварии на вводе

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

image
Источники бесперебойного питания

image
А это аккумуляторы для них — внешне очень похожи на автомобильные…

image
… только занимают несколько больших помещений

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

image
Дизель-генераторные установки

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

image
Статический переключатель нагрузки + ручной байпас Digital Energy

Система охлаждения


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

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

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

image
Внутренние блоки прецизионных кондиционеров

image
Внешние блоки прецизионных кондиционеров

Холодный воздух из камеры смешения или кондиционера через фальшпол или воздуховод подаётся в так называемый «холодный коридор». Это изолированное пространство между лицевыми сторонами двух рядов стоек. Вот такое:

image
Холодный коридор машинного зала

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

image
Горячий коридор машинного зала

Структурированная кабельная система


Километры бережно уложенных проводов. Здесь не нужны слова.

image

image

image

image

image

image

Система пожаротушения


В нашем ЦОДе предусмотрена система газового пожаротушения. Собственно газ (хладон) хранится под давлением в баллонах. В случае пожара по сигналу с датчика в машинном зале клапан будет приведён в действие, и газ по трубам устремится к источнику возгорания.

image
Баллоны с хладоном

image
Манометр

Мониторинг


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

image
Мониторинг электроснабжения

image
Мониторинг системы охлаждения

Система контроля доступа и охрана


На территорию могут попасть только сотрудники, любая дверь снабжена электронным замком со считывателем карты доступа. ИЦВА охраняется в режиме 24/7, в каждом помещении ведётся видеонаблюдение.

Подведём итоги


ИЦВА имеет очень удачное расположение: всего в нескольких километрах от родного города ВКонтакте и рядом с надёжным источником электроэнергии.

Здесь непрерывно продолжается процесс модернизации оборудования и повышения энергоэффективности. PUE (Power Usage Effectiveness), или коэффициент эффективности использования электроэнергии — ключевой показатель оценки ЦОД. Он считается как соотношение всей энергии, потребляемой датацентром, и фактического потребления серверов и сетевого оборудования. Как ясно из этого определения, PUE идеального датацентра в вакууме равен 1.0. ИЦВА — не идеальный датацентр в вакууме, но мы планомерно работаем над снижением этого показателя.

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

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

image

P.S. Статьи о технической стороне ВКонтакте также можно читать в нашем блоге на русском и английском языках. Задать вопрос автору можно в официальном сообществе.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332430/


Метки:  

[Из песочницы] Главная проблема CG в России и первый шаг на пути её решения

Среда, 05 Июля 2017 г. 16:14 + в цитатник
image

Всё, что я вижу вокруг, всегда с той или иной скоростью меняется. Что-то очень быстро, что-то медленно, что-то вообще не сдвигается с места. И здесь речь идет именно о менталитете людей, об их отношении к вещам, с ними никак не связанными; об их понимании того, что в мире есть множество интересных и сложных профессий/наук, о глубине которых они никогда не задумывались. Я говорю о людях, живущих в России. В нашей стране еще с советских времен в головах людей прочно оседают устоявшиеся нормы, пресечь которые или изменить они практически не в состоянии. То, какие мысли витают в головах большинства наших людей касательно политики, финансовой грамотности и изучения чего-то совершенно нового для себя, пугает. И если с политикой всё и так понятно, с финансовой грамотностью — так же, хотя, пожалуй, здесь проблемы не только у россиян, то с уважением к чужой работе, или хотя бы с осознанием того, что твоя работа не самая тяжелая во всей вселенной, у нас очень большие проблемы.

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

Начну с того, что компьютерная графика в нашей стране — это одна из наиболее недооцененных и, возможно, наряду с IT-сферами, самая неочевидная отрасль деятельности. «Неочевидная» здесь — малопонятная, неоднозначная или попросту «вещь для специфичных, увлеченных людей». Никогда не пробовали сравнивать себя с теми же айтишниками (например, программистами)? Сейчас, когда в тренде VR и AR технологии, CG и IT всё теснее начинают сотрудничать друг с другом. Однако в отличие от IT, где работают «исключительно ботаники», которые трудятся изо дня в день и получают заслуженно высокие гонорары, в CG работают ребята, которые могут ткнуть куда надо, они знают про кнопочку «сделать красиво», ну а ещё они рисуют крутых роботов или человекоподных существ в 3D, ну могут ещё рисовать игры, «какие-то там движки регулировать, чтоб игралось нормально», а ещё они сидят и добавляют эффекты, которые те же «айтишники» им действительно разработали… Короче, мозгов-то особо не нужно, каждый при желании может этим заниматься, а когда уже и так всё готово, то и времени на это много не нужно…

Наверняка заметили, как я тихо скатился к наиболее обобщенному мнению о CG? Ну как? Как вам то, что думает большая часть людей про компьютерную графику и её важность в современной России? Как вам тот факт, что в связи с вышесказанным, достойных выплат предлагать вам не будут, а инвестиции в CG… даже звучит странно, согласитесь? А как же тот факт, что именно всё это общество ставит вам дедлайны или просто условия выполнения? В случае с CG идеальным заказчиком всегда будет такая же CG-компания/люди, потому что только они знают истинную ценность вашего труда и сложность работы. Но, справедливости ради, все мы знаем, что в хороших, сформировавшихся студиях по разработке игр/производству 2D/3D-анимации, моушн-дизайна, визуализации интерьеров/экстерьеров зарплаты существенно выше среднего по стране. Однако такие деньги выплачиваться будут только тем людям, которые успели себя зарекомендовать, успели обучиться своему мастерству и готовы (кстати говоря) обучить остальных новичков. Но это как раз тот самый случай: CG работает с CG.

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

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

Короче говоря, труд CG-художников не ценится или оценивается не по достоинству. Это факт. Многие с этим мирятся, правительству нашей страны, кажется, вообще неизвестно об этой проблеме, ровно как и о том, что в других странах есть специальные инвестиционные компании, которые вкладывают капиталы в области медиа, CG, IT и т.п. (тот же Providence Equity Partners). Хотя, например, мне известно о WargamingLabs, проекте студии Wargaming, созданном с целью помочь инди-разработчикам игр продвинуть свой продукт. Но опять же, это только gamedev (Game Development, разработка игр) и каковы масштабы этого предприятия — неизвестно.

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

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

И после такого краткого обзора ситуации с CG в России, сразу возникает резонный вопрос: а как же всё изменить? Как сделать так, чтобы отношение к компьютерной графике из нейтрального перешло в позитивное, в то отношение, которое уже давно существует в США, Канаде и Великобритании?

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

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

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

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

Безусловно, я не претендую на роль супер-создателя-решения-от-всех-проблем, но попробовать нам никто не запрещает. В конце концов, мы хотя бы попытались, пускай, даже эта идея — бред с абсолютно нулевым финалом. Важно попытаться. В этом смысле меня очень вдохновляет Сергей Цыпцын, написавший «Понимая Maya», основатель Real School, а впоследствии и Scream School, главный организатор CG Event’а. Сергей сделал очень много для популяризации CG в России, однако если CG Event создан прежде всего для людей, в CG живущих, то почему бы не создать нечто столь же колоссальное, только для людей, про CG не знавших?

Спасибо.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332490/


Метки:  

Новый пак стикеров Otus coding Owl

Среда, 05 Июля 2017 г. 15:52 + в цитатник
Всем привет! У нас появился классный персонаж, который отлично иллюстрирует жизнь любого, причастного к миру IT…

Баталии за выкатки в прод по пятницам, костыльные решения и спешка перед дедлайном — стикеры для всех и для каждого!

Передать все что тебя переполняет одной картинкой — бесценно.



OTUS Coding Owl появилась в Telegram, чтобы выразить всю эту бурю эмоций! Добавляйте набор по ссылке — и наслаждайтесь!

В планах пополнение и дополнение набора!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332488/


Метки:  

[recovery mode] Программирование и боевое искусство: что общего?

Среда, 05 Июля 2017 г. 15:50 + в цитатник
Написание кода — ремесло, которое требует постоянного развития — считают участники инициативы Coding Dojo в EPAM. Лидер движения Александр из Киева рассказал, как «додзё»-практики повышают настроение у инженеров и почему игра помогает преуспеть в работе.

image


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

image

Итак, разработчики собираются в определенном месте и начинают выполнять «каты» — несложные задания, повторяя которые, прокачивают свое инженерное мастерство. У Coding Dojo могут быть различные формы. Одна из них — Codenjoy, или кодинг ради приятных эмоций. Участники создают свой бот, который затем в режиме реального времени соревнуется в какой-нибудь несложной игре — например, Tetris, Battlecity, Snake, Sudoku, Minesweeper, Moebius и других. Побеждает та команда или участник, чей бот набрал наибольшее количество очков.

Проектный менеджер Александр уже около года занимается продвижением инициативы Codenjoy в EPAM на глобальном уровне:

«Я начинал как обычный инженер на проекте в другой компании. Как-то на одной из конференций узнал о новом инструменте — Coding Dojo, который еще недавно был заморской диковинкой. На этом ивенте Johannes Brodwall продемонстрировал участникам одну из его реализаций. Затем вместе с Сергеем мы решили написать что-то свое.

Так появился Tetris, а чуть позже мы дали этой игре наше собственное название — Codenjoy (от Code + Enjoy). Получилась активность интересного формата, которую мы регулярно проводили, везде, куда нас приглашали. Позже комьюнити Codenjoy поделилось на сэнсэев, или организаторов, подливающих масла в огонь; участников — программистов, которые пишут код; и контрибьюторов — тех, кто начал писать свои собственные игры. В зависимости от результатов игры, участники получают обратную связь — почему лидер вырвался в лидеры, а задние пасут задних.

image

Таким образом, в прошлой компании Codenjoy развивался в качестве инициативы выходного дня, пока я не познакомился с руководителем программы Engineering Excellence в EPAM Сергеем Сергиенко. Он обратил внимание на Codenjoy и через несколько лет пригласил меня в компанию развивать эту инициативу. Таким вот образом я стал заниматься проектом выходного дня, но уже в качестве основной работы.

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

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

image

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

Coding Dojo — это инструмент геймификации для разных профессионалов. Мы умеем работать не только с Software-инженерами, но и с инженерами по автоматизированному тестированию (для них у нас есть программа Coding Automated Testing Dojo). Кроме того, сотрудничаем с нетехническими специалистами (на базе игры I Can Code помогаем им получить базовые представления о программировании). Приятно, когда через два часа такой игры под присмотром фасилитатора HR-специалист говорит: «Здорово! Все не так сложно, как представлялось».

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

image

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

Играя в Coding Dojo, ребята становятся на путь изменений: видят, что их код недостаточно качественный и им нужно расти, ведь кто-то же победил их по очкам в 10 или 100 раз. Или же просто отвлекаются от основных проектных активностей и находят вдохновение в игре. Получается своеобразная кодинг-терапия «лекарством» для энтузиазма.

Присоединяйcя к инициативе Coding Dojo в качестве волонтера. На https://github.com/codenjoyme вы можете сделать fork проекта и работать с ним. С вопросами обращайтесь к Александру по e-mail — Oleksandr_Baglai@epam.com.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332486/


Метки:  

Вырастаем над проблемами Python

Среда, 05 Июля 2017 г. 15:22 + в цитатник

Метки:  

[Из песочницы] Переписываем домашний проект на микросервисы (Java, Spring Boot, Gradle)

Среда, 05 Июля 2017 г. 15:00 + в цитатник

Введение


Image


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


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


Всё это было реализовано в виде прототипа — были пользователи, один урок и одна задача для него, возможность отправить код, который компилировался и исполнялся. Кое-какой фронтенд, но в статье о нём речи не будет. Технологии — Spring Boot, Spring Data, Gradle.


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


В процессе изучения информации я нашёл хорошую статью, где аналогично разбивали некий небольшой монолит на микросервисы. Но там всё делалось на основе Spring Cloud, что безусловно правильнее, но мне хотелось сначала написать велосипед, чтобы потом на практике понимать от каких проблем лечат данные решения. Из данной статьи я использовал только Zuul.


Микросервисы


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


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


  • user-service: сервис с пользователями (создание, просмотр, возможно авторизация)
  • lesson-service: сервис с уроками (создание, просмотр уроков и задач)
  • result-service: сервис с ответами (отправка выполненных задач, хранение результатов)
  • task-executor-service: сервис исполнения кода (компиляция и исполнение задач)

На этом этапе появляется мысль, что со всем этим зоопарком нужно как-то общаться фронтенду и отдельным микросервисам. Кажется неудобным, если все будут знать API и адреса друг друга.
Отсюда появляется ещё один сервис — gateway-service — общая точка входа.


Схема проекта будет выглядеть так:


diagram


Gateway-service


Поскольку я иду по самому простому пути, первой мыслью было сделать просто по контроллеру для каждого микросервиса, в которых будет перенаправление всех запросов по нужным адресам с помощью RestTemplate. Но, немного погуглив, я нашёл Zuul. У него есть интеграция со Spring Boot и конфигурация выходит крайне простой.


build.gradle сервиса выглядит так:


plugins {
    id 'java'
    id 'war'
}

apply plugin: 'spring-boot'

springBoot {
    mainClass 'gateway.App'
}

dependencies {
    compile('org.springframework.cloud:spring-cloud-starter-zuul:1.2.0.RELEASE')
    compile('org.springframework.boot:spring-boot-starter-web')
}

А весь код микросервиса состоит из одного класса, App.java:


@SpringBootApplication
@EnableZuulProxy
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

Это включает ZuulProxy. Маршрутизация описывается в конфиге, у меня это application.properties:


zuul.routes.lesson-service.url=http://localhost:8081
zuul.routes.user-service.url=http://localhost:8082
zuul.routes.task-executor-service.url=http://localhost:8083
zuul.routes.result-service.url=http://localhost:8084

zuul.prefix=/services

Таким образом, запросы на /services/lesson-service/... будут направляться на http://localhost:8081/... и т.д. Получается очень удобное и простое решение для точки входа.
Zuul имеет много других различных фич типа фильтров, но нам от него больше ничего и не нужно.


Фронтенд так же, как мне кажется, в нашем случае должен отдаваться клиенту отсюда. Кладём всё что нужно в gateway-service/src/main/webapp/... и всё.


Остальные сервисы


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


  1. Базы данных.
  2. Взаимодействие между микросервисами.

Базы данных


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


Можно для каждого использовать новый тип базы данных. Но у меня просто появились три MySQL базы данных вместо одной, для user-service, lesson-service и answer-service. A task-executor-service должен хранить некий код задач, в который вставляется пользовательский код для выполнения задачи. Это будет храниться без БД, просто в виде файлов.


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


Взаимодействие между микросервисами


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


Создаём новый модуль в проекте, назовём его service-client. В нём будут, во-первых, классы для взаимодействия с сервисами, во-вторых общие классы для передачи данных. То есть у каждого сервиса есть свои какие-то Entity, соответствующие внутренней логике или схеме БД, но наружу они должны отдавать только экземпляры объектов из общей библиотеки.


Для классов-клиентов пишем абстрактный класс Client:


abstract class Client {
    private final RestTemplate rest;
    private final String serviceFullPath;

    private final static String GATEWAY_PATH = "http://localhost:8080/services";

    Client(final String servicePath) {
        this.rest = new RestTemplate(Collections.singletonList(new MappingJackson2HttpMessageConverter()));
        this.serviceFullPath = GATEWAY_PATH + servicePath;
    }

    protected  T get(final String path, final Class type) {
        return rest.getForObject(serviceFullPath + path, type);
    }

    protected  T post(final String path, final E object, final Class type) {
        return rest.postForObject(serviceFullPath + path, object, type);
    }
}

GATEWAY_PATH — лучше задавать из конфига или ещё как-то, а не хардкодить в этом классе.
И пример наследования этого класса для lesson-service:


public class TaskClient extends Client {
    private static final String SERVICE_PATH = "/lesson-service/task/";

    public TaskClient() {
        super(SERVICE_PATH);
    }

    public Task get(final Long id) {
        return get(id.toString(), TaskResult.class).getData();
    }

    public List getList() {
        return get("", TaskListResult.class).getData();
    }

    public List getListByLesson(final Long lessonId) {
        return get("/getByLesson/" + lessonId, TaskListResult.class).getData();
    }

    public Task add(final TaskCreation taskCreation) {
        return post( "/add", taskCreation, TaskResult.class).getData();
    }
}

Тут может возникнуть вопрос, что за Result и почему мы возвращаем результат от getData() для него. Каждый контроллер возвращает не просто некий запрашиваемый объект в json, а ещё и дополнительную мета-информацию, которая в дальнейшем может быть полезна, поэтому при переписывании в микросервисы я не убрал это. То есть возвращается объект класса Result, где T это сам запрашиваемый объект:


@Data
public class Result {
    public String message;
    public T data;

    public static  Result success(final T data) {
        return new Result<>(null, data);
    }

    public static  Result error(final String message) {
        return new Result<>(message, null);
    }

    public static  Result run(final Supplier function ) {
        final T result = function.get();
        return Result.success(result);
    }
}

Тут нет метода getData(), хотя ранее в коде он используется. Всё это благодаря аннотации @Data от lombok, который я активно использовал.Result удобен тем, что далее можно легко добавлять некую мета-информацию (например время выполнения запроса), и как-то её использовать.


Теперь, чтобы использовать написанный нами код в других модулях, достаточно добавить зависимость (compile project(':service-client') в блок dependencies) и создать такой бин. Вот так выглядит конфигурация result-service:


@SpringBootApplication(scanBasePackages = "result")
@EnableJpaRepositories("result.repository")
@Configuration
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

    @Bean
    public UserClient getUserClient() {
        return new UserClient();
    }

    @Bean
    public TaskClient getTaskClient() {
        return new TaskClient();
    }

    @Bean
    public ExecutorClient getTaskExecutor() {
        return new ExecutorClient();
    }
}

Его контроллер:


@RestController
@RequestMapping
public class ResultController {

    @Autowired
    private ResultService service;

    @RequestMapping(value = "/submit", method = RequestMethod.POST)
    public Result submit(@RequestBody final SubmitRequest submit){
        return run(() -> service.submit(submit));
    }

    @RequestMapping(value = "/getByTask/{id}", method = RequestMethod.GET)
    public Result> getByTask(@PathVariable final Long id) {
        return run(() -> service.getByTask(id));
    }
}

Видно, что везде контроллер возвращает некий Result. И фрагмент сервиса:


@Service
@Transactional
public class ResultService {

    @Autowired
    private AnswerRepository answerRepository;

    @Autowired
    private TaskClient taskClient;

    @Autowired
    private ExecutorClient executorClient;

    public TaskResult submit(final SubmitRequest submit) {

        val task = taskClient.get(submit.getTaskId());
        if (task == null)
            throw new RuntimeException("Invalid task id");

        val result = executorClient.submit(submit);

        val answerEntity = new AnswerEntity();
        answerEntity.setAnswer(submit.getCode());
        answerEntity.setTaskId(task.getId());
        answerEntity.setUserId(1L);
        answerEntity.setCorrect(result.getStatus() == TaskResult.Status.SUCCESS);
        answerRepository.save(answerEntity);

        return result;
    }

    ...

answerEntity.setUserId(1L) — пока тут просто константа, ибо пока что совершенно непонятно как делать авторизацию.


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


Авторизация


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


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


Первоначальный поиск привёл меня на разнообразные статьи, показывающие как шарить сессии с помощью Redis, но прочитанное мною показалось слишком сложным для hello-world домашнего проекта. Через некоторое время, вернувшись к вопросу, я уже нашёл информацию о JWT — JSON Web Token. Кстати, повторяя попытки поиска при написании этой статьи, я уже сразу натыкался на JWT.


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


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


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


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


Итак, немного почитав интернеты, например эту статью, решаем что токен будет всего один и его будет выдавать user-service. Добавляем зависимости:


compile('org.springframework.boot:spring-boot-starter-security')
compile('io.jsonwebtoken:jjwt:0.7.0')

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


private String getToken(final UserEntity user) {
    final Map tokenData = new HashMap<>();
    tokenData.put(TokenData.ID.getValue(), user.getId());
    tokenData.put(TokenData.LOGIN.getValue(), user.getLogin());
    tokenData.put(TokenData.GROUP.getValue(), user.getGroup());
    tokenData.put(TokenData.CREATE_DATE.getValue(), new Date().getTime());
    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.DATE, tokenDaysAlive);
    tokenData.put(TokenData.EXPIRATION_DATE.getValue(), calendar.getTime());
    JwtBuilder jwtBuilder = Jwts.builder();
    jwtBuilder.setExpiration(calendar.getTime());
    jwtBuilder.setClaims(tokenData);
    return jwtBuilder.signWith(SignatureAlgorithm.HS512, key).compact();
}

key тут это секретный ключ токена, который должны знать все сервисы для декодирования токена. Мне не понравилось, что его нужно писать в конфиг каждого сервиса, но другие варианты сложнее.


Далее нам нужно написать фильтр, который при каждом запросе будет проверять токен и авторизировать если всё ок. Но фильтр уже будет не в user-service, а в service-client, т.к. это общий код для всех сервисов.


Сам фильтр:


public class TokenAuthenticationFilter extends GenericFilterBean {

    private final TokenService tokenService;

    public TokenAuthenticationFilter(final TokenService tokenService) {
        this.tokenService = tokenService;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        final String token = ((HttpServletRequest) request).getHeader(TokenData.TOKEN.getValue());
        if (token == null) {
            chain.doFilter(request, response);
            return;
        }

        final TokenAuthentication authentication = tokenService.parseAndCheckToken(token);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(request, response);
    }
}

Если token не прислали — не делаем ничего, иначе пытаемся авторизировать клиента. Проверка авторизации осуществляется уже не нами, а дальше в другом (стандартном) фильтре от spring security. TokenService, где происходит непосредственная проверка токена:


public class TokenService {

    private String key;

    public void setKey(String key) {
        this.key = key;
    }

    public TokenAuthentication parseAndCheckToken(final String token) {
        DefaultClaims claims;
        try {
            claims = (DefaultClaims) Jwts.parser().setSigningKey(key).parse(token).getBody();
        } catch (Exception ex) {
            throw new AuthenticationServiceException("Token corrupted");
        }

        if (claims.get(TokenData.EXPIRATION_DATE.getValue(), Long.class) == null) {
            throw new AuthenticationServiceException("Invalid token");
        }

        Date expiredDate = new Date(claims.get(TokenData.EXPIRATION_DATE.getValue(), Long.class));
        if (!expiredDate.after(new Date())) {
            throw new AuthenticationServiceException("Token expired date error");
        }

        Long id = claims.get(TokenData.ID.getValue(), Number.class).longValue();
        String login = claims.get(TokenData.LOGIN.getValue(), String.class);
        String group = claims.get(TokenData.GROUP.getValue(), String.class);

        TokenUser user = new TokenUser(id, login, group);

        return new TokenAuthentication(token, true, user);
    }
}

TokenData это enum для удобства, из которого можно взять строковые представления полей. Ещё тут есть два класса — TokenUser (это класс с тремя полями) и TokenAuthentication:


public class TokenAuthentication implements Authentication {
    private String token;
    private Collection

https://habrahabr.ru/post/332482/


Метки:  

[Перевод] Рефакторинг кода в обеденный перерыв: знакомство с сodemod-скриптами

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


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


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


За последние годы JavaScript изменился до неузнаваемости. Развитие этого языка привело к тому, что была изменена даже простейшая задача по объявлению переменных. В ES6 появились let и const, стрелочные функции и множество других новшеств, каждое из которых приносит пользу разработчикам.


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


Codemod


Codemod – это инструмент, разработанный Facebook для рефакторинга больших кодовых баз. Он позволяет разработчику реорганизовать большой объём кода за небольшой промежуток времени. Для небольших задач по рефакторингу вроде переименования класса или переменной разработчик использует IDE, такие изменения обычно затрагивают только один файл. Следующим инструментом для рефакторинга является глобальный поиск и замена. Часто он может работать с использованием сложных регулярных выражений. Но такой метод подходит не для всех случаев.


Codemod написан на Python, он принимает ряд параметров, включая выражения для поиска и замены.


codemod -m -d /code/myAwesomeSite/pages --extensions php,html \
    '(.*?)' \
    '\2'

В приведённом примере мы заменяем на с использованием встроенного стиля для указания цвета. Первые два параметра – это флаги, указывающие на необходимость поиска нескольких совпадений (-m), и каталог для начала обработки (-d /code/myAwesomeSite/pages). Мы также можем ограничить обрабатываемые расширения (-extensions php, html). Затем мы предоставляем выражения для поиска и замены. Если выражение для замены не указано, будет предложено ввести его во время выполнения. Инструмент работает нормально, но он очень похож на существующие инструменты для поиска и замены с использованием регулярных выражений.


jscodeshift


jscodeshift следующий в наборе инструментов для рефакторинга. Он также разработан Facebook и предназначен для обработки нескольких файлов Codemod-скриптом. Будучи модулем Node.js, jscodeshift предоставляет простой и удобный API, а «под капотом» использует Recast, являющийся инструментом преобразования AST-to-AST (Abstract Syntax Tree).


Recast


Recast – это модуль Node.js, который предоставляет интерфейс для парсинга и перегенерации JavaScript-кода. Он может анализировать код в виде строки и генерировать из него объекты, соответствующие структуре AST. Это позволяет разработчикам проверять код для таких шаблонов, как, например, объявление функций.


var recast = require("recast");

var code = [
    "function add(a, b) {",
    "  return a + b",
    "}"
].join("\n");

var ast = recast.parse(code);
console.log(ast);
//output
{
    "program": {
        "type": "Program",
        "body": [
            {
                "type": "FunctionDeclaration",
                "id": {
                    "type": "Identifier",
                    "name": "add",
                    "loc": {
                        "start": {
                            "line": 1,
                            "column": 9
                        },
                        "end": {
                            "line": 1,
                            "column": 12
                        },
                        "lines": {},
                        "indent": 0
                    }
                },
        ...........    

Как видно из примера, мы передаём строку кода с функцией, которая складывает два числа. Когда мы парсим строку и распечатываем получившийся объект, то можем видеть AST: видим FunctionDeclaration, имя функции и т. д. Так как это просто JavaScript-объект, то мы можем изменить его как угодно. Затем можно вызвать функцию print для возврата обновлённой строки кода.


AST (Abstract Syntax Tree)


Как упоминалось ранее, Recast строит AST из строки кода. AST – это древовидное представление абстрактного синтаксиса исходного кода. Каждый узел дерева представляет собой конструкцию в исходном коде. ASTExplorer – это онлайн-инструмент, который поможет разобрать и понять дерево вашего кода.
С помощью ASTExplorer можно просмотреть AST простого примера кода. Объявим константу с именем foo и присвоим ей строковое значение ‘bar’.


const foo = 'bar';

Это соответствует такому AST:



В массиве body есть ветвь VariableDeclaration, которая содержит нашу константу. Все VariableDeclarations имеют атрибут id, который содержит важную информацию (имя и т. д.). Если бы мы создавали Codemod-скрипт для переименования всех экземпляров foo, то использовали бы этот атрибут и перебирали бы все экземпляры, чтобы изменить имя.


Установка и использование


Используя инструменты и приёмы, рассмотренные выше, мы можем воспользоваться всеми преимуществами jscodeshift. Поскольку, как мы знаем, он является модулем Node.js, можно установить его для проекта или глобально.


npm install -g jscodeshift

После установки мы можем использовать имеющиеся Codemod-скрипты совместно с jscodeshift. Нужно предоставить некоторые параметры, которые укажут jscodeshift, чего мы хотим достичь. Базовый синтаксис – это вызов jscodeshift с указанием пути к файлу или файлам, которые требуется преобразовать. Важным параметром является местоположение скрипта преобразования (-t): это может быть локальный файл или URL-адрес файла Codemod-скрипта. По умолчанию jscodeshift ищет скрипт преобразования в файле transform.js в текущем каталоге.


Другими полезными параметрами являются пробный прогон (-d), который будет применять преобразование, но не станет обновлять файлы, и параметр -v, который выведет всю информацию о процессе преобразования. Скрипты преобразования – это Codemod-скрипты, простые модули JavaScript, которые экспортируют функцию. Эта функция принимает следующие параметры:


  • fileInfo
  • api
  • options

Параметр fileInfo хранит всю информацию о текущем файле, включая путь и источник. Параметр api – это объект, который обеспечивает доступ к вспомогательным функциям jscodeshift, таким как findVariableDeclarators и renameTo. Наконец, параметр – это опции, которые позволяют передавать параметры из командной строки в Codemod. Например, если мы хотим добавить версию кода ко всем файлам, то можем передать её через параметры командной строки jscodeshift -t myTransforms fileA fileB --codeVersion = 1.2. В этом случае параметр options будет содержать {codeVersion: '1.2'}.


Внутри функции, которую мы экспортируем, нужно вернуть преобразованный код в виде строки. Например, если у нас есть строка кода const foo = 'bar', и мы хотим преобразовать её, заменив const foo на const bar, наш код будет выглядеть так:


export default function transformer(file, api) {
  const j = api.jscodeshift;

  return j(file.source)
    .find(j.Identifier)
    .forEach(path => {
      j(path).replaceWith(
        j.identifier('bar')
      );
    })
    .toSource();
}

Здесь мы объединяем ряд функций в цепочку вызовов и в конце вызываем toSource() для генерации преобразованной строки кода.


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


Существующие Codemod-скрипты


В большинстве случаев разработчикам не нужно писать собственный код – многие типовые действия по рефакторингу уже были превращены в Codemod-скрипты. Например, js-codemod no-vars, который преобразуют все экземпляры var в let или const в зависимости от использования переменной (в let – если переменная будет изменена позже, в const – если переменная никогда не будет изменена).


js-codemod template-literals заменяют конкатенацию строк шаблонными строками, например:


const sayHello = 'Hi my name is ' + name;
//after transform
const sayHello = `Hi my name is ${name}`;

Как пишутся Codemod-скрипты


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


const updatedAnything = root.find(j.VariableDeclaration).filter(
            dec => dec.value.kind === 'var'
        ).filter(declaration => {
            return declaration.value.declarations.every(declarator => {
                return !isTruelyVar(declaration, declarator);
            });
        }).forEach(declaration => {
            const forLoopWithoutInit = isForLoopDeclarationWithoutInit(declaration);
            if (
                declaration.value.declarations.some(declarator => {
                    return (!declarator.init && !forLoopWithoutInit) || isMutated(declaration, declarator);
                })
            ) {
                declaration.value.kind = 'let';
            } else {
                declaration.value.kind = 'const';
            }
        }).size() !== 0;
    return updatedAnything ? root.toSource() : null;

Этот код является ядром скрипта no-vars. Во-первых, фильтр запускается на всех переменных VariableDeclaration, включая var, let и const, а возвращает только объявления var, которые передаются во второй фильтр, вызывающий пользовательскую функцию isTruelyVar. Она используется для определения характера var (например, var внутри замыкания, или объявляется дважды, или объявление функции, которое может быть поднято) и покажет, безопасно ли делать преобразование этой var. Каждая var, которую возвращает фильтр isTruelyVar, обрабатывается в цикле foreach.


Внутри цикла выполняется проверка, находится ли var внутри цикла, например:


for(var i = 0; i < 10; i++) {
    doSomething();
}

Чтобы определить, находится ли var внутри цикла, можно проверить родительский тип.


const isForLoopDeclarationWithoutInit = declaration => {
        const parentType = declaration.parentPath.value.type;
        return parentType === 'ForOfStatement' || parentType ===     'ForInStatement';
    };

Если var находится внутри цикла и не меняется, то её можно заменить на const. Проверка может быть выполнена путём фильтрации по узлам var AssignmentExpression и UpdateExpression. AssignmentExpression покажет, где и когда var была инициализирована, например:


var foo = 'bar';
UpdateExpression покажет, где и когда var была обновлена, например:
var foo = 'bar';
foo = 'Foo Bar'; //Updated

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


Команда Facebook также добавила несколько Codemod-скриптов для обновления синтаксиса React и обработки изменений в React API. Например, react-codemod sort-comp, который сортирует методы жизненного цикла React для соответствия правилу ESlint sort-comp.


Последним популярным Codemod-скриптом React является React-PropTypes-to-prop-types, помогающий справиться с недавним изменением React, в результате которого разработчикам требуется установить prop-types для продолжения использования PropTypes в компонентах React версии 16. Это отличный пример использования Codemod-скриптов. Метод использования PropTypes не увековечен в камне.


Верны все следующие примеры.


Импортируем React и получаем доступ к PropTypes из импорта по умолчанию:


import React from 'react';

class HelloWorld extends React.Component {

    static propTypes = {
        name: React.PropTypes.string,
    }
    .....

Импортируем React и делаем именованный импорт для PropTypes:


import React, { PropTypes, Component } from 'react';

class HelloWorld extends Component {

    static propTypes = {
        name: PropTypes.string,
    }
    .....

И еще один вариант для для stateless компонента:


import React, { PropTypes } from 'react';

const HelloWorld = ({name}) => {
    .....
}

HelloWorld.propTypes = {
    name: PropTypes.string
};

Наличие трёх способов реализации одного и того же решения затрудняет применение регулярного выражения для поиска и замены. Если бы в нашем коде были все три варианта, мы могли бы легко перейти к новому паттерну PropTypes, выполнив:


jscodeshift src/ -t transforms/proptypes.js

В этом примере мы взяли PropTypes Codemod-скрипт из репозитория react-codemod и добавили его в каталог transforms в нашем проекте. Скрипт добавит import PropTypes from 'prop-types'; для каждого файла и заменит все React.PropTypes на PropTypes.


Выводы


Facebook начал внедрять поддержку кода, позволяя разработчикам адаптироваться под её постоянно меняющиеся API и практические подходы работы с кодом. Javascript Fatigue стала большой проблемой, и, как мы увидели, инструменты, помогающие в процессе обновления существующего кода, во многом способствуют её решению.


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


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


В этом посту мы рассмотрели природу Cdemod-скриптов и jscodeshift и то, как быстро они могут обновлять сложный код. Начав с Codemod и перейдя к таким инструментам, как ASTExplorer и jscodeshift, можно научиться создавать Codemod-скрипты в соответствии со своими потребностями. А наличие широкого спектра готовых модулей позволяет разработчикам активно продвигать технологию в массы.


Примечание переводчика: на эту тему было интересное выступление на JSConfEU.


Смотреть видео


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

https://habrahabr.ru/post/332402/


Метки:  

5 бесплатных ассетов для Unity3D, которые облегчат процесс разработки

Среда, 05 Июля 2017 г. 14:01 + в цитатник
Недавно мы выпустили обзор некоторых Unity ассетов для начинающего 2D разработчика.
Сегодня предлагаем вашему вниманию подборку из 5 бесплатных ассетов для Unity3D, максимально простых в использовании и полезных в работе. Данные ассеты призваны упростить некоторые аспекты разработки, а также сэкономить вам время за счет автоматизации определенных нудных задач.



Autosaver

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

Для того чтобы просмотреть параметры сохранения, зайдите в File/Preferences/Autosave
В меню «Настройки» доступны следующие параметры:

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




PlayersPrefs Editor and Utilities

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

PlayersPrefs Editor and Utilities включает в себя поддержку шифрования для защиты от случайного взлома. Для записи и чтения шифрованных данных используйте следующий код:



Окно редактора PlayersPrefs выглядит так:



И вишенка на торте: через класс PlayerPrefsUtility можно записывать значения Bool, DateTime, TimeSpan, Enum:



Simple Note

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

Чтобы свести такие ситуации к минимуму, на помощь приходит Simple Note. Ассет предназначен для создания заметок прямо в редакторе. Эта возможность особенно ценна, если разработку одновременно ведут двое и более человек.

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

Функционал Simple Note включает:

1. Глобальный редактор заметок SimpleNote
Здесь можно добавлять и редактировать общие заметки. Окно вы найдете в меню Window/SimpleNote/ShowNotes



2. Заметки для GameObject – отображаются в окне Scene, когда объект выделен:



Добавить заметку непосредственно на нужный объект можно через меню GameObject/SimpleNote/Add Or Remove Note.

3. Заметки для скриптов в инспекторе:



Для использования нужно добавить атрибуты:



Также в меню File/Preferences/SimpleNote есть возможность задать следующие настройки для отображения заметок:

  • Отступ от края, сторона отображения заметки в окне Scene
  • Цвет отображения заметок




Inspector Navigator

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

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

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



Ez Files Renamer

Ez Files Renamer поможет держать имена объектов в чистоте и порядке.

Просто выделите нужные объекты в окне иерархии или проекта, заполните строку New Name – и готово! Кроме того, можно добавлять префиксы и выбирать знак разделяющий имя с префиксом. Пронумеруйте объекты, установите знак разделения для нумерации. Это прекрасно работает как в окне иерархии, так и в окне самого проекта и не отанимает много времени.

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

Для того чтобы открыть окно Ez Files Renamer, пройдите по следующему пути: Window/BDOAssets/ EzFilesRenamer



Вот те инструменты, полезность которых мы оценили на практике. Если у вас в арсенале тоже есть полезные ассеты, которые помогут сделать работу над проектами удобнее, поделитесь ими в комментариях.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332172/


Метки:  

[Перевод] Чтобы ваша культура вмещала всех, попробуйте работать меньше

Среда, 05 Июля 2017 г. 13:25 + в цитатник
Моя первая работа в области разработки ПО заключалась в программировании на С++ для компании J.D. Edwards, которая сейчас является частью Oracle. Я проработал там с 1996 по 2000 год. Она настолько отличается от любой работы, на которой я был с того времени, с настолько разных сторон, что я всегда отношу ее к короткой “доинтернетной” фазе моей карьеры. Но есть такой момент – команда, в которой я работал, была самой разнообразной из тех, в которых я работал. А может даже из тех, с которыми лишь приходилось иметь дело, в рамках всей нашей отрасли.

Почему? Думаю, у меня есть ответ.

Культура J.D. Edwards и стандарты рабочего пространства были заимствованы напрямую из IBM. Пиджак и галстук обязательны для мужчин. Каждый день. Можно было оставить пиджак на спинке стула в кубикле всю неделю, уезжать домой и приезжать обратно в рубашке, но если ты не забрал пиджак домой на выходные и не менял его каждую неделю, тебе бы указали на это. Если ты начал появляться на работе в 9 вместо 8:30, на это обязательно бы указали. Ништяки? Бесплатная газировка. Пятницы в стиле кэжуал неохотно вводились лишь под давлением интернет бума, потому что иначе становилось труднее нанимать людей. Я любил мою работу и ненавидел дресс-код и режим.

Мои друзья-хипстеры нанимались в интернет-стартапы и носили джинсы, кроссовки и футболки с ироническими рисунками и надписями. Их офисы были в новом хип-районе в центре, с пинг-понгом и настольным футболом (бесплатные обеды еще только дело будущего). Они дружили со всеми своими коллегами, появлялись на работе в 10:00 и обычно заваливались в бар все вместе сразу после работы. Мне было очень завидно… но за разницей в дресс коде я не увидел различий в разнообразии в команде.

Я уже сказал ранее, что до сегодняшнего дня моя команда в J.D. Edwards была самой разнобразной, в которой я работал. Мой первый босс был иммигрантом из Африки, вторым боссом была женщина «мамочка сорок с чем-то». В нашей команде степень разнообразия была высоким по всем параметрам – пол, раса, религия, возраст, наличие детей, происхождение, сексуальная ориентация, инвалидность, статус ветерана. Это была очень талантливая и трудолюбивая группа. В то время я не знал других команд, поэтому это не казалось мне чем-то из ряда вон выходящим.

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

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

Они все были белыми, молодыми, у них не было детей, большинство из них были мужчинами. Женщины были в HR или в отделе качества (QA), или создавали контент. Менеджеры по разработке, были, в основном, белыми мужчинами немного постарше. Менеджерами по качеству были белыми женщинами, тоже слегка старше.

Тьфу.

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

Я уже не работал там в момент, когда крах доткомов раскидал нас кого-куда. Моя «настоящая» карьера в отрасли началась уже после, то есть J.D. Edwards и эта другая компания всегда казались мне прелюдией к тому, что я не очень-то успел осознать. Вчера все поменялось.

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

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

Я увидел преимущества концепции «строго бизнес» в те семь лет, что был в Fog Creek Software и ее дочерней компании, Trello.

Я перешел в Fog Creek в 2008, из Google New York, где я работал до этого пять лет. Google NY имел смешанную корпоративную культуру: культуру продаж и техническую, от вас ожидали приходить на работу в 10, работать до 8, потом заваливаться в бар со своими коллегами. Работа в такой компании, о которой все говорят, будоражила, нравилось ощущение что, что мы были частью чего-то очень большого. Иногда я работал сумасшедшее количество часов, путешествовал по всему миру. Это было здорово. У меня до сих пор осталось много хороших друзей с того времени. Я не говорю, что в Google NY не было разнообразия, как в той интернет-компании, упомянутой выше, но образ жизни был всепоглощающим. В первую очередь, мы были гуглерами.

Когда я пришел в Fog Creek, нас было всего с десяток. У меня был культурный шок. Там было некоторое количество парного программирования, но не так много разговоров «у кулера». Все разрабы собирались на обед в полдень, потом шли обратно в свои офисы и закрывали двери. В 5:00 каждый вставал и уходил. Я был в абсолютном замешательстве. Я пробыл в той всепоглощающей среде настолько долго, что был немного разочарован таким внезапным ограничением роли работы в моей жизни.

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

«Ты знаешь, как мы называем люлей, которые работают после 5 вечера?», спросил он.

«Как?»

«Болваны.»

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

В то время, Fog Creek был маленьким и не имел большого разнообразия. Через годы, мы выросли и создавали продукты, запускали отдельные компании, всегда придерживаясь разумного графика, стараясь все делать профессионально.

Где-то в 2011 году, запахло переменами. Люди в отрасли были недовольны недостатком разнообразия. Пост в блоге нашей компании, «Girls Go Geek, Again», стал самым читаемым и самым расшариваемым в нашей истории (насколько я знаю, он остается в топ-3). Мы сильно хотели построить разнообразие при помощи нашего процесса найма: начали с нашей программы стажировки, которую так много заимствуют (она же является первым этапом при найме на полный день). Нет, мы не стали более разнообразными без усилий, многие люди проделали очень тяжелую работу по расширению нашего процесса найма и нам пришлось стать очень креативными, чтобы построить разнообразие в нашем офисе.

Та статья, ссылку на которую я только что дал – хороший пример. Когда мы хотели стать «более разнообразными» при помощи набора и обучения выпускниц из Flatiron School, мы просто это сделали, потому что нам не пришлось сначала становиться «более вмещающими».

Это было потому, что наша культура была сосредоточена на бизнесе в разработке: как ПО разрабатывается, продается и поддерживается. Если вы в восторге от этого, вы автоматически принадлежите ей. Вам не нужно задерживаться допоздна, пить алкоголь, играть в «Rock Band», играть в настольные игры, не иметь необходимость забирать детей, ходить в церковь, не ходить в церковь или делать что то еще, кроме того, чтобы работать с 9 до 5 и заботиться о выпуске хорошего ПО.

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

Я не агитирую за возвращение формализма в стиле IBM. Но я думаю, что мы что-то упустили, когда выкинули из отрасли галстуки и надели футболки.

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

Мне тут напомнили, про идею, стоящую за «Getting to Yes» (прим. переводчика: имеется в виду книга «Переговоры без поражений» Роджера Фишера) – классической работой по переговорам. Идея в том, что на переговорах, если вы ограничиваете количество пунктов, по которым заинтересованным сторонам нужно договориться, вы увеличиваете шансы придти к соглашению. Вы отбрасываете в сторону свои желания, в пользу прихода к соглашению, просто фокусируясь на своих нуждах. Это выглядит очевидным при взгляде назад, но это действительно произвело революцию в деловом мире.

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

Но, быть может, это имеет свою цену. Если мы отбросим такое желание и сфокусируемся на том, чего мы хотим реально достичь – делать хорошее ПО – может быть, мы откроем для себя новые возможности. Ограничивая количество пунктов, по которым нам надо придти к соглашению и количество часов, которые нам надо потратить для этого, мы естественным образом открываем для себя разнообразный мир талантливых людей.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332478/


Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 1038 1037 [1036] 1035 1034 ..
.. 1 Календарь