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

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

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

Быстрое восстановление данных. Чем нам помогут LRC?

Четверг, 08 Июня 2017 г. 16:38 + в цитатник


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

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

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

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

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

Доступность данных


Технология RAID (Redundant Array of Independent Disks) применяется в системах хранения данных для обеспечения высокой скорости доступа к данным и отказоустойчивости. Высокая скорость достигается за счет распараллеливания процессов чтения и записи данных на диски, а отказоустойчивость — за счет применения помехоустойчивого кодирования.

С течением времени требования к объему и надежности систем хранения увеличивались. Это привело к появлению новых уровней RAID (RAID-1...6, RAID-50, RAID-60, RAID-5E и т.д.) и применению разных классов помехоустойчивых кодов, как MDS (Maximum distance separable — коды с максимальным кодовым расстоянием), так и не-MDS.

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

Availability (доступность) — это вероятность того, что система будет доступна по запросу. Высокая доступность достигается, в частности, за счет кодирования, т.е. часть дискового пространства системы отводится не под пользовательские данные, а для хранения контрольных сумм. В случае отказа дисков системы утраченные данные могут быть восстановлены с помощью этих контрольных сумм — тем самым обеспечивается доступность данных. Как правило, availability рассчитывается по формуле:

$Availability=\frac{MTTF}{MTTF+MTTR}$


MTTF — Mean Time To Failure (средняя наработка до отказа), MTTR — Mean Time To Repair (среднее время восстановления). Чем меньше время, необходимое для восстановления определенного компонента системы, в данном случае – диска или кластерного узла, тем выше доступность данных.

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

Каждый из вариантов организации хранения данных и расчета контрольных сумм имеет свои преимущества и недостатки. Например, коды Рида-Соломона (RS codes) обеспечивают высокую отказоустойчивость. RS-коды являются кодами с максимальным кодовым расстоянием (MDS) и представляются оптимальными с точки зрения избыточного места под хранение контрольных сумм. Недостаток RS-кодов состоит в том, что они достаточно сложны с точки зрения кодирования и требуют очень много чтений для восстановления отказа.

Среди других возможных решений — модифицированные Rotated RS-коды или WEAVER codes (разновидность XOR-кодов). Последние достаточно просты с точки зрения кодирования и требуют очень мало чтений для восстановления отказа. Однако при этом способе кодирования под контрольные суммы требуется выделить гораздо больший, чем при MDS-кодах, объем хранилища.

Хорошим решением указанных выше проблем стало появление LRC (Local Reconstruction Codes). В работе «Erasure Coding in Windows Azure Storage» проводится детальное описание этих кодов, которые, по сути, являются преобразованием RS-кодов в не-MDS. В этой же работе проводится сравнение LRC с другими кодами и показаны преимущества LRC. В данной статье мы рассмотрим, как влияет расположение блоков LRC-страйпов на скорость восстановления.

Проблемы использования LRC в RAID


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

Если данные этого страйпа закодированы RS кодом, как это, например, делается в RAID-6 с двумя контрольными суммами, то кодовую информацию содержат два блока страйпа. На рис. 1 сверху представлен страйп из 19 блоков, среди которых 2 блока $S_1$ и $S_2$ — контрольные суммы. При отказе диска, содержащего, например, блок с номером 2, для восстановления этого блока необходимо будет прочитать 17 блоков из каждого страйпа (16 не отказавших и одну контрольную сумму).

Коды локальной реконструкции в данном случае потребуют разбиения страйпа на несколько локальных групп, для каждой из которых рассчитывается локальная контрольная сумма (local syndrome). Для всех блоков данных также рассчитывается глобальная контрольная сумма. На рис. 1 рассмотрен пример, в котором блоки разбиты на 3 локальные группы размером 5. Для каждой из них рассчитаны локальные контрольные суммы $S_1, S_2,S_3$, а также рассчитана одна глобальная контрольная сумма G.


Рис. 1. Пример представления страйпа RAID6 и страйпа LRC

Локальные контрольные суммы вычисляются как XOR блоков данных, от которых они зависят. Глобальных контрольных сумм может быть несколько, они вычисляются как контрольные суммы RS кодов. В данном случае для восстановления блока с номером 2 необходимо прочитать 6 блоков. Это в 3 раза меньше по сравнению с предыдущим случаем, но на хранение контрольных сумм здесь потребуется больше места. Следует отметить, что в случае отказа 2 дисков одной группы, LRC легко преобразуется в классический RS при сложении (XOR) всех 3 локальных контрольных сумм.

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

Чтобы при восстановлении данных скорость восстановления не ограничивалась скоростью записи на один компонент системы хранения, в каждый страйп может быть добавлен так называемый Empty Block (E), как это делается в RAID-5E и RAID-6E. Таким образом, восстановленные данные в каждом страйпе записываются на свой empty block, а значит, и на отдельный диск. Наличие empty block в страйпе необязательно. В дальнейших наших рассуждениях мы будем рассматривать страйпы с таким блоком для полноты картины.


Рис. 2. Расположение блоков страйпа со сдвигом

Таким образом, при использовании циклического сдвига и наличии empty block расположение страйпов по дискам примет вид как на рис. 2.
Использование LRC также накладывает незначительное ограничение по количеству дисков, на которых может быть расположен страйп. Так, если количество локальных групп равно $k$, размер одной локальной группы равен $l$, количество глобальных контрольных сумм равно $g$ и наличествует empty block, то общий размер страйпа будет равен $kl+g+1$. Если число дисков отличается от длины страйпа, то возможны два варианта:

  1. Создавать локальные группы разного размера. В таком случае некоторые локальные контрольные суммы будут чаще обновляться при изменении данных страйпа, что может привести к более медленной записи.
  2. Не размещать каждый страйп на все диски, а там, где заканчивается один страйп, сразу начинать второй, см. рис. 3. Такой подход приводит к тому, что все локальные группы могут быть одинакового размера, и циклическое смещение вносится автоматически сообразно расположению страйпов. Если длина страйпа совпадает с количеством дисков, то для каждого страйпа выполняется циклический сдвиг, как это делается для RAID-6.


Рис. 3. Блоки, необходимые для восстановления одного отказавшего диска

На рис. 3 рассмотрен случай отказа одного диска — $D_7$. Розовым цветом обозначены все блоки, которые необходимо прочитать, чтобы восстановить его.


Рис. 4. Количество блоков, прочитанное с каждого диска для восстановления одного отказавшего диска

Всего потребовалось прочитать 105 блоков. Если бы вместо LRC использовался RAID-6, то необходимо было бы 340 прочитанных блоков. Чтобы понять, является ли такое расположение блоков оптимальным, посчитаем количество прочитанных с каждого диска блоков, см. рис. 4.

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

Рандомизированные алгоритмы для дисков большого объема


Оставляя в стороне различные способы решения аналогичной проблемы для RAID-6, рассмотрим возможный сценарий в случае с LRC:

  1. Для каждого LRC-страйпа берем классическое расположение блоков (аналогично рис. 1). Используем номер выбранного страйпа в качестве инициализирующего значения (seed) для генератора случайных чисел. Для всех страйпов используется один и тот же генератор случайных чисел, но с разным seed.
  2. Используя инициированный генератор случайных чисел и исходное расположение блоков, получим случайное расположение блоков в текущем страйпе. В нашем случае был применен алгоритм Fisher–Yates shuffle.
  3. Такую процедуру выполняем для каждого страйпа.

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

Введем обозначения: $V$ — объем каждого диска в массиве, $s$ — размер одного блока страйпа, $N$ — длина одного страйпа, $n$ — количество дисков, $l$ — размер локальной группы. $k$ — количество локальных групп, $g$ — количество глобальных контрольных сумм. Тогда математическое ожидание средней загруженности каждого диска будет рассчитываться следующим образом:

$M(D_i)=\frac{Vk(l-1)(l+g)}{s(n-1)} $


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

Тестирование производительности


Для тестирования производительности мы создавали RAID из 22 дисков с различными схемами размещения. RAID-устройство создавалось при помощи модификации device-mapper, которая меняла адресацию блока данных по определенному алгоритму.

На RAID записывались данные, для которых выполнялся расчет контрольных сумм в целях последующего восстановления. Выбирался отказавший диск. Выполнялось восстановление данных либо на соответствующие empty blocks, либо на hot spare disk.

Мы сравнили следующие схемы:
  • RAID-6 — классический RAID-6 с двумя контрольными суммами; восстановление данных на hot spare disk;
  • RAID-6E — RAID6 c empty блоком в конце страйпа; восстановление данных на empty blocks соответствующих страйпов;
  • Classic LRC+E — LRC-схема, в которой локальные группы идут последовательно и заканчиваются контрольной суммой (см рис. 3); восстановление на empty block;
  • LRC rand — для генерации каждого LRC-страйпа, его номер используется в качестве ядра генератора случайных числе, восстановление данных на empty block.

Для тестирования использовались 22 диска со следующими характеристиками:
  • MANUFACTURER: IBM
  • PART NUMBER: ST973452SS-IBM
  • CAPACITY: 73GB
  • INTERFACE: SAS
  • SPEED: 15K RPM
  • SIZE FORM FACTOR: 2.5IN

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

Поскольку конкретные значения скорости восстановления данных могут зависеть от модели жестких дисков, производителя, RPM и др., мы представили полученные результаты в относительных величинах. На рис 5. продемонстрирован прирост производительности в рассматриваемых схемах (RAID6 c empty блоком, Classic LRC, LRC rand) в сравнении с классическим RAID-6.


Рис. 5. Относительная производительность различных алгоритмов размещения

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


Рис. 6. Избыточность различных алгоритмов

Заключение


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

Помехоустойчивое кодирование при помощи LRC способствует существенному снижению избыточности в хранилище по сравнению с репликацией. Схемы кодирования, отличающиеся от кодов Рида-Соломона, на практике чаще всего исследуются в контексте LRC. Xorbas — реализация LRC в HDFS — потребовала увеличения избыточности на 14% по сравнению с RS-кодированием. Скорость восстановления при этом увеличилась на 25-45%. Количество чтений и пересылок по сети также значительно сократилось. Для дальнейшего изучения оптимальных LRC советуем обратиться к работе «A Family of Optimal Locally Recoverable Codes» (Itzhak Tamo, Alexander Barg).

Использованные источники:
  • Hafner, J. L., WEAVER Codes: Highly Fault Tolerant Erasure Codes for Storage Systems, FAST-2005: 4th Usenix Conference on File and Storage Technologies
  • Khan, O., Burns, R., Plank, J. S., Pierce, W., Huang, C. Rethinking Erasure Codes for Cloud File Systems: Minimizing I/O for Recovery and Degraded Reads, FAST-2012: 10th Usenix Conference on File and Storage Technologies
  • Huang, C., Simitci, H., Xu, Y., Ogus, A., Calder, B., Gopalan, P., Li, J., Yekhanin, S., Erasure Coding in Windows Azure Storage, USENIX Annual Technical Conference
  • M. Sathiamoorthy, M. Asteris, D. Papailiopoulos, A. G. Dimakis, R. Vadali, S. Chen, and D. Borthakur. XORing Elephants: Novel Erasure Codes for Big Data. In Proceedings of the VLDB Endowment, volume 6, pages 325–336. VLDB Endowment, 2013.
  • Itzhak Tamo, Alexander Barg. A Family of Optimal Locally Recoverable Codes. arXiv preprint arXiv: 1311.3284, 2013.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330530/


Метки:  

Как я участвовал в хакатоне Angular Attack, и что из этого вышло

Четверг, 08 Июня 2017 г. 16:26 + в цитатник
Привет, друзья. Меня зовут Алексей, я работаю фронтенд-разработчиком в Санкт-Петербургском офисе компании Wrike, и сегодня я хочу рассказать про то, как я поучаствовал в хакатоне AngularAttack, где моя работа Sherlock в итоговом протоколе заняла первое место.

О том, что это и как начиналось


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

Условия хакатона элементарны. Все происходит удаленно. Старт – в полночь по Гринвичу в субботу, финиш – в полночь в понедельник, в команде от 1 до 4 человек, до старта эвента никакого электронного контента создавать нельзя (ни кода, ни ассетов), хотя рисовать на бумажке блок-схемы и придумывать алгоритмы – сколько угодно. Каждому участнику выдается приватный репозиторий на GitHub, в который он кладет код в процессе написания. Обязательное условие – на выходе должно быть web-приложение с использованием фреймворка Angular. Свободно распространяемый контент и библиотеки в своем приложении использовать можно с соблюдением условий лицензии (например, ссылка на автора). Все.

А вот чего бы этакого написать?


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

  • Оно должно быть простым в использовании – работ будет много, судьи – обычные люди, и, если человек за пару десятков секунд не поймет, как пользоваться приложением, он скорее всего не будет разбираться дальше.
  • Оно должно быть несложным в разработке. Я собирался участвовать в одиночку, и идея должна быть такова, чтобы банально успеть ее реализовать за эти 48 часов. Поэтому всякие мысли про бэкенд и прочее отпали сразу – только single page app, только фронт, только чистый Angular.
  • Оно должно быть не очень банальным – нужно, чтобы идея цепляла. Опять же – судьи оценивают не крутость кода, а работу и внешний вид. Поэтому можно написать игру “виселица” (как кстати, многие и сделали), но человек, сыграв в нее раз, больше никогда в игру не вернется (а одним из критериев оценки является так называемый Utility/Fun – насколько работа полезна, прикольна, и, в общем, вызывает желание пользоваться ей вновь и вновь).

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

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



При старте игры некоторые элементы уже могут быть открыты (например, буква L в нижнем ряду доски – это означает, что она точно находится именно здесь). В клетках же, где правильный элемент еще точно не определен, показываются оставшиеся возможные варианты. К примеру, в каждой из остальных клеток нижнего ряда, исходя из текущей позиции, все еще возможны варианты из букв H, O, M, E и S.

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

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

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

Понеслась!, или немного про алгоритмы


В пятницу вечером, перед началом эвента настроил окружение. В качестве языка выбрал Google Dart – тут сомнений не было: несмотря на то, что основным трендом в разработке под Angular является TypeScript, практически весь фронтенд в нашей компании сейчас пишется именно на Дарте, и я решил не изобретать велосипед. Также выполнил настройки git-а и хостинга – в этом году организаторы не предоставляли место для размещения работ, рассчитывая, что каждый из участников сам решит этот вопрос. У меня хостинг был, и это не вызвало проблем, но, возможно, кому-то о таких вещах стоит знать заранее.

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

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

Для головоломки надо было сгенерировать: 1) правильную позицию на доске, 2) позицию, которая изначально открыта, и, самое главное, 3) набор подсказок, которые позволяют перевести открытую позицию в правильную. Причем, набор подсказок должен быть в идеале необходимым и достаточным – задача должна решаться, и при этом, единственным способом.

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

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

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

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

Графика? Все уже нарисовано до нас!


Для игровой доски требовались картинки, отвечающие условию: 6 наборов по 6 штук, каждый набор объединен определенным признаком. Сам бы я замучался их делать – к сожалению, именно в рисовании медведь оттоптал мне оба уха, руки, и все пальцы в придачу, включая те, которые на ногах. Но здесь выручил набор смайлов Emojione, которые с недавнего времени свободно входят в поставку Photoshop CC, на который у меня есть совершенно официальная подписка как часть плана Adobe для фотографов, так что условия лицензии соблюдены. Впрочем, без подписки, думаю, тоже все было бы в порядке: Emojione – свободно распространяемая библиотека.

Кстати, изображения, естественно, упаковал в спрайт использованием responsive backround sprites css — это позволило отображать картинки просто заданием класса для элементов, более того — при необходимости легко менять их размер. Про саму технологию написано уже немало — можно, например, почитать тут.


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

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

Штирлиц на грани провала


Воскресенье ушло на создание и вылизывание UI. Простейшая играбельная версия была готова где-то после полудня, но до комфортной игры было еще далеко – не было ни функциональности Undo, ни уведомлений о том, что позиция решена правильно/неправильно, ни уровней сложности. Первые две фичи были чисто техническими, а вот с последней, кстати, я поступил просто: сделал три уровня – легкий, средний и тяжелый, которые отличаются только количеством изначально открытых клеток. Для Easy это всегда 10, для Medium – 5, а вот на Hard – от нуля до двух. Да, в некоторых раскладах на харде изначально не открыто ни одной клетки. И более того – задача в этом случае тоже решается!

В какой-то момент я понял, что каждой подсказке обязательно нужен тултип, в котором будет подробно описано, что она из себя представляет, иначе судьям, незнакомым с игрой, будет крайне сложно понять, что означает весь этот пестрый набор картинок. Прошерстив в интернете имеющиеся библиотеки с компонентами для Angular Dart, остановился на Angular Material, в котором этот тултип имелся. Одна беда – библиотека была в бета-версии, которой в свою очередь, требовалась последняя бета Ангулара. Ну, где наша не пропадала – проапдейтил сборку со стабильного Angular 2.2.0 до беты 3.0.0, посмотрел, что вроде ничего не поломалось, и все работает как надо, обрадовался, и начал приделывать красивый тултип к подсказкам.

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


Теперь небольшое отступление, для тех, кто не знаком с языком Dart. Код, написанный на нем, не может исполняться в обычном браузере напрямую, его обязательно нужно скомпилировать в Javascript специальной командой. Но для разработки Google выпускает специальную версию браузера Chromium – Dartium, который содержит встроенную виртуальную машину, способную выполнять чистый дартовский код. Понятное дело, что вся разработка идет в этом специальном браузере – так значительно быстрее, а компилируется итоговая версия только тогда, когда ее нужно куда-то выложить.

Так вот – тултипы заработали, подумалось – самое время выложить промежуточную версию на внешний хостинг. Скомпилировал, залил на удаленный сервер, попытался открыть в Chrome – и был крепко удивлен тем, что приложение падает с ошибкой где-то глубоко в недрах Angular. Стектрейс ни о чем не говорил. Два часа назад, когда я заливал предыдущую версию, еще без тултипов, она отлично работала. Нескомпилированный код, запущенный в Dartium, тоже работал без проблем. А вот собранный – нет.

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

В качестве последней надежды около получаса читал профильные форумы – и на каком-то по счету внезапно обнаружил вопрос от участника с такой же, как у меня, проблемой. Более того, ему ответили – двадцать минут назад (!), посоветовав обновить сам Dart SDK на последнюю версию, вышедшую за несколько часов до этого.

Лихорадочно обновляю Dart на локальной машине, собираю пакет, выкладываю на сервер, проверяю – работает.

Выдыхаю – в этот раз просвистело мимо.

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

На финишной прямой…


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



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

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

…и неожиданный результат


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

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

Рабочая версия игры находится здесь: http://sherlock.netmafia.ru/ (крайне рекомендуется разрешение монитора Full HD).

Репозиторий с исходным кодом — тут: https://github.com/izolenta/sherlock, возможно, кому-то будет интересно познакомиться с языком Google Dart.

Спасибо за прочтение – и удачи!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330504/


Метки:  

Интервью с Яковом Шуваевым про команду инженеров, мотивацию и собеседования

Четверг, 08 Июня 2017 г. 16:26 + в цитатник
Одна из особенностей работы большого интегратора — в том, что все знают или примерно представляют, что именно этот интегратор делает и для каких клиентов. Последнее обычно доводится до сведения масс либо неброскими пресс-релизами, либо логотипом интегратора в списке партнеров заказчика. Но очень часто многие не догадываются, как именно проводятся подобные работы, и забывают, что за большим логотипом компании трудятся живые люди.
 
Мы постараемся немного изменить ситуацию – предлагаем вашему вниманию интервью с руководителем одного из технических отделов ЛАНИТ Яковом Шуваевым. Отдел специализируется на реализации решений в области построения надежной и безопасной программной инфраструктуры информационных систем, сервисов, обеспечивающих производственный цикл разработки, а также на всем, что касается баз данных и информационной безопасности.
 

 
Яков, расскажите немного о себе и вкратце о своем отделе. Чем вы занимаетесь и над чем работаете сейчас?
 
Начну, наверное, с учебы. Я из РУДН. Учился на физмате на специальности «Прикладная математика и информатика». Первые три курса учеба занимала все время, на четвертом появилось немного свободы, и я решил, что пора взяться за работу. Шел 2006 год. Было три варианта. Основной план был сходить в те компании, о которых были реальные отзывы от моих друзей. Таких вариантов было два, и первым в списке оказался ЛАНИТ. Мой однокурсник, который учился на параллельном потоке какое-то время там уже работал. Он и организовал мне мое первое в жизни собеседование в ИТ-компании. На этом собеседовании меня встретили мой непосредственный будущий руководитель, руководитель группы разработки и вице-президент компании, который тогда вице-президентом не был, а был простым руководителем проектов – они сидели в одном боксе в опенспейсе. В то время я слабо представлял себе, какие бывают роли в ИТ-компаниях, поэтому пошел на ту же позицию, что и мой однокурсник – «Разработчик-стажер». К слову сказать, если бы тогда я хотел заниматься тем, чем занимаюсь сейчас, у меня бы это не вышло – на тот момент в структуре подразделения была пара специалистов по базам данных, а админов и инженеров по безопасности не было в принципе. После того, как руководитель группы разработки выяснил, что про GWT, JEE и сборщик мусора я мало, что знаю, а мой опыт программирования сводится к написанию лабораторных в вузе и игры судоку на C# для КПК, он передал меня моему будущему руководителю. Мне выдали лист А4 с задачами на логику. Как потом выяснилось, все, кого собеседовали в отдел разработки, прошли через эти задачи.
 
Интересный факт. Не все знают, но физмат РУДН плотно обосновался в ЛАНИТ. Только в одном  подразделении, в котором работает Яков, трудятся еще 5 выпускников физмата РУДН.

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

Тогда


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

Я выяснил, что для того, чтобы система заработала быстро, надежно и безопасно, одного кода не достаточно. Плюс, как показала практика, если код работает у разработчика – это еще не значит, что его можно просто так взять и запустить в кластере.
 
Дальше больше. Были новые проекты, на которых я уже полностью переключился с разработки на администрирование. Так в проектах подразделения, в котором я работал, появились Linux, SVN и сервер непрерывной сборки в его текущем виде. Единственное – меня смущало, что я долго не мог найти в интернете подходящего описания моей ИT-роли в проекте и команде. Это было немного шире, чем системное администрирование, термин DevOps появился только в 2008 году, а на аббревиатуру SRE я тогда не наткнулся. В итоге, долго ломал голову над тем, чем же на самом деле занимаюсь. Это напрягало.
 
С этими мыслями я написал своему руководителю, после чего он предложил эту активность назвать «ИТ-инфраструктурой», а соответственно мою роль на проектах как «специалист по ИТ-инфраструктуре». Жизнь обрела смысл и понеслась…
 
Да и как сейчас уже понимаю, инфраструктурой на тот момент я занимался лучше, чем писал код.

DevOps и SRE


В 2009 году стартовал проект по разработке одного из государственных порталов. Производственный процесс стал резко меняться в соответствии с потоком и масштабом новых задач: росла команда, росло число тестовых стендов. Стенды нужно было создавать, поддерживать в актуальном состоянии, нужно было готовиться к запуску системы в промышленную эксплуатацию. Меня одного на все активности стало не хватать, и мы начали расширять штат «инфраструктуровщиков». Как я уже говорил, на тот момент в штате были специалисты по БД Oracle, которых не совсем было понятно к какой административной единице отнести: то ли к разработке, то ли к администрированию. В итоге решили, что их буду курировать я.
 
На момент образования сектора в нем работало 5 человек, включая меня.
 

К 2016 году наше подразделение открыло дополнительные региональные офисы в Челябинске, Перми, Саратове и Ижевске. «Собачка немного подросла», и в 2016 году наша команда стала распределенной – свыше 30 человек. Встал вопрос о ее трансформации в более крупную административную единицу подразделения – отдел.
 
Во время подготовки к этому нужно было решить очень «сложный» вопрос – как назвать отдел. С одной стороны, команду давно знали по таким ключевым словам как «инфраструктура» и «базы данных». С другой стороны, область нашей деятельности с 2010 года значительно расширилась, да и слово «инфраструктура» у многих ассоциируется с железом, сетью, ЦОДами – всем тем, чем профессионально занималось и занимается другое подразделение ЛАНИТ.
 

 
На собеседованиях, которые я провожу, рассказывая, чем занимается наш отдел, обычно рисую картинку в виде пирамиды, которая условно представляет уровни абстрактной информационной системы, начиная с железа, на котором все работает, и заканчивая прикладным ПО, которое разрабатывает наше подразделение. Верхний уровень «Прикладное ПО» – уровень, которым занимается отдел разработки. Здесь реализуется прикладная функциональность, которая нужна заказчику информационной системы.
 
Ниже – это уровни, которыми занимается наш отдел. Какие-то уровни пирамиды мы закрываем полностью, какие-то – частично. Под частичным закрытием я понимаю то, что сотрудники отдела как минимум должны понимать, что происходит и там, и там, чтобы решать основную задачу – сделать так, чтобы ПО работало быстро, надежно и безопасно.
 
Эти задачи можно решать, выстроив «инфраструктурный периметр» вокруг прикладного кода, но очевидно, что чаще всего это сделать невозможно, поэтому мы тесно взаимодействуем с командой разработки и командой, которая занимается железом, сетью и виртуализацией для достижения этих целей.
 
При этом нужно понимать, что «забора» с уровнем ПО в верхней части пирамиды и уровнем физики снизу нет. Как минимум, чтобы ответить на вопрос, нужно ли оптимизировать код, добавить железа или «докрутить» ОС, надо либо разбираться во всех этих уровнях, либо уметь правильно провести диагностику и сформулировать вопрос к тому, кто разбирается.
 
По структуре отдел делится на секторы. Первый сектор предоставляет услуги по эксплуатации информационных систем. Обычно это третий уровень поддержки, что означает, что команда в курсе того, что из себя представляет система, как она работает, какие задачи выполняет и принимает непосредственное участие в процессе разработки системы. Целями работы этой команды являются обеспечение надежной, быстрой и безопасной работы ППО в промышленной среде и обеспечение непрерывности процессов производства. Основные задачи, которые решает команда сектора, включают в себя: создание и настройку решений по автоматизации развертывания, инфраструктурный и бизнес-мониторинг, управление конфигурациями, управление облачными ресурсами, обеспечение надежности и все, что с этим связано. К 2017 году, в отличие от времени, когда все начиналось, прогрессивное человечество успело придумать термины, которыми можно максимально точно описать то, чем сейчас занимается сектор – это смесь элементов DevOps и SRE.
 

Базы


Чем еще занимался отдел?
 
Второе направление – это сервисы. Jira и Wiki система уже давно стали неотъемлемой частью производственного процесса практически любого проекта подразделения. Кроме того, на базе Jira, помимо проектных, автоматизируется много сервисов самого подразделения, начиная от заказа канцелярии и получения VPN-доступа для удаленной работы и заканчивая процессом приема на работу новых сотрудников.
 
Третье направление работы сектора – предоставление облачных вычислительных ресурсов и ресурсов по хранению данных проектным командам подразделения. Мы предоставляем услуги по организации аренды ресурсов у разных облачных провайдеров, таких как Amazon, Selectel, OnCloud и автоматизации подготовки тестовых окружений для проектов в облаках.
 
Второй сектор – это команда специалистов по базам данных. В начале своего пути команда специализировалась только на СУБД Oracle. Со временем ребята получили большой опыт работы с СУБД PostgreSQL, NoSQL БД RIAK и рядом продуктов, которые тем или иным образом связаны с базами данных. Например, тот же Delphix.
 
С расширением компетенций команды трансформировался и класс решаемых командой баз данных задач.
 
Новый класс задач потребовал использования новых инструментов?


 
Источник
 
Бывает по-разному. Иногда приходит задача, и ее надо срочно решить. Тут уже не важно, какими инструментами. Если оказывается, что в этот момент ты умеешь держать в руках только микроскоп, то и все задачи, включая “забивание гвоздей”, будешь решать микроскопом. Это, кстати, нормально, если заказчик хочет микроскоп, платит за микроскоп и за построенный с помощью микроскопа дом и в конце получает то, что хотел. Со стороны ситуация может выглядеть странно, но если заказчик доволен, то цель достигнута.
 
По очевидным причинам мы таких ситуаций стараемся не допускать. Чтобы решать задачи, делать проекты и не выглядеть при этом странно, важно до получения новой задачи или старта нового проекта быть в курсе того, что происходит вокруг тебя в отрасли. Знание широкого круга технологий и решений дает возможность объяснить заказчику, что микроскоп – это не лучшая в мире вещь, и предложить наиболее оптимальный для решения задачи вариант.
 
И как вы это делаете?
 
Стараемся быть в курсе :) Смотрим вебинары, ходим на конференции, организуем митапы. Если позволяют сроки, пытаемся на некоторых задачах использовать новые технологии, чтобы, когда придет время, иметь возможность предложить и их.
 

Безопасность и надежность


Понятно. Инфраструктура и базы данных – это все, чем вы занимаетесь или есть еще какие-то направления?
 
Есть. В 2015 году мы начали заниматься направлениями информационной безопасности и проектированием катастрофоустойчивых решений. Среди результатов можно отметить завершение проектирования схемы резервирования двух крупных государственных информационных систем. В одном проекте система резервируется на два дата-центра, во втором – на четыре.
 
Насколько мне известно, тот же Amazon позволяет это делать практически из «коробки». В чем сложность?
 
Amazon предоставляет такую возможность на уровне своей инфраструктуры или сервисов – смотря, чем вы пользуетесь. При этом, в зависимости от технологий, которые используются у вас на проекте, работать это будет хорошо только тогда, когда вы на уровне кода своей системы учитываете возможность «переезда» между дата-центрами. В противном случае результат будет мало предсказуемым. В нашем случае задача была придумать схему резервирования для уже много лет работающей системы, которая бы гарантировала заданные показатели RTO и RPO.
 
ОК. А что с безопасностью?
 
В любой стране есть законы и регламенты, которые требуют от определенного класса систем соответствовать некоторому набору требований. В России основными законами в этой области являются 149, 152 и 63 ФЗ и соответствующие им приказы различных ведомств. Так как в основном мы занимается государственными информационными системами, в которых могут обрабатываться персональные данные, а еще может использоваться электронно-цифровая подпись, то мы должны учесть требования всей этой нормативки. Из результатов могу отметить завершение работ по аттестации одной из информационных систем, которую разрабатывает наше подразделение, по требованиям ФСТЭК, мы провели сертификацию программного обеспечения, входящего в эту систему, и две оценки влияния по требованиям ФСБ.
 
Помимо обязательных по закону мероприятий, внутри подразделения мы проводим обучение коллег из других отделов, тестирования и разработки по вопросам информационной безопасности при производстве и эксплуатации систем.
 
И как в итоге звучит название отдела?
 
«Отдел инфраструктурных решений, сервисов и управления данными». Длинно, но отражает суть того, чем мы занимаемся.
 
Чем особенно гордишься за время работы?
 
Горжусь тем, что удалось собрать профессиональную команду, с которой можно решать задачи и которой я доверяю.

О мотивации


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

Про найм сотрудников

 
Существует ли, на ваш взгляд, кадровый голод в ЛАНИТ и в ИТ-сфере в целом? Какие специалисты нужны ЛАНИТ сегодня, чтобы решить поставленные перед компанией задачи? И что нужно сделать, чтобы молодежь оставалась работать в компании?
 
Хорошие вопросы. Сложности с наймом специалистов есть, но эта ситуация характерна для всего рынка – не только для ЛАНИТ. Так как проекты, над которыми работает наше подразделение, обычно не предполагают работу «отсюда и до обеда», список специалистов, которые нам подходят, сильно сужается.
 
Вариантов, как быть в такой ситуации, на мой взгляд, несколько.
 
Первый – классический. Можно искать нужных тебе людей, применяя классические HR-подходы, – долго, но результат на выходе всегда качественный. Многие могут со мной здесь поспорить, но я могу сказать о своем опыте. Наверное, мне везло с нашими HR-ами.
 
Можно еще искать людей в регионах, можно брать стажеров и прокачивать их под нужные вам задачи. Все три способа не сделают текущей команде хорошо прямо сейчас, но в перспективе решат задачу.
 
Второй – пиарить компанию на рынке, в соцсетях и привлекать тех, кто раньше даже и не задумывался о работе в ЛАНИТ. Про Яндекс, Avito, Mail.ru знают все, а что вы знаете про ЛАНИТ? Всегда задаю на собеседованиях этот вопрос.
 
И что отвечают?
 
Обычно, если приходят из интеграторов, то скорее всего что-то слышали, но не обязательно про проекты, которыми занималось именно наше подразделение. ЛАНИТ – это группа компаний, и каждая из них специализируется на чем-то. Кто-то космодромы строит, кто-то банкоматами занимается – разные направления есть. Остальные про нас либо не знают ничего, либо могут ответить что-то типа «Да, слышал… Это же вы госуслуги делаете?» :) И это при том, что ЛАНИТ который год входит в тройку крупнейших ИТ-компаний России, а проектами, которые реализовало только наше подразделение, пользуются по всей стране.
 
Главное — не зацикливаться на одном подходе и, к счастью, в этом плане мы активно движемся в нужном направлении. Проводим митапы, вышли на Хабр. Плюс сейчас набирает обороты стажерская программа, по которой мы ищем молодых ребят к себе для обучения и дальнейшего трудоустройства.
 
Стараемся быть в тренде.

Про удержание сотрудников


В тренде – это хорошо. А как дальше удерживать сотрудников?
 
Для начала, я бы хотел сказать, что никто никого силой не держит :) Для того, чтобы сотрудники не хотели уходить, должны быть созданы условия, с которыми было бы сложно расстаться. В первую очередь – это возможность заниматься любимым делом, далее – чтобы сотрудники чувствовали стабильность и перспективы роста в компании, третье – чтобы они могли развиваться на пользу себе и компании.
 
Чтобы этого достичь, во-первых, мне кажется важным, чтобы каждый сотрудник понимал, чем занимается и живет подразделение, в котором он работает. Если он этого не понимает, он не будет понимать, что и зачем он делает и частью чего он является.
 
Очевидно, что мы не стартап и не продуктовое подразделение, хотя у нас есть и свои программные продукты и внутренние стартапы. В первую очередь, мы – интегратор, который делает проекты. Большие и сложные проекты «под ключ». Что это означает на практике? Это значит, что мы реализуем полный производственный цикл создания информационных систем, начиная со сбора требований и заканчивая эксплуатацией и развитием уже функционирующих в продакшене систем. Сами проекты, над которыми мы работаем, социально значимые, важные для страны. Одно осознание от того, чем ты занимаешься и сколько людей пользуется результатом твоей работы, мотивирует очень сильно.
 
Во-вторых, каждый сотрудник должен понимать, какие возможности открывает для него работа в компании, какие у него есть варианты развития и возможности для этого.
 
В подразделении накоплен колоссальный опыт, который можно перенимать и развиваться с его помощью с бешеной скоростью. Уверен, существует не так много компаний и подразделений, которые могут поделиться теми знаниями и компетенциями, которыми обладают наши эксперты. Бери и учись!
 
С теорией понятно, а как на практике? Все прямо так и работает?
 
Ну… мы не идеальны, но стараемся идти в этом направлении. Большую часть этой теории можно тут же «пощупать» на практике. Динамика наших проектов такова, что, попав в круговорот выпуска очередного релиза какого-нибудь федерального «космолета» под конец года, можно за месяц получить опыта больше, чем в иной компании за год.
 

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

О собеседованиях


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



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

О наставничестве


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

О митапах


Для тех сотрудников, которым тесно в корпоративной Wiki, да и чего скрывать, для PR тоже, мы в прошлом году запустили цикл мероприятий #TechGuruDay, с Твиттером и каналом в Телеграм. Митапы проходят на площадке ЛАНИТ с живыми докладами по ИT-тематике. Наши сотрудники могут выступить в компании приглашенных внешних спикеров. Запустили в этом году блог на Хабре, в который могут писать все сотрудники. Кстати, пользуясь случаем, приглашаю всех, у кого есть интересная тема для митапа, пишите мне на сайте meetup.com – если тема будет как-то пересекаться с тем, что мы делаем, организуем совместный митап.
 
Поэтому, резюмируя, могу сказать, что причин не уходить от нас, как мне кажется, больше, чем уходить! Но, жизненные ситуации бывают разные, и от нас тоже уходят.  В этих случаях мы обычно очень грустим, но продолжаем работать дальше. Особенно, зная, что ушедшие сотрудники грустят вместе с нами и очень часто через какое-то время возвращаются назад.

О планах на будущее

 
Есть у  вас в планах запустить какие-то новые активности?
 
В этом году хочется провести больше митапов TechGuruDay, чем было в прошлом году, хочется рассказать что-нибудь интересное на какой-нибудь конференции.
 
Что можете пожелать своим коллегам?
 
Не стоять на одном месте, постоянно развиваться и двигать мир вперед!
 
Если прямо сейчас народ захочет попасть к тебе в команду, где им узнать про ваши «космолеты» и кто вам нужен?
 
Сейчас будет как последний слайд на какой-нибудь презентации с конференции с большой надписью «WE’RE HIRING».
 
Про «космолеты» можно задавать вопросы в комментариях. Если коротко, то ищем спецов по базам данных PostgreSQL и Oracle, инженеров со знанием ansible и python в команду DevOps/SRE, архитекторов и инженеров по безопасности. Причем, всех уровней. Ну, и, как у всех, у нас есть сайт с вакансиями, где все более подробно расписано.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330510/


Метки:  

Новые продукты и сервисы на выставке Citrix Synergy

Четверг, 08 Июня 2017 г. 16:16 + в цитатник
Свежее исследование, проведенное IDC, выявило, что в 2019 г. компании потратят $2,1 триллиона на технологии и сервисы, помогающие в реализации и управлении инициативами цифровой трансформации бизнеса. В каких направлениях будет происходить трансформация и какие инструменты необходимы для нее, читайте под катом.



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

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



Облачные среды


Агентство Gartner отмечает, что сегодня 40% своего бюджета компании тратят на облачные технологии (включая облачные сервисы). При этом 78% опрошенных компаний планируют увеличить эти расходы в 2017 г. Активное внедрение облачных технологий создает сложности для конечных пользователей, которые вынуждены применять несколько облачных сервисов, приложений и источников данных, не говоря уже о необходимости использования различных технологий доступа и нескольких наборов учетных данных. Теневые ИТ-ресурсы создают проблемы в виде использования несанкционированных приложений и инструментов, что усложняет обслуживание ИТ-комплекса и увеличивает риск нарушения информационной безопасности. Для поддержания производительности работы сотрудников Citrix представляет обновленную и защищенную цифровую рабочую среду , которая унифицирует доступ и управление мобильными приложениями, SaaS-, веб-, Windows-приложениями и документами, а также консолидирует доступ, контроль и рабочие процессы в одном решении. С помощью системы единой регистрации сотрудники имеют защищенный доступ к одинаковым функциональным возможностям на любом устройстве. В отличие от других решений, защищенная цифровая рабочая среда Citrix создана на основе контекстного подхода. Это единственное решение, которое включает функции совместной работы, управления правами на доступ к данным и бизнес-процессов. Непосредственно в защищенной цифровой рабочей среде пользователи могут создавать, редактировать и совместно работать с онлайн-документами Office 365.

Citrix ускорила разработку инноваций в области облачных технологий с выпуском новых сервисов и функциональных возможностей для расширения этой мощной модели предоставления рабочих сред. Эти сервисы включают XenApp Essentials и XenDesktop Essentials , рабочая нагрузка которых реализована в Microsoft Azure, но управляются они из Citrix Cloud. Дополнительные сервисы Citrix Cloud включают решение по управлению мобильными устройствами и приложениями XenMobile, а также NetScaler Gateway Service, что позволяет заказчикам быстро и просто создавать шлюз-в-облаке. Кроме того, Citrix Cloud предлагает интеграцию с Azure Active Directory, предлагая администраторам использовать возможности, предоставляемые Интернетом вещей и другими новыми сервисами, разработанными лабораторией Citrix.

Усиленная защита и расширенная аналитика


Согласно глобальному опросу, проведенному в 2017 г. институтом Понемон , 73% респондентов назвали управление данными, 76% – управление конфигурацией и 72% – управление приложениями в качестве основных условий для снижения рисков при создании новой ИТ-инфраструктуры в ближайшие 2 года. Увеличение и изменение периметра корпоративной безопасности создает потребность в более интеллектуальном подходе при управлении политиками информационной безопасности в рамках всего нового периметра. Для того чтобы помочь заказчикам эффективно защищать свои среды, Citrix Consulting Services представило Security Practice и Citrix Analytics, новое решение обеспечения безопасности и анализа поведения, которое расширяет функциональные возможности Citrix NetScaler Management and Analytics System (MAS) и предлагает новые функции обнаружения подозрительного поведения приложений в рамках продуктов Citrix (XenApp/XenDesktop, XenMobile, ShareFile, NetScaler) и проактивного устранения рисков.

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



Хотя Citrix Analytics уделяет большое внимание вопросам безопасности, существуют другие направления, включая производительность и доступность, в которых Citrix Analytics предоставляет большие преимущества. Несколько аналитических модулей реализовано в ПО NetScaler MAS (Management and Analytics System). NetScaler MAS – это программный продукт, которые выполняет управление сетями и их анализ. NetScaler MAS предоставляет следующие функции:

  • Централизованное управление для высокой эффективности работы: NetScaler MAS автоматизирует административные задачи, включая управление конфигурацией и сертификатами, для того, чтобы сэкономить время и исключить ошибки, связанные с человеческим фактором. NetScaler MAS также интегрируется с ПО для управления облачными средами и SDN.
  • Контроль и анализ: NetScaler MAS использует данные сети для проактивного определения и устранения ошибок и обнаружения угроз безопасности.
  • Управление жизненным циклом приложений: NetScaler MAS контролирует и управляет приложениями в рамках всей инфраструктуры доставки приложений

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

https://habrahabr.ru/post/330522/


Метки:  

[Из песочницы] Дополнение к анализу алгоритмов

Четверг, 08 Июня 2017 г. 15:47 + в цитатник
image

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

Что нужно знать перед началом?


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

Smoothed analysis


Скорее всего, вы впервые слышите это словосочетание. Что неудивительно, т.к. Smoothed анализ появился по меркам математики недавно: в 2001 году. Разумеется это подразумевает, что идея не лежит на поверхности. Я буду считать, что вам уже известен анализ худшего случая, анализ среднего, а так же сравнительно бесполезный анализ лучшего случая: и того три очевидных варианта. Так вот smoothed analysis — четвертый вариант.

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

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

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

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

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

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

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

$$display$$С_{smooth}(n, \sigma)=\max\limits_{x}\{M_{r \in X_{n}}[\tau(x+\sigma||x||r)]\}$$display$$


, где $inline$\sigma$inline$ некоторая небольшая константа, $inline$X_n$inline$ множество возможных входных данных размера $inline$n$inline$, $inline$\tau$inline$ функция возвращающая время (или память), которое алгоритм затратит на обработку конкретных данных, $inline$M$inline$ — математическое ожидание, а скобки разные для удобства.

Говоря простым языком smooth оценка означает, что не существует достаточно большого непрерывного куска данных, на которых алгоритм будет работать в среднем медленнее, чем $inline$С_{smooth}$inline$. Таким образом smoothed оценка сильнее средней, но слабее худшей. Очевидно что варьируя $inline$\sigma$inline$ можно смещать её от среднего к максимуму.

Поскольку определение не тривиально я нарисовал картинку для понимания:

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

Подробнее об этом можно прочитать в статье «Smoothed Analysis of Algorithms». В ней применяют этот подход для анализа симплекс метода. По ссылкам можно найти и другие статьи.

Анализ алгоритмов во внешней памяти


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

Внешняя память это диск, сеть или другое медленное устройство. Для анализа алгоритмов оперирующих с ними используют другую модель выполнения во внешней памяти. Если упрощать, то в этой модели у компьютера есть $inline$M$inline$ машинных слов внутренней памяти, все операции с которой, ничего не стоят, так же ничего не стоят вычислительные операции на CPU, а ещё есть внешняя память, с которой возможно работать только целыми блоками размера $inline$B$inline$ слов и каждая такая операция считается элементарной. Причем $inline$M$inline$ значительно больше $inline$B$inline$. В этой модели говорят об IO сложности алгоритма.

Таким образом даже если решать на каждом блоке NP-полную задачу в памяти, это не повлияет на IO-сложность алгоритма. Но в такой формулировке это не большая проблема поскольку блок имеет фиксированную длину и мы просто говорим, что вот такая у нас элементарная операция. Однако модель будет не применима для алгоритма драматически уменьшающего число операций на CPU ценой увеличения операций с диском, так что в итоге это будет выгодно. Но даже в таком случае, нужно что бы этот размен был нетривиальным. Причем размен в обратную сторону укладывается в модель, поэтому добавление сжатия не вызывает сложностей. А замена медленного алгоритма сжатия на более быстрый, относится к тривиальному размену.

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

При анализе в этой модели будьте аккуратны с округлением, т.к. чтение одного машинного слова и $inline$B$inline$ машинных слов занимает одно и то же время. В общем случае чтение $inline$N$inline$ последовательных слов занимает $inline$\lceil N/B \rceil$inline$ операций, и при небольших $inline$N$inline$ вклад округления будет значительным, особенно если потом эта величина умножается на что-то.

Из-за особенностей модели задачи начинают решаться будто быстрее, т.к. вычислительные операции ничего не стоят. Например сортировка слиянием выполняется за $inline$O(\frac{Nlog_{M/B}(N/B)}{B})$inline$, что намного быстрее чем могло бы быть. Но не стоит обманываться, при фиксированных $inline$M$inline$ и $inline$B$inline$, все это дает лишь мультипликативную константу, которую легко съедает диск.

SSD и кэш


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

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

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

Бонус


Напоследок расскажу об интересном обозначении, применяемом при анализе NP-полных задач. Сам я узнал о таком обозначении в лекциях Александра Куликова «Алгоритмы для NP-трудных задач».

Неформально символ «О»-большое съедает всё кроме старшего члена, а у старшего члена съедает мультипликативную константу. Оказывается, существует символ $inline$O^{\ast}$inline$, который съедает не просто мультипликативную константу, а целый полином. Т.е. $inline$O(n^{100})=O^{\ast}(1)$inline$, и $inline$O(n^{100}2^n)=O^{\ast}(2^n)$inline$. Так что если вам станет грустно из-за того, что ваша программа тормозит, можете утешать себя мыслью, что алгоритмически её IO-сложность $inline$O^*(1)$inline$.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330518/


Метки:  

Как «Пилот» модернизировал фискальный регистратор в ККТ Fujitsu

Четверг, 08 Июня 2017 г. 15:43 + в цитатник
Наверняка, вы много читали о знаковых поправках в закон 54-ФЗ «О применении контрольно-кассовой техники», обязывающих отечественные магазины в режиме реального времени отчитываться об осуществленных продажах, передавая данные о расчетах с покупателями через интернет в ФСН РФ. Изменения коснулись практически всех ритейлеров (кроме небольшого списка исключений, указанных в тексте поправок), даже тех, кто раньше работал по упрощенной системе налогообложения.
Подробно о сути закона и его влиянии как на магазины, так и на обычных покупателей, группа компаний «Пилот» писала в своем блоге. Теперь наглядно продемонстрируем, как контрольно-кассовую технику (ККТ) требуется модернизировать согласно требованиям 54-ФЗ. Заинтересовавшихся прошу под кат.


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

Для появления на свет ККТ POSprint FP510-Ф требуется программная модернизация модели ККМ POSprint FP510K, заключающаяся в смене прошивки и замене электронной контрольной ленты защищенной (ЭКЛЗ) на фискальный накопитель (ФН) или подготовка с нуля, то есть из принтера.

Рассмотрим второй способ. Возьмём принтер Fujitsu FP510


Принтеры поступают от производителя без интерфейсной платы с заглушкой (брэкетом)


Извлекаем заглушку



Устанавливаем на неё фискальный модуль с предустановленным ПО



Устанавливаем на модуль фискальный накопитель



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


ККТ готова к использованию.

Казалось бы, все просто и ничего не мешает ритейлерам закупить необходимую для соответствия требованиям ФЗ-54 технику. Однако есть явная проблема: дефицит, либо брак фискальных накопителей. По договору с производителем предоплаченные ФН должны поступать заказчикам в течение 60 дней. По факту же этот срок значительно увеличивается. А это значит, что не все ритейлеры успеют поставить на учет свою ККТ – а по закону они должны это сделать до 1 июля 2017 года.

Если же говорить о том, кто использует в работе ККТ POSprint FP510-Ф, то это такие крупные сети, как «Атак», «Ашан», «Детский мир», «Иль Де Ботэ», «Летуаль», Bershka, Lefties, Massimo Dutti, Oysho, Pull&Bear, Stradivarius, Zara, Zara Home и др.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330486/


Метки:  

Объектное Реактивное Программирование

Четверг, 08 Июня 2017 г. 15:16 + в цитатник

Дмитрий Карловский из SAPRUN представляет… ммм...


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

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

Рекламная пауза


SAPRUN


Всем привет, меня зовут Дмитрий Карловский. Я — руководитель группы веб-разработки компании САПРАН. Компания наша является крупнейшим интегратором САП-а в России, но в последнее время мы активно смотрим в сторону разработки собственных программных продуктов.

$mol — реактивный до мозга костей


Один из них — кроссплатформенный open source веб фреймворк быстрого построения отзывчивых интерфейсов с говорящим названием "$mol". В нём мы по максимуму применяем возможности Объектного Реактивного Программирования, о которых я и расскажу далее...

$mol


Что будем делать вечером? Попробуем завоевать ритейл!


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

toys.hyoo.ru


Каталог товаров


Игрушек у нас много, а начать продажи надо было ещё вчера. Поэтому мы хотим сделать всё как можно быстрее, но не про… теряв user experience.

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

Каталог различных игрушек


Фильтрация


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

Каталог с фильтром


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

Например, если мы отфильтровали по размеру, то при изменении числа отзывов нет смысла выполнять повторную фильтрацию. А вот если отфильтровали по числу отзывов… ну вы поняли, да?

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

Сортировка


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

Каталог со сложным фильтром и сложной сортировкой


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

Учёт всех зависимостей


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

Диаграмма всех зависимостей между состояниями


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

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

Всё ли рендерить?


Если вы будете отображать все данные, что подготовили, то алгоритмическая сложность рендеринга будет пропорциональна объёму этих данных. 10 товаров рендерятся мгновенно, 1000 — с задержкой, а если 10000, то пользователь успеет сходить попить чайку.

График с линейной прогрессией


Или не всё?


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

График с логарифмической и линейной прогрессией


Отображение лишь видимого


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

Диаграмма вырезания видимой части списка товаров


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

Примерение изменений к DOM


Ок, данные мы подготовили, осталось показать их пользователю. Решение в лоб — удалить старое DOM-дерево и вырастить новое. Именно так работают все HTML-шаблонизаторы.

Перерисовывать DOM - это долго


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

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

Виртуальный DOM


Как натянуть ужа на ежа? Правильно, давайте генерировать новое DOM дерево всего приложения, а потом React специальная библиотека будет сравнивать его новую и старую версию, и применять различия к тому DOM дереву, что реально видит пользователь.

Виртуальный дом на каждый чих - это медленно


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

Прямые зависимости


А как могла бы выглядеть работа наиболее эффективного решения?

Прямые зависимости. Что может быть эффективней?


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

И так сойдёт!


И так сойдёт!


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

Треугольник серпинского на ReactJS


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

nin-jin.github.io/sierpinski/stack.html


Перед вами известное демо созданное ребятами из Facebook, показывающее как сильно тупят сложные приложения на Реакте. Они это сейчас пытаются решить размазыванием вычислений по нескольким кадрам, что даёт заветные 60 кадров в секунду, но приводит к визуальным артефактам. Фундаментальная же проблема у них остаётся неизменной — виртуальный DOM требует кучи лишних вычислений на каждый чих.

Треугольник серпинского с использованием ОРП


ОРП, напротив, позволяет минимизировать объём вычислений, автоматически оптимизируя потоки данных от их источника до их потребителя.

mol.js.org/perf/sierp/


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

Парадигмы


Давайте, наконец, добавим немного теории…

Что такое Объектное Программирование? Основной его чертой является объединение данных и функций для работы с ними в рамках одной абстракции с относительно простым интерфейсом — объекте.

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

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

Объектное, Функциональное и Реактивное


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

Проталкиваем (ФРП)


Есть два принципиально разных способа реализации реактивности.

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

const FilterSource = new Rx.BehaviorSubject( toy => toy.count > 0 )
const Filter = FilterSource.distinctUntilChanged().debounce( 0 )

const ToysSource = new Rx.BehaviorSubject( [] )
const Toys = ToysSource.distinctUntilChanged().debounce( 0 )

const ToysFiltered = Filter
.select( filter => {
    if( !filter ) return Toys
    return Toys.map( toys => toys.filter( filter ) )
} )
.switch()
.distinctUntilChanged()
.debounce( 0 )

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

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

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

Затягиваем (ОРП)


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

class $my_toys {

    @ $mol_mem()
    filter( next ) {
        if( next === undefined ) return toy => toy.count() > 0

        return next
    }

    @ $mol_mem()
    toys( next = [] ){ return next }

    @ $mol_mem()
    toys_filtered() {
        if( !this.filter() ) return this.toys()

        return this.toys().filter( this.filter() )
    }
}

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

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

Добавляем сортировку


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

@ $mol_mem()
sorter( next ) {
    if( next === undefined ) return ( a , b )=> b.price() - a.price()

    return next
}

@ $mol_mem()
toys_sorted() {
    if( !this.sorter() ) return this.toys_filtered()

    return this.toys_filtered().slice().sort( this.sorter() )
}

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

Отображаем лишь видимое


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

@ $mol_mem()
toys_visible() {
    return this.toys_sorted().slice( ... this.view_window() )
}

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

children() {
    return this.toys_visible()
}

Реактивный рендеринг


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

@ $mol_mem()
render() {
    let node = document.getElementById( this.id() )

    if( !node ) {
        node = document.createElement( 'div' )
        node.id = this.id()
    }

    /// Node updating here

    return node
}

Зная идентификатор компонента, мы ищем соответствующий узел в реальном DOM-дереве. А если не нашли, то создаём его. После этого актуализируем его состояние и возвращаем.

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

А если исключение?


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

toys.hyoo.ru/#luck=.9


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

Защищаем приложение от падения компонента


Поэтому давайте завернём рендеринг DOM-узла в блок try-catch и в случае возникновения ошибки, записывать имя исключения в специальный атрибут. А если рендеринг пройдёт без эксцессов — стирать его.

try {

    /// Node updating here

    node.removeAttribute( 'mol_view_error' )

} catch( error ) {

    console.error( error )

    node.setAttribute( 'mol_view_error' , error.name )
}

Индикация ошибки


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

[mol_view_error] {
    opacity: .5 !important;
    pointer-events: none !important;
}

Загрузка: Синхронная блокирующая


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

namesakes_message() {

    /// Serial
    const user = this.user()
    const count = this.name_count( user.name )

    return this.texts().namesakes_message
    .replace( /\{count\}/g , count )
}

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

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

Загрузка: Асинхронная неблокирующая


Чтобы решить эту проблему в яваскрипте принято писать код на колбэках.

namesakes_message() {

    /// Parallel
    return Promise.all([

        /// Serial
        this.user().then( user => this.name_count( user.name ) ,

        this.texts() ,

    ])
    .then( ([ count , texts ])=> {
        return texts.namesakes_message.replace( /\{count\}/g , count )
    } )

}

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

Загрузка: Синхронная неблокирующая с ручной параллельностью


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

/// Serial
async namesakes_count() {
    const user = await this.user()
    return await this.name_count( user.name )
}

async namesakes_message() {

    /// Parallel
    const [ count, texts ] = await Promise.all([
        this.namesakes_count() ,
        this.texts() ,
    ])

    return texts.namesakes_message.replace( /\{count\}/g , count )
}

Если мы пометили функцию как "асинхронную", то мы можем приостанавливать её до появления определённого события.

Как видно, это не сильно спасает, так как для распараллеливания запросов всё равно приходится кастовать специальные заклинания.

Загрузка: Синхронная неблокирующая без лишнего шума


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

@ $mol_mem()
namesakes_message() {

    /// Parallel
    const texts = this.texts()
    const user = this.user()

    /// Serial
    const count = this.namesakes_count( user.name )

    return texts.namesakes_message.replace( /\{count\}/g , count )
}

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

Загрузка: Автоматическое распараллеливание


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

В данном примере, первое прерывание произойдёт лишь при доступе к user.name, а значит загрузка текстов и информации о пользователе пойдёт параллельно.

@ $mol_mem()
namesakes_message() {

    /// Parallel
    const texts = this.texts()
    const user = this.user()

    /// Serial
    const count = this.namesakes_count( user.name ) /// <-- first yield

    return texts.namesakes_message.replace( /\{count\}/g , count )
}

Загрузка: Игрушки


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

/// Before
@ $mol_mem()
toys(){ return [] }

/// After
toys_data() {
    return $mol_http.resource( '/toys.json' ).json()
}

@ $mol_mem()
toys() {
    return Object.keys( this.toys_data() ).map( id => this.toy( id ) )
}

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

Индикация ожидания


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

[mol_view_error="$mol_atom_wait"] {
    animation: my_waiting .25s steps(6) infinite;
}

Движение данных


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

Взаимодействие пользователя с сервером через интерфейс


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

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

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

Двунаправленные зависимости


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


Двунаправленные зависимости: Меняем состояние виджета



Двунаправленные зависимости: Меняем состояние страницы



Двунаправленные зависимости: Меняем состояние модели



Двунаправленные зависимости: Пришёл ответ от сервера



Как думаете, что за фреймворк тут использован?

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

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

Однонаправленный поток данных


А как называется архитектура со следующей диаграммы?


Однона… что это у нас?



Потока хоть и два, но не пересекаются



Facebook подумал-подумал и придумал FLUX, где поток от сервера к пользователю идёт через компоненты, а обратно — через глобальные процедуры — так называемые "Экшены".

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

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

Двусторонние каналы: Прямой поток


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


Двусторонние каналы: Обратный поток


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


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

Двусторонние каналы: Непротиворечивый цикл


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


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

Абстракции


class $mol_string {

    hint() { return '' }

    @ $mol_mem()
    value( next = '' ) { return next }

    // ...
}

Данный пример — компонент строкового поля ввода. Для иллюстрации приведено два свойства: hint — это текст показываемый, если значение поля не задано; и value — это текущее значение. Когда пользователь вводит новое значение оно передаётся в value. А благодаря декоратору, результат работы метода кешируется в внутри объекта.

Одностороннее переопределение


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

const Name = new $mol_string

Name.hint = ()=> 'Batman'

Двустороннее переопределение


Или можем попросить компонент в качестве value брать не своё локальное состояние, а нашу локальную переменную.

let name = 'Jin'

Name.value = ( next = name )=> {
    return name = next
}

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

Это вообще законно?


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

Кавайная какашка


Но на практике это всё отлично работает и не доставляет проблем.

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

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

Контроль времени жизни


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

    @ $mol_mem()
    Name() {
        const Name = new $mol_string

        /// Setup ```Name``` here

        return Name
    }

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

Связывание владельца с имуществом


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

        /// Setup ```Name```:

        /// One way binding
        Name.hint =  ()=> this.name_hint()

        /// Two way binding
        Name.value = ( next )=> this.name( next )

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

Резюме


Реактивное программирование — каскадное изменение состояний по нашим правилам.


ОРП провоцирует простой, понятный, но эффективный код.


Ленивая архитектура минимизирует объём вычислений.


Потока данных всегда два и они не должны пересекаться.


Синхронный код — добро.


Ручное управление потоками данных — зло.


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

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

Вопросы?


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

Реализации ОРП: $mol_mem, VueJS, MobX, CellX, KnockOut


Получившийся магазин: toys.hyoo.ru


Исходники магазина: github.com/nin-jin/toys.hyoo.ru


Эти слайды: nin-jin.github.io/slides/orp


Треугольники Серпинского: github.com/nin-jin/sierpinski

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

https://habrahabr.ru/post/330466/


Метки:  

Зачем хакеры воруют торговые алгоритмы хедж-фондов и HFT-компаний

Четверг, 08 Июня 2017 г. 15:12 + в цитатник


Изображение: Russ Allison Loar, CC BY 2.0

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

Кража алгоритма: зачем это нужно


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

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

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

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

К примеру, зимой 2015 года были предъявлены обвинения бывшему работнику одного из расположенных на Манхэттене хедж-фондов Two Sigma Кангу Гао (Kang Gao) — согласно опубликованным документам, его трудовой контракт запрещал доступ к торговым стратегиям, финансовым моделям, но несмотря на это сотрудник отправлял такие файлы сам себе на email. Впоследствии он намеревался запустить собственную HFT-фирму.

Как осуществляются атаки


Представители компаний, занимающихся информационной безопасностью, не публикую названия компаний, чьи торговые алгоритмы пытались украсть хакеры. Однако исследователь из Kroll Эрнест Гилберт заявлял в разговоре с журналистом Financial Times о том, что финансовые компании являются «заманчивой целью для хакеров», поскольку не все из них внедряют инструменты и подходы по обеспечению защиты информации, вроде сегментации сети и мониторинга трафика.

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

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

Не все так плохо


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

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

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

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

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

Другие материалы по теме финансов и фондового рынка от ITinvest:


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

https://habrahabr.ru/post/330514/


Метки:  

Интеграция Cordova в нативный iOS проект

Четверг, 08 Июня 2017 г. 14:48 + в цитатник
image

Продолжая небольшую серию статей «Crosswalk Project — замена Android WebView», есть смысл разобрать аналогичную задачу для iOS. Основой для интеграции на этот раз был выбран проект Cordova, т.к. он имеет больший функционал и в данном случае лучше подходит для поставленной задачи.

Оба решения и Cordova, и Crosswalk основываются на WKWebView в своей версии для iOS. Поэтому в данном случае прямой заменой системному WebView они не являются, а только расширяют его.

Целевой язык демо-проекта — Swift, но для проекта на Objective-C всё будет аналогично. Не нужно только выполнять последний шаг по адаптации Cordova для использования со Swift.


NB! Для Crosswalk имеется простое руководство по интеграции с помощью Cocoa Pods и есть поддержка основных плагинов Cordova с возможностью расширения.

Существует 2 варианта для встраивания Cordova в ваше приложение:
  1. Встраивание Cordova вручную.
  2. Добавление необходимых компонентов через Cocoa Pods.

NB! На самом деле есть ещё 1 простой вариант. Настроив окружение для Cordova, вы получите рабочий Xcode-проект, который вполне можно использовать отдельно от Cordova для дальнейшей разработки. Только учтите, что этот проект на Objective-C.

Встраивание Cordova вручную.


Я рассмотрю сначала первый вариант и добавлю Cordova с необходимыми компонентами вручную. Этот вариант чуть более сложен, но более гибок и позволяет использовать последние версии cordova-ios и плагинов не зависимо от создателей pod'ов.

Использованные версии ПО:

Настройка окружения.


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

1. Устанавливаем менеджер пакетов npm, с помощью которого далее установим Cordova и необходимые плагины (для установки npm я использовал MacPorts):
sudo port install npm4

2. Устанавливаем непосредственно Cordova:
sudo npm install -g cordova

Аналогично можно установить только cordova-ios:
sudo npm install -g cordova-ios

Это может пригодиться, если вы не планируете работать с остальными платформами. Однако, в этом случае будет чуть менее удобно пользоваться командами в консоли. Например, необходимо будет использовать:
cordova-ios/bin/create

с полным путём вместо короткой команды:
cordova create

NB! Все установленные с помощью npm пакеты будут находится здесь: /opt/local/lib/node_modules/.

3. Далее создаём проект Cordova, переходим в его папку и добавляем целевую платформу iOS:
cordova create cordova_full
cd cordova_full/
cordova platform add ios

Необходимые нам файлы будут находится в папке cordova_full/platforms/ios/. Аналогичный набор с минимальными отличиями мы получим, если использовать непосредственно пакет cordova-ios.

NB! При создании проекта можно указать название приложения и bundle identifier. Подробнее смотрите в документации Cordova.

4. Дополнительно можно установить утилиту plugman для работы с плагинами Cordova:
sudo npm install -g plugman

5. Установим также 2 плагина для отображения сообщений в консоли и работы с системным статус баром, они нам пригодятся для работы. Для этого необходимо перейти в папку с ресурсами для ios и выполнить следующие команды:
plugman install --platform ios --project . --plugin cordova-plugin-console
plugman install --platform ios --project . --plugin cordova-plugin-statusbar

NB! Для желающих работать с тулчейном Ionic Framework (http://ionicframework.com/) и использовать его шаблоны — всё выглядит аналогично.

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


1. За основу проекта был взят стандартный шаблон Tabbed Application из Xcode. Созданный демо-проект со всеми ресурсами можно найти на github.

Минимально поддерживаемая Cordova iOS 4.4.0 версия iOS равна 9.0, её же выбираем для демо-проекта.

2. Переносим в наш демо-проект необходимые ресурсы:
  • папку с проектом CordovaLib cordova_full/platforms/ios/CordovaLib/
  • папку с установленными плагинами cordova_full/platforms/ios/HelloCordova/Plugins/
  • конфигурационный файл Cordova cordova_full/platforms/ios/HelloCordova /config.xml
  • папку с ресурсами для web-приложения cordova_full/platforms/ios/www/

NB! После добавления CordovaLib, проверьте в настройках основного проекта во вкладке Build Phases -> Compile Sources. Удалите оттуда файлы CordovaLib, чтобы не было конфликтов при сборке.

NB! При добавлении папки с ресурсами www/ необходимо выбрать опцию «Create folder references», чтобы ресурсы располагались по стандартному для Cordova пути.

3. Необходимо настроить демо-проект для корректной сборки:
  • в Build Settings -> Other Linker Flags добавить флаг -ObjC
  • в Build Settings -> Header Search Paths добавить пути:
    "$(TARGET_BUILD_DIR)/usr/local/lib/include"
    "$(OBJROOT)/UninstalledProducts/include"
    "$(OBJROOT)/UninstalledProducts/$(PLATFORM_NAME)/include"
    "$(BUILT_PRODUCTS_DIR)"
  • в Build Phases -> Target Dependencies добавить CordovaLib
  • в Build Phases -> Link Binaries with Libraries добавить libCordova.a

NB! Обратите внимание, необходимо добавлять всю строку вместе с кавычками.

В варианте для Objective-C настройка закончена и проект можно использовать.

4. Адаптация для Swift. Проект Cordova iOS изначально был реализован на языке Objective-C и на данный момент не известно про официальные планы по его портированию на Swift. Существует неофициальный порт, но он не закончен.

Однако, нет принципиальной проблемы для использования Cordova в проекте на Swift. Необходимо только добавить Bridging Header для связи мира Swift и Objective-C.

Для этого необходимо создать в проекте .h файл (например, Bridging-Header.h):
#ifndef Bridging_Header_h
#define Bridging_Header_h

#import "CDVViewController.h"

#endif /* Bridging_Header_h */

И добавить в Build Settings -> Objective-C Bridging Header путь к нему:
CordovaEmbedded/Libraries/Bridging-Header.h

5. После этого мы можем использовать Cordova WebView. Например, унаследуем в демо-проекте SecondViewController от CDVViewController вместо UIViewController. И лёгким движением руки наша вторая вкладка превращается в полноценное Cordova приложение.

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

Первый плагин позволяет нам получать сообщения в консоли Xcode в адекватном виде:
CordovaEmbedded[31857:638683] Received Event: deviceready

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



Добавление необходимых компонентов через Cocoa Pods.


1. Для иллюстрации подключения Cordova через CocoaPods возьмём тот же самый шаблон проекта Tabbed Application из Xcode. Созданный демо-проект со всеми ресурсами можно найти на github.

2. Создадим pod файл с помощью команды
pod init
и добавим в него pod'ы:
pod 'Cordova' # Cordova framework and plugins
pod 'CordovaPlugin-console'
pod 'cordova-plugin-camera'
pod 'cordova-plugin-contacts'
pod 'cordova-plugin-device'
pod 'cordova-plugin-device-orientation'
pod 'cordova-plugin-device-motion'
pod 'cordova-plugin-globalization'
pod 'cordova-plugin-geolocation'
pod 'cordova-plugin-file'
pod 'cordova-plugin-media-capture'
pod 'cordova-plugin-network-information'
pod 'cordova-plugin-splashscreen'
pod 'cordova-plugin-inappbrowser'
pod 'cordova-plugin-file-transfer'
pod 'cordova-plugin-statusbar'
pod 'cordova-plugin-vibration'
pod 'cordova-plugin-wkwebview-engine'
pod 'phonegap-ios-template' # Cordova template 

NB! Добавляются все плагины, т.к. они используются в шаблоне с ресурсами phonegap-ios-template. Практически можно добавить только нужные, но тогда необходимо будет скорректировать config.xml в шаблоне.

3. Устанавливаем pod'ы командой
pod install
и открываем полученный .xcworkspace. Далее необходимо выполнить шаг 4 из предыдущего раздела, по адаптации проекта для использования с языком Swift.

4. Сейчас есть проблема с конфигурацией и при сборке проект не находит все нужные заголовки. Решить это можно добавив в Build Settings -> User Header Search Paths путь (с флагом recursive):
"${PODS_ROOT}"

5. — 6. Для иллюстрации работоспособности Cordova можно повторить шаги 5 и 6 из предыдущего раздела. Всё работает аналогично.

Выводы и полезные ресурсы.


Вариант с подключением Cordova вручную не сильно сложнее варианта с использованием Cocoa Pods в данном случае, но более гибок и позволяет использовать последние версии cordova-ios и плагинов.

А вот при использовании Cocoa Pods есть несколько минусов:
  • нет возможности обновиться на нужную версию Cordova iOS или плагина;
  • всё-равно необходимо производить конфигурацию проекта;
  • необходимо изменять конфигурацию Cordova в pod-проекте.

По большому счёту, основные минусы заключаются в не очень хорошей поддержке pod'ов для Cordova :).

Дополнительно про интеграцию Cordova WebView в нативный iOS проект можно изучить:

NB! Обратите внимание, что официальная документация по интеграции несколько устарела и может иметь лишние или отсутствующие шаги.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330508/


Метки:  

Экосистема: больше участников — больше прибыль! Зачем Skyeng открывает API

Четверг, 08 Июня 2017 г. 14:29 + в цитатник

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

Что мы понимаем под экосистемой?


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

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

Теперь представим, что между телефоном и автомобилем возникает какая-то дополнительная связь (синергия). Т.е. появляются некие новые use cases, не существовавшие ранее и невозможные без этой синергии. Например, мы можем найти машину на парковке, заранее завести из приложения зимой, проверить уровень бензина, телефон нам напомнит о предстоящем ТО до того, как загорится страшная лампочка check engine и т.д. Эти дополнительные возможности повышают сумму ценности автомобиля и телефона с базовых двух до двух с половиной «единиц счастья». Неудивительно, что автомобильные концерны довольно активно сотрудничают с Google и Apple.

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

Представим себе, что у нас есть десять каких-то условных отдельных (standalone) продуктов. Предположим, что все они обладают одинаковой ценностью, которую мы примем за 1. Таким образом, общая ценность пакета наших продуктов равна 10. Если завтра мы выпустим еще один продукт с такой же ценностью, то общая ценность для клиента станет равна 11.

Теперь представим себе, что мы нашли способ связать эти продукты — подобно примеру про автомобиль и телефон. Пусть их связка дает новую ценность (новый функционал, невозможный в standalone-режиме) в 0,5 очков. Примем, что все десять продуктов можно связать друг с другом, получив 45 связок. Таким образом, организовав связи (экосистему), мы более чем утроили ценность нашего предложения (32,5 вместо 10), хотя ценность самих продуктов, если брать их по отдельности, осталась прежней.

Теперь, добавив 11-й продукт, также обладающий связями со всей имеющейся экосистемой, мы увеличиваем ее ценность не на 1, а сразу на 6 (продукт + 10 связок).

На этом этапе ценность связей становится для нас важнее ценности самого продукта. Строго говоря, 11-й продукт может вообще не иметь никакого своего value, но иметь связи. Он все равно принесет 5 очков ценности экосистеме. Мало того, этот новый продукт может даже обладать отрицательной ценностью (глюки, альфа-версия, еще что-то), но, при наличии ценных связей, его выпуск будет не просто оправдан, а необходим.

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

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

У нас есть браузерное расширение для перевода текстов. Само по себе оно далеко не единственное на свете, и, наверное, даже не лучшее. Но у него есть уникальное преимущество – оно привязано к нашему словарю, где есть подробная карточка по каждому слову, и само слово можно добавить в свой список для запоминания в мобильном приложении. Так образовательная ценность расширения заметно вырастает. Vimbox Субтитры — сервис, позволяющий смотреть кино и сериалы с английской дорожкой и английскими же субтитрами; при наведении курсора на слово появляется его перевод. Для получения удовольствия от просмотра — не идеальное решение: мы бы могли сильно повысить его ценность, просто подкачивая полноценные русские субтитры, и переводя не слова, а сразу фразы. Мы жертвуем этой ценностью, чтобы дать возможность ученику закрыть свои лексические пробелы с помощью других наших продуктов.

Сейчас наша экосистема включает в себя:

Платформу Vimbox, содержащую элементы:
· виртуальный класс, где проходят занятия с преподавателем;
· сервис «Домашние задания», являющийся отдельным приложением платформы;
· инструмент «Эссе»;
· контрольные работы;
· запись речи для обучения произношению;
— Мобильные приложения, в частности:
· Words, инструмент для заучивания английских слов;
· Listening, приложение для аудирования;
· Aword – аналог Words для внешних пользователей;
— Браузерные расширения, упомянутые выше:
· Vimbox Переводчик;
· Vimbox Субтитры.

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


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

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

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



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

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

Что можно сделать на нашем API? Вот примеры того, что приходило нам в голову и ещё никем не реализовано:

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

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

Техническая документация на Skyeng API доступна по ссылкам:


На текущий момент мы открываем три метода:

  • dictionary.skyeng.ru/api/public/v1/words/search?search=mother — по произвольному запросу, необязательно из одного слова, выдаёт релевантные слова и выражения, а для каждого слова — его значения, отсортированные по их популярности, с переводами и картинками.
  • dictionary.skyeng.ru/api/public/v1/meanings?ids=192984 — по id отдает значение слова с примерами употребления, картинками, переводом, озвучкой, транскрипцией, списком значений других слов, которые переводятся аналогично.
  • words.skyeng.ru/api/public/v1/users/meanings?email=gleb.s@skyeng.ru — по email отдает список id значений слов, которые взяты на изучение учеником школы Skyeng, и степени их изученности (если залогиниться в Skyeng и позвать этот сервис без параметра email, он отдаст такой список для залогиненного пользователя).

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



Мы готовы вам всячески помогать — рассказывать про API и консультировать по методикам обучения и продуктовым вопросам. Все самые лучшие ваши разработки мы будем советовать нашим ученикам и выложим на витрину приложений в Vimbox наравне с нашими собственными. Фактически Skyeng предоставляет вам место в своей экосистеме и платформу для роста.

По данным за май 2017 года пользователи приложения Words в день в среднем добавляли на изучение 186 тысяч слов и проходили 21 тысячу тренировок, а доля активных пользователей приложения среди 10,3 тысяч активных учеников школы Skyeng составила 33%. Число учеников школы растёт в 3 раза каждый год. Поэтому у вас сразу из коробки и абсолютно бесплатно будет таргетированная платящая аудитория — десятки тысяч клиентов Skyeng, изучающих английский язык, в основном, это топ-менеджеры из крупных городов России и СНГ.

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

Ну и, наконец, обещанный конкурс. Авторов самых лучших разработок мы планируем наградить ценными призами! Призовой фонд составит 200 тысяч рублей, определять победителей будем мы сами, ориентируясь на полезность решения для учеников школы и на интегрированность в нашу экосистему. Кроме того, про интересные приложения мы напишем на «Хабре». Чтобы принять участие в конкурсе разработок и получить консультацию нужно заполнить заявку.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330456/


Метки:  

Dagaz: Забегая вперёд

Четверг, 08 Июня 2017 г. 14:10 + в цитатник
image Сто тринадцать раз в секунду оно тянется, и достает все дальше. Если бы пришло подтверждение, сигнал — оно могло бы остановиться, и оно не останавливается. Оно тянется и находит всё новые способы. Оно импровизирует, оно изучает. Оно не сознает, что делает…

Джеймс Кори «Пожар Сиболы»


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

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

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

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

Основной инстинкт


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

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

  1. Среди всех доступных ходов ищет ход непосредственно ведущий к победе (в нашем случае, это взятие короля противника)
  2. Если такого хода нет, ищет любой ход берущий фигуру противника и не подставляющий «Махараджу» под ответный удар
  3. Если подходящих ходов нет — делает любой безопасный ход
  4. Если нет безопасных ходов — передаёт эстафету другому боту (как правило, рандомному)

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




Вот ещё один пример. В "Трёх мушкетёрах" взятия выполняются только одним из противников, но зато на каждом ходу. Задача другого игрока — направить «мушкетёров» таким образом, чтобы они оказались на одной вертикали или горизонтали. Если цель не будет достигнута и любая из сторон не сможет сделать очередной ход — «мушкетёры» победят:




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

Выбор безопасного хода
CarefulAi.prototype.getMove = function(ctx) {
  var result = [];
  // Генерируем все ходы из текущей позиции
  _.chain(Dagaz.AI.generate(ctx, ctx.board))
    // Просто проверка наличия действий внутри хода, на всякий случай
   .filter(function(move) {
       return move.actions.length > 0;
    })
    // Для каждого хода
   .each(function(move) {
     // Применяем ход к текущей позиции, получая новую позицию
     var b = ctx.board.apply(move);
     // Если цель противника не достигнута
     if (b.checkGoals(ctx.design, ctx.board.player) >= 0) {
         // Добавляем ход к списку безопасных ходов
         result.push(move);
     }
  }, this);
  if (result.length > 0) {
      // Выбираем любой случайный ход из списка безопасных
      var ix = this.params.rand(0, result.length - 1);
      return {
          done: true,
          move: result[ix],
          ai:   "careful"
      };
  }
  // Если нет безопасных ходов
  if (this.parent) {
      // Обращаемся к Рандому 
      return this.parent.getMove(ctx);
  }
}

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

Игры для одного


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




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




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

Забегание вперёд
  var x = [];
  var queue = [ ctx.board ];
  var timestamp = Date.now();
  while ((Date.now() - timestamp < this.params.AI_FRAME) && queue.length > 0) {
      var board = queue.shift();
      var moves = cache(x, board);
      if (board.checkGoals(Dagaz.Model.getDesign(), board.player) != 0) {
          return {
              done:  true,
              move:  traceMove(ctx, board),
              ai:    "win"
          };
      }
      for (var i = 1; i < moves.length; i++) {
           var b = board.apply(moves[i]);
           var k = getKey(b);
           if (_.isUndefined(x.cache[k]) && !isLoop(ctx, b)) {
               queue.push(b);
           }
      }
  }
  ...

Просто перебираем всевозможные ходы, пока есть время. Если находим цель — идём к ней по прямой! Хотя работа этого бота довольно наглядна, он использует не лучший способ, чтобы решить задачу. Было бы разумнее потратить больше времени вначале, чтобы заняться анимацией уже после того как решение найдено. Именно так я и поступил при разработке бота для решения пасьянсов "Солитёра":




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

Немного текста
Goal: 10,16,17,18,24,31
Current: 22,23
Current: 22,25,24
Current: 22,27,24,26
Current: 22,27,38,26,31
Current: 24,27,38,26,31,23
Current: 22,27,38,24,31,25
Current: 22,27,38,26,29,30
Current: 22,27,38,26,33,32
Current: 22,27,38,26,17,24
Current: 22,27,10,26,17
Current: 24,27,10,26,17,23
Current: 22,27,10,24,17,25
Current: 22,27,10,26,15,16
Current: 22,27,10,26,19,18
Current: 22,27,10,26,31,24
Current: 22,39,24,32
Current: 22,37,24,32,38
Current: 22,23,24,32,38,30
Current: 22,37,26,32,38,25
Current: 22,37,10,32,38,17
Current: 22,37,24,30,38,31
Current: 22,37,24,34,38,33
Current: 22,37,24,46,38,39
Current: 22,37,24,18,38,25


Можно заметить, что я прерываю перебор по достижении набора из 6 позиций (из такого количества фигур состоял искомый пасьянс). Разумеется, это не единственная оптимизация. При наивном подходе, описанном выше, позиции могут повторяться. Как всегда, когда речь заходит о повторении позиций, на помощь приходит Zobrist Hash (на самом деле, он помогает ещё раньше: прежде чем сравнивать позиции поэлементно гораздо эффективнее в начале сравнить их хэши).

Кстати говоря
С отладкой этого бота произошёл забавный казус. Так получилось, что разработанные игры я запускаю, в основном, под FireFox-ом лишь изредка проверяя их на Chrome и IE. Однажды, уже при выкладывании релиза, выяснилось, что solitaire-ai, прекрасно работая под IE и FireFox, под Chrome работает в десятки раз медленнее! Это было не сильно критично, но очень странно.

Для выяснения ситуации пришлось использовать профайлер. В результате оказалось, что причиной тормозов в Chrome является этот самый console.log. Даже если сама консоль закрыта. После того как я убрал консольный вывод, всё заработало с примерно одинаковой скоростью. Мораль в этой истории очень проста. Если вам необходимо выводить большой объём текста (например, в отладочных целях) и вы собираетесь использовать для этого console.log — подумайте ещё раз.

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

Оно тянется


Довольно очевидно, что для более менее серьёзных игр, вроде шахмат или шашек, потребуется более сложный AI, чем всё то, о чём я писал выше. Выбор, по большому счёту, невелик: Минимакс, с его "Альфа-бета отсечением" и метод "Монте-Карло" (и по тому и по другому имеются замечательные статьи на Хабре). Каждый из этих подходов универсален. У каждого из них есть свои плюсы и минусы. Не претендуя на полноту обзора, перечислю первое, что приходит в голову.

  1. Чтобы использовать метод минимакса, необходимо определить функцию, выполняющую оценку позиции (как разработчик настольных игр со стажем, могу заметить, что для некоторых игр это может быть очень непросто).
  2. Альфа-бета отсечение особенно эффективно при выполнении поиска в глубину, либо комбинированного поиска (в ширину, до некоторой гарантированной глубины, например на 2-3 хода, после чего, в глубину, не более чем на N уровней). Это делает его малопригодным в условиях ограниченных вычислительных ресурсов и, самое главное, при необходимости вывода ответа не позднее заданного времени (пусть знающие люди поправят меня, если я ошибаюсь).
  3. Эффективность альфа-бета отсечения можно значительно улучшить, применяя предварительно ранжирование ходов по их качеству (как я скажу ниже, при использовании метода «Монте-Карло» такие эвристики тоже полезны).
  4. При использовании метода минимакса, перебор в глубину нельзя останавливать в произвольном месте. При обнаружении форсированных ходов (в Шахматах такими являются шахи и взятия фигур) поиск следует продолжать до возникновения более «спокойной» позиции.
  5. При использовании метода «Монте-Карло» симуляция производится до терминальной позиции (победы одного из игроков или признания ничьей). В играх с большой продолжительностью партии это может быть проблемой.

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

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

Отладочный лог
Player: Black
d2 — c2
Goal: 1; Deep: 26; Player: 1; P1: a2; P2: a4,a3,b3,c3,c2
Goal: 1; Deep: 20; Player: 1; P1: a1; P2: a4,b4,c4,d4,b3
Goal: 1; Deep: 16; Player: 1; P1: b1; P2: a4,b4,d4,a3,c3,d3
Goal: 1; Deep: 34; Player: 1; P1: c2; P2: a4,b4,d4,b3
Goal: 1; Deep: 22; Player: 1; P1: c3; P2: a3,b3,d3,b2,d2
Goal: 1; Deep: 24; Player: 1; P1: b1; P2: a4,b4,c3,b2,c2
Goal: 1; Deep: 30; Player: 1; P1: d2; P2: a4,c4,b3,b2
Goal: 1; Deep: 12; Player: 1; P1: a1; P2: a4,b4,c4,b3,d3,d2
Goal: 1; Deep: 34; Player: 1; P1: b1; P2: a4,b4,a3,c1
Goal: 1; Deep: 60; Player: 1; P1: d2; P2: a4,b4,b3,b1,c1
Goal: 1; Deep: 34; Player: 1; P1: d2; P2: a3,c2,a1,b1
Goal: 1; Deep: 36; Player: 1; P1: b1; P2: a4,d4,a3,d3,c2
Goal: 1; Deep: 32; Player: 1; P1: c1; P2: b4,a3,c3,a2,c2
Goal: 1; Deep: 24; Player: 1; P1: c2; P2: b3,b2
Goal: 1; Deep: 70; Player: 1; P1: a1; P2: b3,b2
Goal: 1; Deep: 38; Player: 1; P1: b1; P2: a4,b4,c3,a2,b2
Goal: 1; Deep: 28; Player: 1; P1: a1; P2: a4,d4,b3,c3,c2
Goal: 1; Deep: 34; Player: 1; P1: b2; P2: a4,b4,d4,a3,d3
Goal: 1; Deep: 20; Player: 1; P1: c1; P2: a4,b4,c4,d4,a3,c3
Goal: 1; Deep: 18; Player: 1; P1: c2; P2: a4,c4,a3,c3,b2,d1
Goal: 1; Deep: 28; Player: 1; P1: a2; P2: d4,c3,d3,c2
Goal: 1; Deep: 34; Player: 1; P1: d1; P2: b4,a3,b3,d3,a2
Goal: 1; Deep: 30; Player: 1; P1: b1; P2: a4,a3,b3,c3,b2,c2
Goal: 1; Deep: 36; Player: 1; P1: a2; P2: b4,a3,b3
Goal: 1; Deep: 24; Player: 1; P1: c1; P2: b4,a3,b3,d3
Goal: 1; Deep: 36; Player: 1; P1: a1; P2: a4,c3,a2,c2
Goal: 1; Deep: 22; Player: 1; P1: c1; P2: a4,b4,c4,d4,b2,c2
Goal: 1; Deep: 38; Player: 1; P1: c3; P2: a4,d4,b3,b2,c2
Goal: 1; Deep: 46; Player: 1; P1: a1; P2: a4,b4,c4,b2,c2
Goal: 1; Deep: 38; Player: 1; P1: a1; P2: a4,b4,d3,c2,d2
Goal: 1; Deep: 28; Player: 1; P1: b1; P2: b4,c4,d4,c3,a2
Goal: 1; Deep: 20; Player: 1; P1: d2; P2: a4,b4,c4,b3,c2
Goal: 1; Deep: 20; Player: 1; P1: c1; P2: a4,b3,c3,b2
Goal: 1; Deep: 48; Player: 1; P1: d1; P2: a3,a2,b2
Win = 5; All = 11; Move = d3 — c3
Win = 6; All = 12; Move = d3 — d2
Win = 13; All = 18; Move = a3 — b3
Win = 7; All = 13; Move = c4 — c3
Win = 3; All = 8; Move = b4 — b3
Player: White
a3 — b3

Имея перед глазами такой вывод, можно оценивать корректность работы алгоритма. Первое, на что следует обратить внимание это то, соответствуют ли «цели», зафиксированные алгоритмом, целям игрока согласно правилам игры. В процессе отладки, у меня была пара ситуаций, когда алгоритм пытался искать попросту «не то». Если с целями всё нормально, смотрим на оценку ходов (Win — количество зафиксированных побед, All — общее количество сыгранных игр). UCT «из коробки» работает, в принципе неплохо, но я внёс пару изменений:

  1. Ограничил глубину поиска (100 по умолчанию)
  2. Добавил эвристики ходов

Для Коно эвристика выглядит следующим образом
Dagaz.AI.heuristic = function(ai, design, board, move) {
  var r = 1;
  if (move.actions.length > 0) {
      var pos = move.actions[0][1][0];
      if (board.getPiece(pos) !== null) {
          r += 9;
      }
  }
  return r;
}

То есть, взятия в 10 раз более предпочтительны чем «тихие» ходы. Здесь следует заметить, что в отличии от метода минимакса, сортировать ходы в Монте-Карло (в соответствии с их эвристиками) бесполезно. Необходимо строить алгоритм таким образом, чтобы вероятность выбора хода была пропорциональна его эвристической оценке. Оба нововведения благоприятно сказались на статистике побед/сыгранных игр для Коно и я взялся за другие игры.




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

Эвристика довольно очевидна
Dagaz.AI.heuristic = function(ai, design, board, move) {
  var r = 1;
  for (var i = 0; i < move.actions.length; i++) {
      if ((move.actions[i][0] !== null) && (move.actions[i][1] !== null)) {
           var d = move.actions[i][1][0] - move.actions[i][0][0];
           if ((board.player == 1) && (d < -1)) {
                r += 10;
           }
           if ((board.player == 2) && (d == 1)) {
                r += 10;
           }
      }
      if ((move.actions[i][0] !== null) && (move.actions[i][1] === null)) {
           r += 5;
      }
  }
  return r;
}

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

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

Изменения в UCT
function UctAi(params) {
  this.params = params;
  ...
  if (_.isUndefined(this.params.UCT_COEFF)) {
      this.params.UCT_COEFF = Math.sqrt(2);
  }
}

UctAi.prototype.getMove = function(ctx) {
  this.generate(ctx, ctx.board);
  ...
  var mx = null;
  for (var i = 0; i < ctx.childs.length; i++) {
      var u = 0;
      if (ctx.childs[i].win > 0) {
          u = ctx.childs[i].win / ctx.childs[i].all;
      }
      var h = this.heuristic(ctx.design, ctx.board, ctx.childs[i].move);
      var w = this.params.UCT_WEIGHT * u + (1 - this.params.UCT_WEIGHT) * h;
      if ((mx === null) || (w > mx)) {
          mx = w;
          ctx.result = ctx.childs[i].move;
      }
      console.log("Weight: " + w + "; Win = " + ctx.childs[i].win + "; All = " + ctx.childs[i].all + "; Move = " + ctx.childs[i].move.toString());
  }
  ...
}

Ходы по эвристикам конечно хуже чем то, что даёт UCT, но, в не очень сложных играх, они дают компьютеру «дожить» до того момента, когда UCT сможет работать. Весовые коэффициенты подобраны таким образом, чтобы эвристики оказывали заметное влияние лишь в тех случаях, когда алгоритм Монте-Карло не работает.

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




Главная причина в том, что я не смог придумать для этой игры простую и адекватную эвристику. В результате, программа делает свои ходы «на ощупь». При наличии достаточных вычислительных ресурсов это не было бы проблемой (алгоритм Монте-Карло подходит для этой игры как нельзя кстати), но 3 секунды расчёта хода в одном потоке — это пока максимум того, что я могу себе позволить (кстати, UCT можно очень хорошо масштабируется при наличии нескольких потоков).

Конечно же, метод Монте-Карло, в том виде, как он у меня сейчас реализован, подходит далеко не для всех игр. Я не собираюсь на нём зацикливаться. Для игр, подобных Шахматам, пожалуй, минимакс подойдёт лучше. Я ещё буду иметь возможность исследовать этот вопрос. Также, у меня есть кое какие мысли по поводу улучшения текущей реализации UCT. Посмотрим, что получится лучше.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330320/


Метки:  

Распределенные структуры данных (часть 2, как это сделано)

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

В предыдущей статье — часть 1, обзорная — я рассказал о том, зачем нужны распределенные структуры данных (далее — РСД) и разобрал несколько вариантов, предлагаемых распределенным кешем Apache Ignite.


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


Итак:




Начнем с того, что, как минимум в случае с Apache Ignite, РСД не реализованы с нуля, а являются надстройкой над распределенным кешем.


Распределенный кеш — это ...

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


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


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


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


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


Например, при старте кеша укажем что:


  • партиций будет 4 [A,B,C,D]
  • каждая партиция будет храниться на двух серверах (т.е. каждая будет иметь по одному бекапу)

Запустим четыре data node [JVM 1-4] (ответственные за хранение данных) и одну client node [Client JVM] (ответственную только за предоставление доступа к данным).


Каждая из четырёх data node может быть использована как client node (то есть предоставлять доступ ко всем данным). Например, JVM 1 смогла получить данные по партициям A,C,D, хотя, локально, располагает только A (Primary) и D (Backup).


Primary и Backup node

Любая data node распределенного кеша для конкретной партиции может являться Primary или Backup, либо вообще не содержать партицию.


Primary node отличается от Backup тем, что именно она обрабатывает запросы в рамках партиции и, по необходимости, реплицирует результаты на Backup node.


В случае выхода Primary node из строя, одна из Backup node становится Primary.


В случае выхода Primary node из строя, при отсутствии Backup node, партиция считается утерянной.


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



Рапределенные кеши разделяют на Partitioned и Replicated.


Разница состоит в том, что Partitioned-кеш хранит один (или один + N бекапов) экзепляр партиции в рамках кластера, а Replicated хранит по одному экземпляру партиции на каждой data node.



Partitioned-кеш имеет смысл использовать для хранения данных, чьи объемы превышают возможности отдельных серверов, а Replicated — для хранения одних и тех же данных «везде».


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


Итак, перейдем к подробностям реализации.


Традиционное пояснение

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


Для обеспечения работы РСД используются два кеша: один Replicated и один Partitioned.


Replicated-кеш — в данном случае это системный кеш, (ignite-sys-cache) отвечающий, в том числе, за хранение информации об РСД, зарегистрированных в системе.


Partitioned-кеш (ignite-atomics-sys-cache) хранит данные, необходимые для работы РСД, и их состояние.


Итак, большинство РСД создается следующим образом:


  1. Транзакция стартует.
  2. В кеше ignite-sys-cache, по ключу DATA_STRUCTURES_KEY, берется Map<Имя_РСД, DataStructureInfo> (при необходимости создается), и в нее добавляется новый элемент с описанием, например, IgniteAtomicReference.
  3. В кеш ignite-atomics-sys-cache, по ключу из добавленного ранее DataStructureInfo добавляется элемент, отвечающий за состояние РСД.
  4. Транзакция коммитится.

При первом запросе на создание РСД создается новый экземпляр, а последующие запросы получают уже ранее созданный.


IgniteAtomicReference и IgniteAtomicLong (краткая вводная)


Третий шаг инициализации для обоих типов сводится к добавлению в ignite-atomics-sys-cache объекта типа GridCacheAtomicReferenceValue или GridCacheAtomicLongValue.


Оба класса содержат одно единственное поле val.


Соответственно, любое изменение IgniteAtomicReference:


// Изменим значение, если текущее соответствует ожидаемому.
ref.compareAndSet(expVal, newVal);

… это запуск EntryProcessor со следующим кодом метода process:


EntryProcessor — это ...

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


Метод process принимает MutableEntry (объект в кеше) и может изменить его значение.


EntryProcessor, по сути, является альтернативой транзакции по одному ключу (иногда даже реализуется как транзакция).


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


Boolean process(MutableEntry> e, Object... args) {
    GridCacheAtomicReferenceValue val = e.getValue();

    T curVal = val.get();

    // Переменные expVal и newVal  — параметры метода
    // ref.compareAndSet(expVal, newVal);
    if (F.eq(expVal, curVal)) {
        e.setValue(new GridCacheAtomicReferenceValue(newVal));

        return true;
    }

    return false;
}

IgniteAtomicLong является дефакто расширением IgniteAtomicReference, поэтому и его метод compareAndSet реализован аналогичным образом.


Метод incrementAndGet не имеет проверок на ожидаемое значение, а просто добавляет единицу.


Long process(MutableEntry e, Object... args) {
    GridCacheAtomicLongValue val = e.getValue();

    long newVal = val.get() + 1;

    e.setValue(new GridCacheAtomicLongValue(newVal));

    return newVal;
}

IgniteAtomicSequence (краткая вводная)


При создании каждого экземпляра IgniteAtomicSequence...


// Создадим или получим ранее созданный IgniteAtomicSequence.
final IgniteAtomicSequence seq = ignite.atomicSequence("seqName", 0, true);

… ему выделяется пул идентификаторов.


// Начинаем транзакцию
try (GridNearTxLocal tx = CU.txStartInternal(ctx, seqView, PESSIMISTIC, REPEATABLE_READ)) {
GridCacheAtomicSequenceValue seqVal = cast(dsView.get(key), GridCacheAtomicSequenceValue.class);

// Нижняя граница локального пула идентификаторов
locCntr = seqVal.get();

// Верхняя граница
upBound = locCntr + off;

seqVal.set(upBound + 1);

// Обновляем экземпляр GridCacheAtomicSequenceValue в кеше
dsView.put(key, seqVal);

// Завершаем транзакцию
tx.commit();

Соответственно, вызов...


seq.incrementAndGet(); 

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


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


IgniteCountDownLatch (краткая вводная)


Декремент счетчика:


latch.countDown();

… реализуется следующим образом:


 // Начинаем транзакцию
 try (GridNearTxLocal tx = CU.txStartInternal(ctx, latchView, PESSIMISTIC, REPEATABLE_READ)) {
    GridCacheCountDownLatchValue latchVal = latchView.get(key);

    int retVal;

    if (val > 0) {
        // Декрементируем значение
        retVal = latchVal.get() - val;

        if (retVal < 0)
            retVal = 0;
    }
    else
        retVal = 0;

    latchVal.set(retVal);

    // Сохраняем значение
    latchView.put(key, latchVal);

    // Завершаем транзакцию
    tx.commit();

    return retVal;
}

Ожидание декрементации счетчика до 0...


latch.await();

… реализуется через механизм Continuous Queries, то есть при каждом изменении GridCacheCountDownLatchValue в кеше все экземпляры IgniteCountDownLatch уведомляются об этих изменениях.


Каждый экземпляр IgniteCountDownLatch имеет локальный:


/** Internal latch (transient). */
private CountDownLatch internalLatch;

Каждое уведомление декрементирует internalLatch до актуального значения. Поэтому latch.await() реализуется очень просто:


if (internalLatch.getCount() > 0)
    internalLatch.await();

IgniteSemaphore (краткая вводная)


Получение разрешения...


semaphore.acquire();

… происходит следующим образом:


// Пока разрешение не будет получено
for (;;) {
    int expVal = getState();

    int newVal = expVal - acquires;

    try (GridNearTxLocal tx = CU.txStartInternal(ctx, semView, PESSIMISTIC, REPEATABLE_READ)) {
        GridCacheSemaphoreState val = semView.get(key);

        boolean retVal = val.getCount() == expVal;

        if (retVal) {
            // Сохраняем информацию о получивших разрешения.
            // В случае выхода из строя какой-либо node,
            // захваченные ею разрешения будут возвращены.
            {
                UUID nodeID = ctx.localNodeId();

                Map map = val.getWaiters();

                int waitingCnt = expVal - newVal;

                if (map.containsKey(nodeID))
                    waitingCnt += map.get(nodeID);

                map.put(nodeID, waitingCnt);

                val.setWaiters(map);
            }

            // Устанавливаем новое значение
            val.setCount(newVal);

            semView.put(key, val);

            tx.commit();
        }

        return retVal;
    }
}

Возврат разрешения...


semaphore.release();

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


int newVal = cur + releases;

IgniteQueue (краткая вводная)


В отличие от остальных РСД, IgniteQueue не использует ignite-atomics-sys-cache. Используемый кеш описывается через параметр colCfg.


// Создадим или получим ранее созданный IgniteQueue.
IgniteQueue queue = ignite.queue("queueName", 0, colCfg);

В зависимости от указанного Atomicity Mode (TRANSACTIONAL, ATOMIC) можно получить разные варианты IgniteQueue.


queue = new GridCacheQueueProxy(cctx, cctx.atomic() ? 
    new GridAtomicCacheQueueImpl<>(name, hdr, cctx) : 
    new GridTransactionalCacheQueueImpl<>(name, hdr, cctx));

В обоих случаях состояние IgniteQueue контролируется с помощью:


class GridCacheQueueHeader{
   private long head;
   private long tail;
   private int cap;
... 

Для добавления элемента используется AddProcessor...


Long process(MutableEntry e, Object... args) {
    GridCacheQueueHeader hdr = e.getValue();

    boolean rmvd = queueRemoved(hdr, id);

    if (rmvd || !spaceAvailable(hdr, size))
        return rmvd ? QUEUE_REMOVED_IDX : null;

    GridCacheQueueHeader newHdr = new GridCacheQueueHeader(hdr.id(),
        hdr.capacity(),
        hdr.collocated(),
        hdr.head(),
        hdr.tail() + size, // Выделяем место под элемент
        hdr.removedIndexes());

    e.setValue(newHdr);

    return hdr.tail();
}

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


После этого...


// По ключу, сформированному на основе
// нового hdr.tail()
QueueItemKey key = itemKey(idx);

… в очередь добавляется новый элемент:


cache.getAndPut(key, item);

Удаление элемента происходит аналогично, но указатель меняется не на tail, а на head...


GridCacheQueueHeader newHdr = new GridCacheQueueHeader(hdr.id(),
    hdr.capacity(),
    hdr.collocated(),
    hdr.head() + 1, // Двигаем указатель на голову
    hdr.tail(),
    null);

… и элемент удаляется.


Long idx = transformHeader(new PollProcessor(id));

QueueItemKey key = itemKey(idx);

T data = (T)cache.getAndRemove(key);

Разница между GridAtomicCacheQueueImpl и GridTransactionalCacheQueueImpl состоит в том, что:


  • GridAtomicCacheQueueImpl при добавлении элемента сначала атомарно инкрементирует hdr.tail(), а потом уже добавляет по полученному индексу элемент в кеш.


  • GridTransactionalCacheQueueImpl делает оба действия в рамках одной транзакции.

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


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


Эта проблема решается таймаутом ожидания значения.


long stop = U.currentTimeMillis() + RETRY_TIMEOUT;

while (U.currentTimeMillis() < stop) {
    data = (T)cache.getAndRemove(key);

    if (data != null)
        return data;
}

Пара слов о надежности нетранзакционного решения

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


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


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


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


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

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

https://habrahabr.ru/post/328368/


Метки:  

[Из песочницы] awless.io, могучий CLI для AWS

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

Метки:  

Путешествие внутрь Avito: платформа

Четверг, 08 Июня 2017 г. 13:20 + в цитатник
image

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


Аппаратная часть


Долгое время наши серверы стояли в датацентре Basefarm в Швеции, но в январе-феврале прошлого года мы справились с масштабной задачей по переезду в московский датацентр Dataspace. Про миграцию, если это будет интересно, расскажу в отдельной статье (про перенос базы мы уже рассказывали на Highload 2016).
Переезд был вызван несколькими причинами. Во-первых, нашумевшим законом №242-ФЗ о хранении персональных данных граждан РФ. Во-вторых, мы получили больше контроля над своим железом — не всегда расторопные работники шведского датацентра могли выполнять простейшие заявки по несколько дней; здесь же персонал делает всё быстро, да и в любом случае мы всегда можем лично приехать в ДЦ и поучаствовать в решении возникших проблем.

Серверы


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

Сеть


Наша сеть построена по классической двухуровневой схеме: ядро плюс уровень доступа. Для отказоустойчивости каждый коммутатор уровня доступа подключается по оптике к двум разным корневым коммутаторам; поверх этих двух линков делается LACP-линк (один виртуальный линк поверх нескольких физических, позволяет полностью утилизировать все физические линки и добавляет устойчивость к отказу физических линков).

Программная часть


Виртуализация


Аппаратная виртуализация как таковая у нас не используется, а вот виртуализация на уровне операционной системы (aka контейнеры) — очень даже. В основном это LXC (когда-то давно использовалась OpenVZ), но сейчас мы с интересом смотрим на Docker (с Kubernetes) и потихоньку перебираемся на него, а новые микросервисы запускаем сразу в кластере Kubernetes.

О том, как мы используем Kubernetes, мы рассказывали на профильном митапе и Codefest 2017:


Хранилище картинок


История хранилища картинок подробно описана в статье. Сейчас оно имеет двухуровневую структуру: первый уровень — маленькие картинки (те, что используются в поисковой выдаче и, соответственно, часто запрашиваются; разрешением до 640x640) плюс кэш больших картинок, второй уровень — большие картинки, которые доступны только из карточки объявления. Прямого доступа извне к серверам второго уровня нет, всё проходит через первый уровень (и таким образом оседает в кэше). Ввиду разного профиля нагрузки на разные уровни, конфигурация и количество серверов в каждом уровне также различаются: на первом уровне много серверов с дисками небольшого объёма, а на втором уровне немного (~ в пять раз меньше) серверов с дисками большого объёма.

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

image

Если вдаваться в подробности, то у нас есть по 100 виртуальных картиночных нод первого и второго уровня, которые равномерно раскиданы по физическим серверам соответствующих уровней. Привязка виртуальных нод к физическим регулируется с помощью CNAME-записей в DNS и, в случае с первым уровнем, внешних IP на серверах.
Для снижения нагрузки на наши серверы и экономии трафика и электроэнергии мы используем CDN, однако наша платформа обладает достаточными ресурсами для того, чтобы работать самостоятельно, и мы не завязаны на конкретном провайдере.

Устройство платформы


Входящий трафик балансируется на разных уровнях: L3, L4, L7.
Внутреннее устройство платформы можно описать как “находится в процессе перехода с монолита на микросервисы”. Функциональность поделена на куски, которые мы называем “сервисами” — это ещё не микросервисы, но уже не монолит.

Устройство сервиса типовое: фронтенд на nginx, бекэнд — собственно сервис, и некоторый набор прокси до всех необходимых источников данных — БД, кэшей, других сервисов.

image

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

Заключение


Часто от высоконагруженных проектов ждут сложной архитектуры, пятиэтажных решений, требующих непрерывной поддержки. Это неправильно — чем сложнее система, тем больше неприятностей может породить самый незначительный баг. Поэтому мы за простоту. Мы придерживаемся принципа KISS, не плодим сущности и не усложняем то, что должно быть простым — и в разработке, и в поддержке, и в администрировании.
Такое устройство платформы позволяет нам легко её масштабировать, а значит избегать множества проблем. Сейчас мы находимся в переходном возрасте периоде и обратили свой взгляд на современные и удобные вещи: Docker и микросервисы. Скоро расскажем, что из этого получится.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330414/


Метки:  

Ethernet-коммутаторы Brocade

Четверг, 08 Июня 2017 г. 13:09 + в цитатник
Brocade, известный большинству как производитель коммутаторов для сетей хранения данных, выпускает и Ethernet-коммутаторы. Некоторый набор таких коммутаторов (ICX и VDX) оказался у нас в руках, и мне хочется сделать короткий обзор и отметить вещи, которые показались интересными. Я постараюсь избежать маркетинговых формулировок и цифр, но для интересующихся укажу ссылки на сайт производителя. Приступим :)

Коммутаторы ICX

Эти коммутаторы предназначены для использования в сети предприятия (Enterprise Campus). Семейство ICX состоит из линеек доступа (7150/7250/7450), агрегации (7450) и агрегации/ядра (7750).

ICX 7150 – младшее и последнее пополнение в семействе ICX. Кроме стандартных моделей на 24 и 48 портов в этой линейке имеется компактный коммутатор на 12 портов (7150-C12P) и коммутатор с портами 802.3bz Multigigabit Ethernet (7150-48ZP). Модели на 12/24/48 портов имеют пассивное охлаждение, а модели на 24/48 портов с PoE могут работать без использования активного охлаждения.

ICX 7250 – стандартные модели на 24 и 48 портов. Основное отличие – 8 uplink/stacking портов.

ICX 7450 – стандартные модели на 24 и 48 портов. Коммутаторы не имеют встроенных uplink/stacking портов, но имеют 3 слота для модулей дополнительных интерфейсов (1GE, 10GE, 40GE). Также в этой линейке есть коммутатор с портами 802.3bz Multigigabit Ethernet (7450-32ZP) и коммутатор агрегации 7450-48F (48x1GE SFP).

ICX 7750 – агрегация/ядро. Доступны 3 модели (48x10BASE-T, 48x1/10GE SFP/SFP+, 26x40GE QSFP), все поддерживают установку дополнительного модуля на 6x40GE QSFP портов. Все порты 40GE поддерживают режим breakout (разделение порта 40GE на 4 порта 10GE).

Коммутаторы линейки ICX поддерживают стандартный для такого позиционирования набор технологий, откровенных пробелов в функционале не замечено. В линейках 7150/7250/7450 некоторые модели в дополнение к PoE+ поддерживают Power over HDBaseT (до 90 Ватт на порт).

ПО для управления и мониторинга коммутаторов – Brocade Network Advisor (работает под Windows или Linux, на отдельном сервере либо в виде виртуальной машины).

Что хочется отметить из особенностей:
  • Стек коммутаторов. Все коммутаторы ICX поддерживают организацию стека через uplink/stacking порты, собирать стек можно в пределах линейки (т.е. 7250 с 7450, например, не собрать). Максимальное количество коммутаторов в стеке – 12. Для стекирования используются обычные порты 10GE или 40GE, максимальная пропускная способность 480Гбит/с. Максимальная протяжённость соединения для стека – 10 км (long-distance stacking). Поддерживаются как кольцевая, так и линейная топология.
  • Для тех, кто не рассматривает стекирование как вариант обеспечения отказоустойчивости, 7750 предлагает альтернативный вариант – Multi-Chassis Trunking (он же MC-LAG). Т.е. пара коммутаторов собирается в кластер, который подключённые к кластеру устройства видят как одно логическое устройство.
  • Лицензирование. Для 7150/7250/7450 основными лицензиями являются Port on Demand (лицензия на 10GE порты) и лицензия на L3 функционал (протоколы динамической маршрутизации, PIM, PBR, VRRP и т.д.). 7750 имеет только одну лицензию – L3 – которая не требует активации.
  • С точки зрения образов ОС коммутаторов существует два вида: switch image и router image. Каждый коммутатор имеет два flash (primary и secondary) и по умолчанию содержит оба вида image.
  • Комбинации OC image и L3 лицензии дают нам следующие варианта feature set: Layer 2 (switch image без лицензии), базовый Layer 3 (router image без лицензии), полный Layer 3 (router image с лицензией). Если вам требуется, например, статическая маршрутизация, то хватит базового Layer 3.
  • Поддерживаемые возможности удобно указаны в документе Features and Standards Support Matrix. Я бы даже сказал, что это образцовый документ.
  • Функционал Time Domain Reflectometer, который у Brocade называется Virtual Cable Test.
  • 7150 – новая линейка, и некоторые вещи в datasheet обозначены как Feature to be supported in a future software release. В июле планируется выпуск ПО, в котором среди прочего будет стекирование и L3-функционал.

А теперь посмотрим, что можно собрать на базе ICX. Кроме обычной двух/трёхуровневой архитектуры (на standalone коммутаторах + Multi-Chassis Trunking) для Enterprise Campus предлагаются два решения.

Первое, с использованием стекирования и, опционально, с учётом long-distance стекирования, может выглядеть таким образом

Схема, думаю, не требует комментариев.

Второе решение называется Campus Fabric. Фактически это реализация стандарта 802.1BR (Bridge Port Extension) на коммутаторах ICX, где 7750 выступает в роли единой точки контроля (Control Bridge — CB), а остальные коммутаторы в роли выносных линейных карт (Port Extenders — PE).

Какие преимущества даёт такая архитектура?
  • Это распределённое шасси, в котором легко можно увеличить портовую ёмкость.
  • Все линки активны.
  • Централизованный management plane и control plane.
  • L3-лицензия, если требуется, нужна только на Control Bridge, что позволяет сэкономить на L3-лицензиях.

Но есть и спорные моменты:
  • Централизованный control plane можно рассматривать как недостаток, т.к. вся фабрика – один failure domain.
  • Весь трафик идёт через ядро фабрики (Control Bridge). Исключением является multicast и broadcast replication, которые делаются на Port Extender локально.
  • На портах доступа Port Extender’ов не поддерживается LAG.

По масштабированию/резервированию отмечу следующие вещи:
  • Control Bridge на базе 7750 является стеком из 4х (максимум) коммутаторов, рекомендованная топология стека – кольцо. Используем минимум 2 коммутатора, т.к. нам обязательно нужно резервирование Control Bridge.
  • В качестве Port Extenders можно использовать 7450 и 7250. Поддержка 7150 будет позже.
  • PoD лицензии всё ещё нужны.
  • Максимальное количество Port Extenders – 36. Стек коммутаторов считается как отдельные коммутаторы.
  • Возможность подключать Port Extenders по цепочке – до 6 устройств.

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

Коммутаторы VDX

Напомню, как выглядит folded Clos сеть:

Leaf-коммутаторы обеспечивают подключение серверов, Spine-коммутаторы обеспечивают зарезервированную высокоскоростную связность для leaf-коммутаторов. На картинке изображён 3-stage (leaf-spine-leaf) вариант такой сети, но Brocade в документации рассматривает и 5-stage (leaf-spine-superspine-spine-leaf) вариант.

В семействе VDX я хотел бы остановиться на двух линейках: 6740 и 6940.

VDX 6740 – leaf-коммутаторы с портами 48x10GE (10GBASE-T либо SFP+) + 4x40GE QSFP.

VDX 6940 – leaf/spine-коммутаторы. 6940-36Q – 36x40GE QSFP портов. 6940-144S – 96x10GE SFP+ и 12x40GE QSFP портов (при этом 3 40GE порта можно объединить в один 100GE порт и использовать трансиверы QSFP28).

Эти коммутаторы позиционируются для использования в ЦОД, и имеют соответствующие характеристики:
  • Все порты 40GE поддерживают режим breakout (разделение порта 40GE на 4 порта 10GE).
  • Поддерживается как front-to-back, так и back-to-front охлаждение.
  • Два блока питания.
  • Поддержка FCoE и DCB.
  • Поддержка средств автоматизации, возможность интеграции с OpenStack и продуктами VMware.
  • Поддержка VXLAN.

Не буду отрицать, что сеть ЦОД на скоростях 10GE/40GE немного устарела, но коммутаторы 25GE/100GE у Brocade в другом семействе (SLX), и к нам они не попали.

Из особенностей коммутаторов VDX отмечу следующее:
  • Лицензирование. Есть два вида лицензий – Port on Demand (на 10GE и 40GE порты) и лицензия на FCoE. Лицензии PoD автоматически «привязываются» к активным портам. Т.е. вы достали коммутатор из коробки, включили, и вам не нужно искать в документации, какая группа портов активируется лицензией – можно просто устанавливать трансиверы. Для возврата лицензии в пул свободных лицензий нужно будет выполнить несколько команд в CLI.
  • Коммутаторы поддерживают VCS Fabric – TRILL-based Ethernet-фабрика (до 48 коммутаторов). TRILL-based, т.к. от TRILL используется только data-plane, а control-plane используется свой. Вещь неприхотливая к топологии, удобная как в настройке, так и в обслуживании.
    Непривычно то, что коммутаторы VDX всегда находятся в режиме Logical Chassis, т.е. фактически каждый коммутатор – это VCS-фабрика из одного коммутатора. И, т.к. в рамках VCS-фабрики конфигурация сохраняется автоматически, на коммутаторах VDX вы не найдёте аналога copy run startup.
    VCS является базовым функционалом, но использование VCS-фабрики – вещь опциональная и отключаемая.
  • Два flash, но, в отличие от ICX, тут они для отказоустойчивости и удобства обновления ПО. Разделения образов ОС по вариантам тут нет.
  • Поддерживаемые возможности всё так же указаны в документе Features and Standards Support Matrix. Подход к написанию документации в этом плане не отличается от ICX.
  • Т.к. это Brocade, то вполне ожидаемо, что некоторые технологии SAN-коммутаторов можно встретить на Ethernet-коммутаторах. Например, это MAPS (продвинутый мониторинг) и часть технологий VCS-фабрики.
  • Все фирменные DAC (медный direct attach) на 10GE и 40GE – активные.

Архитектуры

Кроме дизайнов на базе VCS-фабрики Brocade, конечно, предлагает дизайны на базе IP-фабрики. Это Clos-сеть (3-stage либо 5-stage), где граница L2/L3 находится на leaf-коммутаторах, а связность leaf-spine и ECMP обеспечивает протокол динамической маршрутизации (как правило это BGP).

IP-фабрика с pervasive eBGP (используем eBGP для всех типов связности)

IP-фабрика с iBGP (eBGP используется только для связности super-spine <-> spine и super-spine <-> edge leaf, iBGP используется в пределах DC POD для spine <-> leaf).

В обоих случая для подключения серверов к двум leaf-коммутаторам (multihoming) используется VCS-фабрика из двух коммутаторов (vLAG pair).

И не забываем про VXLAN. Brocade поддерживает виртуализацию с VXLAN в качестве data-plane, при этом в качестве control plane можно использовать EVPN. Итак, берём дизайны IP-фабрики, прибавляем EVPN VXLAN и получаем варианты:
c eBGP


и с iBGP

Для multihoming’а используется тот же механизм что и в IP-фабрике.

Brocade не настаивает на использовании iBGP или eBGP, оба варианта равнозначны. Brocade поддерживает оба варианта Integrated Routing and Bridging для EVPN VXLAN: asymmetric и symmetric. Из тех реализаций EVPN VXLAN, что я видел, на VDX одна из самых полнофункциональных.

Конечно, кроме VDX существует множество других продуктов Brocade для ЦОД, но в данной статье они не рассматриваются.


В заключение хочу добавить, что каких-то существенных претензий к качеству оборудования и софта не возникло. CLI, как и у многих других производителей, очень похож на Cisco, в некоторых местах он даже удобнее (а мы знаем, что часть CLI у Cisco далека от идеала). Документация по каждому продукту собрана в одном месте (Document Library), и написана эта документация очень правильно. Validated Design вообще одно удовольствие читать. Ну и напомню ещё раз про документы Features and Standards Support Matrix – кое-кому неплохо было бы перенять такой подход. Развитое и активное community, что есть не у каждого производителя. Сложность.

И немного про текущий статус Brocade.

Broadcom покупает весь бизнес Brocade, при этом решения Fibre Channel (т.е. всё для SAN) остаются в портфеле решений Broadcom, а оставшиеся продукты Brocade будут проданы другим компаниям. Сделка Broadcom-Brocade завершится в 3 финансовом квартале (заканчивается 30 июля 2017).

Что будет с остальными продуктами:
  • ARRIS покупает Ruckus Wireless и линейку коммутаторов ICX (которые, по всей видимости, будут продаваться как Ruckus ICX). При этом заявлено, что Ruckus Wireless сохранит свою структуру и канал продаж, т.е. будет что-то наподобие сделки Meraki-Cisco. Сделка Broadcom-ARRIS должна завершиться к концу августа 2017.
  • Extreme Networks покупает решения для ЦОД, а именно продукты VDX/MLX/SLX, Brocade Workflow Composer и Network Visibility & Analytics. Сделка Broadcom-Extreme должна завершиться к концу сентября 2017.
  • Pulse Secure покупает семейство продуктов vADC (virtual Traffic Manager и связанные с ним продукты).
  • AT&T покупает платформу Vyatta (Vyatta Network OS и связанные с ней продукты).
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330500/


Метки:  

Firebase на I/O 2017: новые возможности

Четверг, 08 Июня 2017 г. 12:58 + в цитатник
Гостевая статья от участника Google I\O 2017 и GDG Lead в Нижнем НовгородеАлександра Денисова.

Привет Хабр! Совсем недавно в Маунтин-Вью, Калифорния прошла очередная международная конференция, посвященная технологиям Google — I/O 2017. Кто-то ездил на нее в Калифорнию, кто-то приходил на I/O Extended организованные региональными отделениями GDG комьюнити, кто-то смотрел трансляцию самостоятельно, а кто-то не смотрел вовсе (На всякий случай оставлю это тут: все сессии I/O 2017 в записи). О том насколько была хороша или не очень хороша конференция в этом году, мнения противоречивы, я могу сказать только лично от себя, мне очень понравилось.

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

Интеграция с Fabric



О том что Google приобрел Fabric у Twitter я слышал уже некоторое время назад, но на I/O я воочию увидел групп менеджера из Fabric Рича Пэрета из Fabric и кофаундера Firebase Эндрю Ли на одной сцене, обсуждающих перспективы объединения команд и дружески подкалывающих друг друга.



Итак, что же мы получили в результате этого слияния? Во-первых, Crahslytics в скором времени будет интегрирован в Firebase как основное решение для crash reporting! Уже сейчас в консоли Crash Reporting мы видим приглашение установить сервис Crashlytics и поучаствовать в его тестировании, а в скором времени он полностью заменит Firebase Crash Reporting.



Во-вторых, интеграция с сервисом Digits теперь позволяет аутентификацию по номеру телефона! Бесплатно можно будет осуществлять 10 тысяч аутентификаций в месяц, что вполне должно покрыть нужды разработчиков. А Digits SDK как самостоятельный продукт в ближайшее время получит статус deprecated.



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

Динамический хостинг с Firebase Cloud Functions


Еще в марте, на Google NEXT’17, ребята из команды Firebase рассказали о запуске нового сервиса Cloud Functions for Firebase. Сервис предоставляет возможность размещать небольшие JavaScript функции непосредственно в Google Cloud инфраструктуре, и исполнять их в качестве реакции на события, вызванные сервисами Firebase или HTTP запросами.

Это позволяет кастомизировать или расширять стандартную работу сервисов Firebase своими фичами, такими как отправка welcome email каждому новому пользователю (Authentication), отслеживать и удалять ненормативную лексику в постах или чатах (Realtime Database), конвертировать изображения при загрузке в хранилище (Storage) и тп.

Для тех кто не пробовал, покажу пример применения Cloud Functions. Возьмем из GitHub исходники FriendlyChat, приложения создание которого я описывал в прошлогодней статье. Привяжем его к чистому Firebase проекту и добавим Cloud Function, которая будет автоматически приветствовать всех новых пользователей в чате.

Первым делом придется установить Node.js, а затем установить Firebase Command Line Interface (CLI) командой:

npm -g install firebase-tools

авторизоваться в интерфейсе командой

firebase login

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

firebase init functions

В результате в папке создастся структура проекта, заходим в папку functions и находим index.js, здесь и будут хранится наши функции. Если открыть файл, то в нем будет только одна строчка — const functions = require('firebase-functions'); — это собственно подключение Firebase SDK. Добавим туда подключение Admin SDK:

const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

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

exports.addWelcomeMessages = functions.auth.user().onCreate(event => {
	  const user = event.data;
	  console.log('A new user signed in for the first time.');
	  const fullName = user.displayName || 'Anonymous';

  	// В базу данных будет положено сообщение от файрбез бота о добавлении нового пользователя
  	return admin.database().ref('messages').push({
    	name: 'Firebase Bot',
    	photoUrl: 'https://image.ibb.co/b7A7Sa/firebase_logo.png', // Firebase logo выгружен на первый попавшийся image hosting
    	text: '${fullName} signed in for the first time! Welcome!'
  });
});

Осталось выгрузить функцию в облако и все:


firebase deploy --only functions

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

Но все это было представлено еще до I/O! Непосредственно на нем, Firebase представил новинку, которая должна порадовать сообщество веб-разработчиков. Сервис Firebase Hosting, который раньше позволял работать только со статическим контентом, был расширен интеграцией с Cloud Functions, и теперь работает с динамическим контентом, формируемым сервисом Cloud Functions.

Теперь разработчики занимающиеся progressive web приложениями, смогут полностью отказаться от своего сервера и использовать только Firebase.

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

Firebase Performance Monitoring


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

Для того чтоб сервис начал собирать данные о производительности вашего приложения, необходимо подключить Performance Monitoring SDK, после этого сервис сразу начнет собирать данные. Сервис будет предоставлять отчеты в виде так называемых трейсов (trace) — отчетов о производительности между двумя событиями в вашем приложении. Сразу после подключения начнут собираться данные для автоматических трейсов:

  • App start trace — измеряет время между тем когда пользователь запустил приложение и тем когда приложение отозвалось
  • App in background trace — измеряет время нахождения приложения в бекграунде
  • App in foreground trace — измеряет время активности приложения

Подключим сервис к приложению, чтобы посмотреть как это выглядит. Я взял стандартное приложение из google codelabs — FriendlyChat и подключил его к своей базе. Теперь подключим Performance Monitoring, для этого добавим в project-level build.gradle в секцию buildscript -> repositories:

jcenter() 

и в секцию buildscript -> dependencies

classpath 'com.google.firebase:firebase-plugins:1.1.0'

затем в app-level build.gradle в секцию dependencies

compile 'com.google.firebase:firebase-perf:10.2.6'

и под apply plugin: 'com.android.application'

apply plugin: 'com.google.firebase.firebase-perf'

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

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

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

Trace myTrace = FirebasePerformance.getInstance().newTrace("test_trace");
myTrace.start();

а после участка

myTrace.stop();

Я добавил трассировку загрузки изображения в чат, ну и ради интереса добавим счетчик

myTrace.incrementCounter("storage_load");

Но результаты в консоли доступны не сразу, они появятся там в течении 12-ти часов.



Усовершенствованная аналитика


Начну с того, что Firebase Analytics больше не существует, теперь сервис называется Google Analytics for Firebase, и это неспроста. Сервис был разработан совместно командами Firebase и Google Analytics, а все отчеты теперь доступны не только в консоли Firebase, но и в интерфейсе Google Analytics.





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



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

Добавилось еще много всяких интересных фич, интеграция с AdMob, автоматический Screen Tracking, бесплатный Storage Tier в BigQuery…. так что полагаю, что для аналитики все-таки тоже придется писать отдельную статью.

Firebase SDK — теперь в опенсорсе


Да, это именно так. Исходный код Firebase SDK теперь доступен для изучения на GitHub. Не весь конечно, на данный момент доступны исходники Firebase iOS SDK 4.0, Firebase JavaScript SDK 4.0 и Firebase Admin SDKs (Node.js, Java и Python). Следующим обещают выложить Android SDK, будем ждать с нетерпением.



Теперь можно будет поправлять Google, если что-то в коде вам не понравится! То есть теперь, если вы найдете какие-то, с вашей точки зрения, баги — можно будет просто создать issue через стандартный GitHub issue tracker и Firebase команда рассмотрит ее. Весь проект можно так же найти в Google Open Source Directory.

Приятные мелочи


И напоследок я вкратце расскажу о всяких приятных мелочах, которые были добавлены в уже существующие сервисы.

Realtime Database:

  • Расширены возможности, теперь доступно до 100000 одновременных подключений
  • Добавлена возможность профилирования, profiler позволяет анализировать скорость работы с данными, пропускную способность и время задержки в зависимости от уровня

Storage:

  • Добавлен мапинг на уже существующие cloud storage bucket’ы, теперь можно работать с ними через Firebase
  • Появилась возможность выбора региона, в котором будут хранится ваши данные. Это может быть полезно как с юридической точки зрения, так и с точки зрения производительности

Cloud Messaging:

  • Добавлена поддержка аутентификации на токенах для APN, и значительно упрощена логика соединения и регистрации в клиентском SDK.

TestLab:

  • Добавлены Game Loop support и FPS мониторинг, что в сочетании с Unity SDK и C++ SDK, представленными ранее, должно сделать Firebase привлекательной для разработчиков игр.
  • Добавлена возможность симуляции уровня сети, можно выбрать скорость подключения 4G, 3G и т.п.
  • В датацентре появились Google Pixel и Galaxy S7 для тестирования приложений на реальных устройствах последнего поколения
  • Появился доступ к Android O

А также, не привязываясь ни к какому из сервисов, еще добавлю что в iOS SDK была реализована поддержка Swift, что должно порадовать разработчиков под iOS работающих с Firebase.

Итак, какие можно сделать выводы? Ничего супер неожиданного и сногсшибательного на I/O представлено не было. Но Firebase растет, растет медленно и уверенно. Используя ее сервисы в качестве бэкэнда уже можно создавать вполне конкурентноспособные приложения, анализировать их работу, управлять их продвижением и монетизировать. И чем дальше, тем больше интересных инструментов появляется у пользователей.

P.S: На I/O было озвучено интересное предложение от от Firebase — программа Альфа (без VPN не откроется). У тех кто зарегистрируется и выразит свое желание участвовать в программе, будет возможность проверить обновления сервисов Firebase до их релиза. Они будут не идеальные (думаю, что местами совсем сырые), но, приняв участие в Альфа-сообществе, формируя фидбэки на еще не выпущенные продукты, вы поможете определить будущее Firebase!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330488/


Метки:  

[recovery mode] Отслеживание отправки форм с помощью GTM

Четверг, 08 Июня 2017 г. 10:35 + в цитатник
image

Всем привет!

Краткое вступление:
Если у вас есть грамотные разработчики и формы на вашем сайте можно отследить с помощью стандартного триггера “Отправка формы” в Google Tag Manager или встроить событие в обработчик — я вам искренне завидую:) Сегодня мы рассматриваем другой случай.

ПРОБЛЕМА:
Последнее время всё реже можно встретить ситуацию, когда после отправки формы пользователь перенаправляется на новую страницу. Все манипуляции обычно происходят по тому же адресу. То есть для отправки данных используется технология AJAX.

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

Как «косячили» раньше:
Раньше отправку форм отслеживали по индивидуальному адресу страницы. Если его не было — просили разработчиков изменить саму логику работы формы.

Как «косячат» сейчас:
Относительно новые технологии позволяют отправлять данные без перезагрузки страниц. Это создает проблему для отслеживания отправки форм: вместо изменившейся ссылки отслеживают НАЖАТИЕ на кнопку, а не факт отправки.

Плюсы таких подходов:
• Простота в установке цели. Если вы не знаете, как это делать, то сможете достаточно быстро в этом разобраться.
• Большее количество заявок *sarcasm*.

Минусы:
• Выполненные цели не совпадают с количеством заявок. Погрешность при этом может в среднем составлять 20-30%.
• Данные по результативности источников трафика также не будут соответствовать действительности.

К тому же, трудности возникают, когда нам необходимо внести правки в код сайта, чтобы ПРАВИЛЬНО отправить событие об отправке формы:
• Разработчики клиента не знают, что/как/где нужно исправить. Эта проблема встречается довольно часто.
• Сайт находится на сторонней платформе (nethouse, insales, wix, LPgenerator и др.). Они не всегда дают возможность оперативно изменять код.

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

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

РЕШЕНИЕ:
1. Необходимо сгенерировать код GTM и установить его на сайт в соответствии с требованиями Google Tag Manager:
tagmanager.google.com

2. На вкладке с триггерами добавить новый — “Модель DOM Готова”.
image

3. На вкладке “Теги” создать новый с типом “Пользовательский HTML”, а в качестве триггера выбрать созданный на предыдущем шаге.

image

Сам код:

image

Он поможет отслеживать отправку форм.
Подробнее о коде можете прочитать здесь: vk.cc/6Au3Jj

4. Затем создать переменную для данных об успешной отправке.
Чтобы узнать, какую переменную тянуть, необходимо:
— Заполнить и отправить форму
image

— Открыть консоль браузера и отправить запрос к уровню данных (скорее всего, вида «dataLayer» без кавычек). После этого появится несколько объектов
image

В этом конкретном случае есть два объекта «ajaxSuccessData». В URL первого — “говорящая ссылка” об отправке сообщения. Второй показывает на странице блок с сообщением “Заявка отправлена”.

У вас не появились похожие данные? Вполне возможно, в вашем коде GTM просто используется другое название уровня данных.
Проверить название уровня можно в коде GTM:image

5. Создать переменную: GTM -> Переменные -> Создать
На предыдущем скриншоте интересен только статус «success»:true в переменной уровня данных responseText, которая в свою очередь находится внутри контейнера ajaxSuccessData.

image

Как в этом случае проверить наличие статуса «success»:true? В поле имя переменной уровня данной нужно ввести через точку их названия:
ajaxSuccessData.responseText

Имя самой переменной может быть любым.

image

6. Создать триггер.
— Название триггера должно быть говорящим.
— Тип триггера «Пользовательское событие»
— Имя события — “ajaxSuccess”:
image

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

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

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

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

image

image

Сайты разные, но последовательность действий, описанная выше, для всех одна.

Отслеживайте цели правильно, и пусть ваши продажи постигнут дзен!

Автор: Павел Мрыкин, руководитель отдела автоматизации и аналитики в digital-агентстве
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330472/


«Корпоративный сектор»: Что такое эксклюзивные блокчейны

Четверг, 08 Июня 2017 г. 10:26 + в цитатник
Биткойн-блокчейн хорошо проявил себя в качестве децентрализованной электронной платежной платформы. Поэтому не удивительно, что успех биткойна привел к попыткам различных компаний адаптировать технологию для корпоративного применения. Например, эстонский LHV Bank внедрил систему платежей Cuber, основанную на окрашенных монетах (colored coins), организованных поверх биткойн-блокчейна.

Однако разработчики корпоративных приложений быстро пришли к пониманию, что биткойн-блокчейн не может полностью удовлетворить их требования, по крайней мере, в краткосрочной перспективе. Это привело к появлению эксклюзивных блокчейнов (permissioned blockchain), о которых мы поговорим в сегодняшнем материале.

/ изображение Adam Bailey CC

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

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

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

И мировые организации уже изучают возможности построения собственных эксклюзивных блокчейнов. Три крупных нидерландских банка ABN Amro, ING и Rabobank исследуют использование блокчейна для платежных систем. А, например, компания Citigroup построила три блокчейна и внутреннюю валюту на их основе с целью минимизации рисков при взаимодействии с другими банками.

Особенности эксклюзивных блокчейнов


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

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

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

«Закрытые блокчейны предоставляют компаниям интересную возможность использовать бездоверительность и прозрачность [блокчейнов] во внутренних и межкорпоративных сценариях», — говорит Дэн Василюк (Dan Wasyluk), руководитель команды Syscoin.

Создание блоков в эксклюзивном блокчейне не требует доказательства работы (proof-of-work). Вместо него, для консенсуса в эксклюзивных блокчейнах могут использоваться хорошо изученные алгоритмы консенсуса с аутентифицированными участниками, например, Practical Byzantine Fault Tolerance (PBFT). Другой пример — протокол создания блоков, используемый в BitShares. В подобных алгоритмах у каждого обработчика транзакций есть пара ключей — закрытый и открытый. Создатели блоков известны и определяются по цифровой подписи блока.

Фреймворки для эксклюзивных блокчейнов


Блокчейны с эксклюзивным доступом менее глобальны по сравнению с общедоступными блокчейнами. При их создании разработчики не ставят целью построить единую инфраструктуру для какой-нибудь отрасли в целом. По этой причине разработка эксклюзивных блокчейнов ведется на основе фреймворков, в то время как общедоступные блокчейны больше похожи на PaaS-решения. Грубо говоря, блокчейн-фреймворки по своим задачам напоминают СУБД (одну и ту же СУБД можно подставить в back-end множества сайтов), а общедоступные блокчейны — веб-платформы наподобие Twitter или Facebook (каждая платформа уникальна и имеет свой набор характеристик).

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

  • IBM Fabric. Компания IBM начала разработку своего блокчейн-фреймворка в 2015 году. В 2016 году ИТ-гигант стал одним из основателей Hyperledger — проекта под крылом The Linux Foundation, направленного на разработку enterprise-стандартов для блокчейнов и распределенных реестров. Фреймворк написан на Go и использует Docker-контейнеры для реализации смарт-контрактов.

  • Intel Sawtooth Lake. Intel подошла к блокчейну с точки зрения интернета вещей (Internet of Things). Из особенностей Sawtooth Lake можно выделить алгоритм консенсуса proof of elapsed time (PoET), который использует модуль доверенных вычислений SGX, встроенный в процессоры Intel последних поколений. Реализован на Python.

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

  • Enterprise Ethereum. Несмотря на то что Ethereum является общедоступным блокчейном, его разработчики уделяют много внимания использованию кода продукта для создания эксклюзивных блокчейнов. В начале 2017 года они объявили об организации альянса Enterprise Ethereum, целью которого является разработка функций, ориентированных на бизнес (например, выделение алгоритма консенсуса в отдельный модуль).

Помимо перечисленных решений, есть множество других фреймворков: Chain, Monax, Symbiont, Axoni и так далее. Также имеется ряд инициатив, приближающих блокчейн биткойна к корпоративной среде, например BloqEnterprise.

Привязка к блокчейнам


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

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

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

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

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


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

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

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

https://habrahabr.ru/post/330370/


Метки:  

Пишем пасьянс «Косынка»

Четверг, 08 Июня 2017 г. 10:25 + в цитатник
Девять лет назад я имел неосторожность приобрести приставку PSP, чему был очень рад. Омрачало радость только отсутствие пасьянса. Не то, чтобы я был любителем пасьянса, но как-то привык я раскладывать один из вариантов — “Косынку”. Пришлось такой пасьянс написать самому. В дальнейшем этот написанный для PSP пасьянс я портировал под Windows и под QNX. В этой вот статье я и расскажу, как написать такую игру.



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

Зададим ящики, где могут находиться карты вот такой вот структурой:

//масти
enum CARD_SUIT
{
 //пики
 CARD_SUIT_SPADES,
 //червы
 CARD_SUIT_HEARTS,
 //трефы
 CARD_SUIT_CLUBS,
 //буби
 CARD_SUIT_DIAMONDS
};
  struct SCard
  {
   CARD_SUIT Suit;//масть
   long Value;//значение карты от двойки до туза
   bool Visible;//true-карта видима
  } sCard_Box[13][53];//тринадцать ящиков по 52 карты в каждой максимум


Всего у нас 13 ящиков. Каждый ящик состоит из 52 отделений. Вот они на рисунке:


Ящики на игровом поле

Флаг видимости карты означает, что карта открыта. Примем, что если значение карты отрицательно, то больше карт в ящике нет.
В каждый ящик можно поместить максимум 52 карты и ещё признак того, что больше карт нет – всего 53 отделения-ячейки.
Нам потребуется функция для перемещения карт между ящиками. Вот она:

//----------------------------------------------------------------------------------------------------
//переместить карту из ящика s в ячейку d
//----------------------------------------------------------------------------------------------------
bool CWnd_Main::MoveCard(long s,long d)
{
 long n;
 long s_end=0;
 long d_end=0;
 //ищем первые свободные места в ящиках
 for(n=0;n<52;n++)
 {
  s_end=n;
  if (sCard_Box[s][n].Value<0) break;
 }
 for(n=0;n<52;n++)
 {
  d_end=n;
  if (sCard_Box[d][n].Value<0) break;
 }
 if (s_end==0) return(false);//начальный ящик пуст
 //иначе переносим карты
 sCard_Box[d][d_end]=sCard_Box[s][s_end-1];
 sCard_Box[s][s_end-1].Value=-1;//карты там больше нет
 return(true);
}


Здесь мы ищем индекс отделения из которого можно взять и индекс отделения в которое можно положить. Но правила перемещения с учётом масти и значения карты эта функция не проверяет. Это просто перемещение нижних карт из одного ящика в другой.

Также нам потребуется функция перемещения карт из нулевого ящика в первый. Эти ящики являются магазином, так что их содержимое перемещается по кругу.
//----------------------------------------------------------------------------------------------------
//перемещение карт внутри колоды
//----------------------------------------------------------------------------------------------------
void CWnd_Main::RotatePool(void)
{
 bool r=MoveCard(0,1);//перемещаем карты из нулевого ящика в первый
 if (r==false)//карт нет
 {
  //перемещаем обратно
  while(MoveCard(1,0)==true);
 }
}


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

Теперь нам нужно инициализировать расклад. Сделаем это вот так:
//----------------------------------------------------------------------------------------------------
//инициализировать расклад
//----------------------------------------------------------------------------------------------------
void CWnd_Main::InitGame(void)
{
 TimerMode=TIMER_MODE_NONE;
 long value=sCursor.Number[0]+10*sCursor.Number[1]+100*sCursor.Number[2]+1000*sCursor.Number[3]+10000*sCursor.Number[4];
 srand(value);
 long n,m,s;
 //выставляем все отделения ящиков в исходное положение
 for(s=0;s<13;s++)
  for(n=0;n<53;n++) sCard_Box[s][n].Value=-1;
 //помещаем в исходный ящик карты
 long index=0;
 CARD_SUIT suit[4]={CARD_SUIT_SPADES,CARD_SUIT_HEARTS,CARD_SUIT_CLUBS,CARD_SUIT_DIAMONDS};
 for(s=0;s<4;s++)
 {
  for(n=0;n<13;n++,index++)
  {
   sCard_Box[0][index].Value=n;//ставим карты
   sCard_Box[0][index].Suit=suit[s];
   sCard_Box[0][index].Visible=true;
  }
 }
 //теперь разбрасываем карты по ящикам
 for(n=0;n<7;n++)
 {
  for(m=0;m<=n;m++)
  {
   long change=RND(100);
   for(s=0;s<=change;s++) RotatePool();//пропускаем карты
   //перемещаем карту
   if (MoveCard(0,n+2)==false)//если пусто в ящике 0 - делаем заново
   {
    m--;
    continue;
   }
   long amount=GetCardInBox(n+2);
   if (amount>0) sCard_Box[n+2][amount-1].Visible=false;//карты невидимы
  }
 }
 //приводим магазин в исходное состояние
 while(1)
 {
  if (GetCardInBox(1)==0) break;//если пусто в ящике 1
  RotatePool();//пропускаем карты
 }
}


Изначально все карты помещаются в нулевой ящик (магазин), затем этот ящик прокручивается на случайное число, а затем карта просто перемещается в остальные ящики с индексами от 2 до 8. Можно, конечно, раскидывать карты так, чтобы пасьянс гарантированно собирался, но я так не сделал. А можно просто выбирать карту из 52 карт случайным образом и класть в нужный ящик. Так я тоже не стал делать.

Вышеприведённая функция использует ещё одну функцию:
//----------------------------------------------------------------------------------------------------
//получить количество карт в ящике
//----------------------------------------------------------------------------------------------------
long CWnd_Main::GetCardInBox(long box)
{
 long n;
 long amount=0;
 for(n=0;n<53;n++)
 {
  if (sCard_Box[box][n].Value<0) break;
  amount++;
 }
 return(amount);
}

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

Чтобы не отслеживать, какие карты видимы, а какие нет, я задал вот такую вот функцию:
//----------------------------------------------------------------------------------------------------
//сделать нижние карты всех рядов видимыми
//----------------------------------------------------------------------------------------------------
void CWnd_Main::OnVisibleCard(void)
{
 long n;
 for(n=2;n<9;n++)
 {
  long amount=GetCardInBox(n);
  if (amount>0) sCard_Box[n][amount-1].Visible=true;
 }
}

Она открывает все нижние карты в ящиках со второго по восьмой.

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

//----------------------------------------------------------------------------------------------------
//переместить карты из одного ящика в другой
//----------------------------------------------------------------------------------------------------
void CWnd_Main::ChangeBox(long s_box,long s_index,long d_box)
{
 long n;
 long d_end=0;
 //ищем первое свободное место в ящике назначения
 for(n=0;n<52;n++)
 {
  d_end=n;
  if (sCard_Box[d_box][n].Value<0) break;
 }
 //перемещаем туда карты из начального ящика
 for(n=s_index;n<52;n++,d_end++)
 {
  if (sCard_Box[s_box][n].Value<0) break;
  sCard_Box[d_box][d_end]=sCard_Box[s_box][n];
  sCard_Box[s_box][n].Value=-1;//карты там больше нет
 }
}

А вот полное перемещение карт с учётом всех правил выполняет другая функция, использующая ChangeBox.
//----------------------------------------------------------------------------------------------------
//переместить карты с учётом правил
//----------------------------------------------------------------------------------------------------
void CWnd_Main::ChangeCard(long s_box,long s_index,long d_box,long d_index)
{
 if (d_box>=2 && d_box<9)//если ящик на игровом поле
 {
  //если он пуст, то класть туда можно только короля
  if (d_index<0)
  {
   if (sCard_Box[s_box][s_index].Value==12) ChangeBox(s_box,s_index,d_box);//наша карта - король, перемещаем её
   return;
  }
  //иначе, класть можно в порядке убывания и разных цветовых мастей
  if (sCard_Box[d_box][d_index].Value<=sCard_Box[s_box][s_index].Value) return;//значение карты больше, чем та, что есть в ячейке ящика
  if (sCard_Box[d_box][d_index].Value>sCard_Box[s_box][s_index].Value+1) return;//можно класть только карты, отличающиеся по значению на 1
  CARD_SUIT md=sCard_Box[d_box][d_index].Suit;
  CARD_SUIT ms=sCard_Box[s_box][s_index].Suit;
  if ((md==CARD_SUIT_SPADES || md==CARD_SUIT_CLUBS) && (ms==CARD_SUIT_SPADES || ms==CARD_SUIT_CLUBS)) return;//цвета масти совпадают
  if ((md==CARD_SUIT_HEARTS || md==CARD_SUIT_DIAMONDS) && (ms==CARD_SUIT_HEARTS || ms==CARD_SUIT_DIAMONDS)) return;//цвета масти совпадают
  ChangeBox(s_box,s_index,d_box);//копируем карты
  return;
 }
 if (d_box>=9 && d_box<13)//если ящик на поле сборки
 {
  //если выбрано несколько карт, то так перемещать карты нельзя - только по одной
  if (GetCardInBox(s_box)>s_index+1) return;
  //если ящик пуст, то класть туда можно только туза
  if (d_index<0)
  {
   if (sCard_Box[s_box][s_index].Value==0)//наша карта - туз, перемещаем её
   {
    DrawMoveCard(s_box,s_index,d_box);   
   }
   return;
  }
  //иначе, класть можно в порядке возрастания и одинаковых цветовых мастей
  if (sCard_Box[d_box][d_index].Value>sCard_Box[s_box][s_index].Value) return;//значение карты меньше, чем та, что есть в ячейке ящика
  if (sCard_Box[d_box][d_index].Value+1/можно класть только карты, отличающиеся по значению на 1
  CARD_SUIT md=sCard_Box[d_box][d_index].Suit;
  CARD_SUIT ms=sCard_Box[s_box][s_index].Suit;
  if (ms!=md) return;//масти не совпадают
  DrawMoveCard(s_box,s_index,d_box);
  return;
 }
}

На поле сборки (ящики с индексами от 9 до 12) можно класть только одномастные карты в порядке увеличения значения, но первым должен быть всегда туз. На игровом поле цвета масти должны быть противоположны, значения карт должны увеличиваться, а переносить на пустое поле можно только короля.

Пасьянс собран, когда на поле сборки в каждом ящике ровно 13 карт:
//----------------------------------------------------------------------------------------------------
//проверить на собранность пасьянс
//----------------------------------------------------------------------------------------------------
bool CWnd_Main::CheckFinish(void)
{
 long n;
 for(n=9;n<13;n++)
 {
  if (GetCardInBox(n)!=13) return(false);
 }
 return(true);
}


Для удобной работы с ящиками есть массив с их координатами:
  //координаты расположения ячеек карт
  long BoxXPos[13][53];
  long BoxYPos[13][53];


Заполняется этот массив так:
 //размер поля по X
 #define BOX_WIDTH 30
 //положение ящиков 0 и 2 по X и Y
 #define BOX_0_1_OFFSET_X 5
 #define BOX_0_1_OFFSET_Y 5
 //положение ящиков с 2 по 8 по X и Y
 #define BOX_2_8_OFFSET_X 5
 #define BOX_2_8_OFFSET_Y 45
 //положение ящиков с 9 по 12 по X и Y
 #define BOX_9_12_OFFSET_X 95
 #define BOX_9_12_OFFSET_Y 5
 //смещение каждой следующей карты вниз
 #define CARD_DX_OFFSET 10
 //масштабный коэффициент относительно размеров карт на PSP
 #define SIZE_SCALE 2

 for(n=0;n<13;n++)
 {
  long xl=0;
  long yl=0;
  long dx=0;
  long dy=0;
  if (n<2)
  {
   xl=BOX_0_1_OFFSET_X+BOX_WIDTH*n;
   yl=BOX_0_1_OFFSET_Y;
   xl*=SIZE_SCALE;
   yl*=SIZE_SCALE;
   dx=0;
   dy=0;
  }
  if (n>=2 && n<9)
  {
   xl=BOX_2_8_OFFSET_X+BOX_WIDTH*(n-2);
   yl=BOX_2_8_OFFSET_Y;
   xl*=SIZE_SCALE;
   yl*=SIZE_SCALE;
   dx=0;
   dy=CARD_DX_OFFSET*SIZE_SCALE;
  }
  if (n>=9 && n<13)
  {
   xl=BOX_9_12_OFFSET_X+(n-9)*BOX_WIDTH;
   yl=BOX_9_12_OFFSET_Y;
   xl*=SIZE_SCALE;
   yl*=SIZE_SCALE;
   dx=0;
   dy=0;
  }
  for(m=0;m<53;m++)
  {
   BoxXPos[n][m]=xl+dx*m;
   BoxYPos[n][m]=yl+dy*m;
  }
 }


В этом массиве для каждого ящика формируются все расположения всех 52 карт колоды.
С помощью такого массива можно легко определить, что выбрал игрок мышкой:
//размер карты по X
#define CARD_WIDTH  27
//размер карты по Y
#define CARD_HEIGHT 37

//----------------------------------------------------------------------------------------------------
//определение что за ящик и номер ячейки в данной позиции экрана
//----------------------------------------------------------------------------------------------------
bool CWnd_Main::GetSelectBoxParam(long x,long y,long *box,long *index)
{
 *box=-1;
 *index=-1;
 long n,m;
 //проходим по ячейкам "магазина"
 for(n=0;n<13;n++)
 {
  long amount;
  amount=GetCardInBox(n);
  for(m=0;m<=amount;m++)//ради m<=amount сделана 53-я ячейка (чтобы щёлкать на пустых ячейках)
  {
   long xl=BoxXPos[n][m];
   long yl=BoxYPos[n][m];
   long xr=xl+CARD_WIDTH*SIZE_SCALE;
   long yr=yl+CARD_HEIGHT*SIZE_SCALE;
   if (x>=xl && x<=xr && y>=yl && y<=yr)
   {
    *box=n;
    if (mcode>


Собственно, на этом написание логической части пасьянса и заканчивается. Интерфейсную же часть вы можете сделать по своему вкусу. Поскольку я переносил программу с PSP (где она вертится в while(1)), то лично я привязал циклы к таймеру и каждому режиму таймера дал свой номер и обработчик. Также асинхронно привязал отработку OnPaint от таймера. Так проще всего оказалось сделать при портировании.

В архиве программа для Windows, для QNX и оригинал для PSP.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330470/


Метки:  

PHDays 2017: как это было

Четверг, 08 Июня 2017 г. 10:11 + в цитатник


Команда mClouds.ru побывала на международном форуме по практической безопасности Positive Hack Days (PHDdays VII), который прошёл 23-24 мая 2017 года в Москве. Форум собрал большой круг специалистов в области информационной безопасности, руководствуясь принципом — минимум рекламы и максимум полезных знаний.

Программа мероприятия состоит из следующих секций:
Технический доклад — презентация работ от «акул» информационной безопасности.
Секция/Бизнес-доклад — секция с участием представителей бизнеса.
Hands-on Labs — практические мастер-классы от профессионалов своего дела.
Fast Track / Young School — секция для молодых ученых, презентация собственных исследований, нацеленная на расширение границ знаний в сфере ИБ.

Стенды


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

Отметим понравившиеся нам стенды. Начнём с компании Positive Technologies, которая представила бета-версию бесплатного сканера уязвимостей PT BlackBox Scanner, для выявления уязвимостей в веб-приложениях.
Для проверки сканером вашего приложения потребуется подтвердить владение сайтом, и облачный сканер выполнит поиск слабых мест. Возможно сканирование с помощью агента без подтверждения прав владения сайтом.
Протестировать свой веб-ресурс возможно на сайте сканера — bbs.ptsecurity.com.

Ожидаем появление QRadar SIEM Community Edition для использования в предприятиях малого бизнеса с ограничением по EPS и с возможностью апгрейда количества обрабатываемых событий.

Краткой строкой




Microsoft за стенд с Windows и Xbox.


Ростелеком, спасибо за вкусный кофе и свежевыжатый сок!


Infotecs предоставил возможность пройти тест и протестировать ViPNet Alcotronic! / @roman_rrrrr

Axoft за аттракцион “hackers in da box”. Beyond Security — за форму регистрации с вводом ФИО, электронной почты и пароля на 40”+ тач мониторе с экранной клавиатурой.

Конкурсные площадки


Отдельно стоит упомянуть о конкурсах для участников форума.

Большой куш — банкомат и киоски самообслуживания, это те объекты, которые расположены на пути нашего следования до работы, учёбы и наших друзей. Набитые аккуратно нарезанной бумагой кассеты, часто становятся жертвами как умных, так и не очень умных жуликов. Посетители могут попробовать себя в роли исследователя систем ДБО и открыть мешочек с золотом в Hardware Village, в качестве подопытных используются два киоска для самообслуживания и один банкомат.


bystroff


Киоск дистанционного обслуживания #1


Киоск дистанционного обслуживания #2

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


@dmitryzakharenko

Наливайка — традиционные закрытие конкурсной программы на PHDays для участников достигших алкогольной зрелости. Прошедшим отбор участникам предстоит “испытать на прочность” веб-приложение, находящееся под защитой WAF (Web Application Firewall), и продемонстрировать навык трезво мыслить в любой ситуации.
При срабатывании “системы защиты” участникам каждые 5 минут предлагается выпить 50 мл крепкого и очень горячительного напитка, а после чего, продолжить борьбу до захвата главного игрового флага. Если главный флаг забрать не удалось, то победитель определяется по количеству набранных флагов в “игровое время”.

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




IoT by Google

Automotive Village: CarPWN — участники форума могут проверить на прочность безопасность автомобиля Tesla Model S. Поиск нужных проводов и блоков, правильное подключение к бортовой сети автомобиля и проведения MiTM-атаки, всё это возможно попробовать в течение двух дней форума с открытым стендом и доступом к Tesla!



WAF bypass — традиционный конкурс на PHDays, где требуется обойти межсетевой экран (МСЭ) от компании PT Application Firewall (PT AF). Победитель определяется исходя из количества заработанных баллов, которые начисляются за получение флагов. В этом году направление взято на обход нового компонента PT AF для защиты баз данных.



MITM Mobile — Перехват SMS, телефонных разговоров и USSD, развертывание и работа с ложными базовыми станциями — всё это можно увидеть на стенде и попробовать освоить техники для взлома собственного оператора. Стандарт GSM может быть взломан не только спецслужбами с дорогостоящим оборудованием, но и технически подкованным участником с железкой за $25.

HackBattle — решение сложных и неожиданных задач в режиме реального времени на главной сцене, где потребуется продемонстрировать навыки и умения работать в режиме повышенной нагрузкие с демонстрацией скорости и находчивости в решении предоставленных вопросов. Для участия в конкурсе требовалось пройти первый этап, отборочное испытание. Победитель получает Hak5 Field Kit и бурные овации от публики!

Рекомендуем к ознакомлению


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

Ты, а не тебя. Армии умных ботов в руках хакера — Генеральный директор компании «Лавина Пульс» Андрей Масалович, рассказал примеры из жизни начиная от распознавания капчи и сканирования SQL-инъекция до влияния на ход выборов.
“Противостояние в Сети сегодня — это не война между ботами и людьми, а скорее война между армиями «умных» ботов”

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

DDoS-атаки в 2016–2017: переворот — модификация в организации и проведении DDoS-атак, их изменения и причины, предпосылки и последствия, а также взаимосвязь с развитием IoT.

Хакер в ловушке, или Практическая демонстрация блокировки эксплойтов и криптолокера — мастер-класс с демонстрацией вредоносного кода и средств защиты в активном режиме (антивирус, URL-фильтрация, antispyware, IPS, Threat Intelligence, DNS Sinkholing, песочницы на базе Next Generation Firewall и т.п.).

Видеозаписи докладов публикуются на youtube канале и на официальном сайте мероприятия, остаётся только дождаться видео с PHDays VII. Ознакомиться с видео докладов прошлого года можно на официальном сайте PHDays VI.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330468/


Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 998 997 [996] 995 994 ..
.. 1 Календарь