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

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

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

Генерация документов. Проблемы и решения

Вторник, 01 Августа 2017 г. 21:34 + в цитатник
Для генерации документов по шаблонам важной задачей является сокращение количества шаблонов. Чем меньше шаблонов, тем легче их поддерживать, вносить в них изменения. Этого можно достичь, если шаблоны будут полиморфны, т.е. будут содержать в себе избыточность. В зависимости от параметров генерации лишние части во время генерации документа будут удаляться и в результате останутся только те части, которые требуются. Разметим, например, текст шаблона следующим образом:

Текст части 1.
Постоянно присутствующий текст. Текст части 2.


Передадим генератору в параметрах, что надо удалить (или оставить ). В результате получим:

Постоянно присутствующий текст. Текст части 2.

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


Для логической операци ИЛИ (удалять, если выбраны или ) разметка может быть следующей:
||Текст части 1.
Постоянно присутствующий текст. Текст части 2.


Перечислим достоинства и недостатки данного способа разметки шаблонов.

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

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

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

https://habrahabr.ru/post/334666/


Метки:  

[Перевод] Руководство для начинающих по прогрессивным веб-приложениям и фронтенду

Вторник, 01 Августа 2017 г. 20:04 + в цитатник

image


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


RESTful API


Первое, о чём я хочу рассказать, это концепция RESTful API. Термин REST, или RESTful API, всплывает во многих беседах между веб-разработчиками, и на то есть веская причина. REST (REpresentational State Transfer, передача состояния представления) API и веб-сервисы предоставляют простой способ взаимодействия с архитектурой бэкенда без необходимости разбираться в этой самой архитектуре.


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


RESTful API бывают самыми разными. Наиболее популярные из них возвращают JSON-объекты, которыми можно легко манипулировать посредством JavaScript на стороне клиента, что позволяет фронтенд-разработчикам эффективно работать с одними лишь частями View и Controller паттерна MVC (Model-View-Controller).


TL;DR: RESTful API очень популярны и предоставляют фронтенд-разработчикам возможность взаимодействовать с ресурсами в вебе, сосредоточившись на разработке фронтенда и не беспокоясь об архитектуре.


AJAX


AJAX (Asyncronous JavaScript And XML) существует уже немало лет, и каждый разработчик так или иначе использовал его в своей работе (большинство из нас — посредством jQuery). Здесь я не будут углубляться в устройство AJAX, поскольку в сети есть сотни источников получше, но хочу отнять у вас минутку времени, чтобы просто восхититься теми возможностями, которые эта технология даёт фронтенд-разработчикам.


С помощью AJAX мы можем запрашивать ресурсы из одного одного или нескольких мест (или локально, если страница расположена на том же сервере, что и запрашиваемый URI) и в любое время, без замедления работы веб-приложений или необходимости начать отрисовку всех данных. Фактически, мы можем не грузить любой контент на страницу, а затем просто запрашивать его, как только будет загружена пустая HTML-страница. В сочетании с RESTful API получается невероятно гибкое, высокопортируемое и удобное в сопровождении решение для веб-приложений.


TL;DR: AJAX — очень мощный инструмент, который в сочетании с RESTful API позволяет создавать по-настоящему динамичные веб-приложения, которые быстро загружаются и отображают контент из ресурсов в вебе.


Получение контента из веба


Поначалу создание вашей первой веб-страницы может показаться довольно трудной задачей, так что будем идти постепенно. Начнём с получения контента из RESTful API с помощью AJAX-вызовов.


Первым делом нужно найти высококачественный API, желательно такой, который возвращает JSON. Вот для примера несколько ресурсов, которые выводят placeholder-контент и пригодны для создания примера веб-приложения:


  • JSON Placeholder — placeholder-текст, выдаваемый в JSON-формате, подходящий для многих вариантов использования. Очень прост для начинающих, идеально подходит для заполнения макета (mockup) веб-приложения, вроде того, что мы с вами сделаем.
  • Unsplash It — placeholder-контент не будет полным без изображений, и именно отсюда их надо брать. Документация очень понятная и простая в применении, так что можно сразу начинать пользоваться.
  • Random User Generator — ещё один высококачественный ресурс, предоставляющий сгенерированные пользовательские профили, которые можно сконфигурировать под свои нужды. Здесь есть куча настроек, но для целей статьи нужно совсем немного.

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


Первое, что нужно сделать, прежде чем начать писать код, это посетить конечную точку одного из API и посмотреть, что вы будете получать. Давайте отправим GET-запрос в Random User Generator, просто для проверки. Вы получите что-то подобное:


image


Это называется JSON-файл (JavaScript Object Notation), который должен выглядеть для вас знакомым, если вы когда-либо использовали объекты в JavaScript. Давайте запросим тот же ресурс программным способом:


// Отправляем 'GET'-запрос на заданный URL и после его завершения исполняем callback-функцию
function httpGetAsync(url, callback) {
  var xmlHttp = new XMLHttpRequest();
  xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
      callback(xmlHttp.responseText);
  };
  xmlHttp.open('GET', url, true);
  xmlHttp.send(null);
}

Именно это и делает приведённый код, который занимает всего 10 строк (9 без комментария). Скармливаем соответствующую URL конечную точку API и функцию callback, и мы увидим какой-то контент. Допустим, вы создали пустую HTML-страницу и залинковали вышеприведённый JS-код. Теперь просто выполним её в браузерном инструментарии для разработчиков:


httpGetAsync(
  'https://randomuser.me/api/',
  function(e){console.log(e)}
);

Вы получите результат, аналогичный предыдущему, только теперь он будет обёрнут в двойные кавычки. Естественно, ведь это строковое значение. И что ещё естественнее, теперь мы можем конвертировать его в JS-объект посредством JSON.parse(), а затем использовать так, как предполагалось.


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


В частности, я бы сосредоточился на параметрах seed и results, которые можно встроить в наш URL, чтобы каждый раз получать тот же набор пользователей. Для их добавления нужно просто добавить после URL знак ?, а затем {parameter_name}={value}, разделяя параметры с помощью &. Полагаю, все об этом знают, но всё же нужно было об этом упомянуть. В этой статье я также воспользуюсь параметром nationalities, чтобы быть уверенным, что в HTML не будет не-латинских символов, которые усложнят мне жизнь. Отныне и впредь, моей целевой конечной точкой для получения пользователей будет эта, она поможет мне получить тех же 25 пользователей, и всех из США.


TL;DR: Чтобы начать разрабатывать веб-приложение, нужно найти высококачественный JSON API. С помощью 10 строк JavaScript-кода можно легко запрашивать ресурсы у RESTful API, которые выдают случайных пользователей, и потом конвертировать их в JavaScript-объекты.


Представление и головоломка с CSS-фреймворком


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


Инструкции по использованию классов и селекторов фреймворка применимы только к mini.css, но с очень небольшими правками они будут верны и для Bootstrap (считайте представление веб-приложения своей домашней работой, потому что здесь я не буду вдаваться в подробности относительно CSS).


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

, который уже присутствует в mini.css, но вы можете решить эту задачу так, как вам удобнее. Также я добавлю в панель навигации .drawer, который может быть заменён какими-нибудь кнопками, и, наконец,
, чтобы приложение выглядело чисто и аккуратно:


image


Я буду понемногу показывать свой код (после добавления карточки пользователя), но сначала скажу, почему использование CSS-фреймворка является хорошей идей. Попросту говоря, когда вы строите для веба, то существует слишком много тестовых вариантов, и некоторые комбинации устройства/ОС/браузера получаются более своеобразными, чем другие. CSS-фреймворк работает с этим особенностями по своему усмотрению, хотя в то же время предоставляет вам базовый каркас, который поможет создать адаптивное приложение (responsive application). Адаптивность крайне важна в разработке для мобильных устройств, так что почитайте об этом побольше.


Допустим, нас всё устраивает в оболочке приложения, давайте перейдём к отрисовке данных, полученных от Random User Generator. Я не собираюсь усложнять эту процедуру и выведу для каждого пользователя имя, изображение, ник, почту, местоположение и день рождения. Но вы можете придумать свой набор позиций. Не забудьте обратиться к ключу .results вашего объекта после парсинга JSON-данных, потому что в него всё обёрнуто. Чтобы всё выглядело красиво, я воспользуюсь замечательным пакетом иконок Feather, а также классом .card из mini.css и кое-какими CSS-трюками.


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


Теперь наше приложение динамически заполняется контентом, который мы выводим на экран с помощью JavaScript и HTML. Мы только что создали наше первое представление (View), являющееся причудливым способом сказать, что мы создали визуальное отображение данных, запрошенных у API.


TL;DR: Отзывчивость и стили крайне важны для любого веб-приложения, так что будет хорошей идеей использовать CSS-фреймворк для создания простой HTML-оболочки приложения, а затем отрисовки с помощью JavaScript данных, полученных от API.


JavaScript-библиотеки


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


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


Также React позволяет использовать JSX, благодаря чему мы можем писать HTML внутри JavaScript без необходимости оборачивать его в кавычки. Так что наш код может стать ещё немного чище. Однако помните, что придётся сделать некоторые преобразования, например из class в className. Но со временем вы привыкните, а отладочные сообщения в консоли действительно очень помогают в решении таких проблем.


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


// Функциональный компонент для иконки почты.
function SvgMail(props){
  return ;
}
// Функциональный компонент для иконки календаря.
function SvgCalendar(props){
  return ;
}
// Функциональный компонент для иконки прикрепления к карте.
function SvgMapPin(props){
  return ;
}
// Функциональный компонент для иконки пользовательской карточки.
function UserCard(props){
  var user = props.user;
  return 
{user.login.username}

{user.name.title} {user.name.first} {user.name.last} {user.login.username}

{user.email}

{user.dob.split(" ")[0].split("-").reverse().join("/")}

{user.location.city}, {user.location.state}

; } // Отрисовка списка пользователей в виде карточек. function renderUsers(){ var userCards = users.map( function(user, key){ return ; } ); ReactDOM.render(
{userCards}
,contentArea); }

Мы просто извлекли из предыдущего кода функциональный компонент, сделав его многократно используемой сущностью. Стоит взглянуть, что происходит под капотом, когда Babel преобразует HTML, предоставленный по вызовам React.createElement():


function SvgMapPin(props) {
  return React.createElement(
    'svg',
    { xmlns: 'http://www.w3.org/2000/svg', width: '24', height: '24', viewBox: '0 0 24 24', fill: 'none', stroke: '#424242', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round' },
    React.createElement('path', { d: 'M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z' }),
    React.createElement('circle', { cx: '12', cy: '10', r: '3' })
  );
}

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


TL;DR: Преобразование с помощью React неструктурированных вызовов HTML-отрисовки в функциональные компоненты — задача простая, и результат получается гораздо удобнее в сопровождении. При этом разработчик получает больше контроля над своим кодом, и повышается степень повторного использования.


Добавляем второе представление (view)


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


  • Мы будем отправлять GET-запрос на адрес https://jsonplaceholder.typicode.com/comments?postId={id}, что позволит получить 5 сегментов текста за раз в JSON-формате, инкрементируя {id}.
  • Также мы будем отправлять GET-запросы на адрес https://unsplash.it/800/800?image={id}, при этом будем каждый раз получать какую-то картинку. Для этого воспользуемся кодом, который будет генерировать случайный {id} для каждого запроса. В моём Codepen-примере я также добавил массив неправильных значений {id}, которые я извлёк из API, так что у нас не будет ни одного ответа без изображения.
  • После выполнения обоих запросов будем создавать карточку для каждого поста, случайным образом приписывая пользователя из списка в качестве автора, и затем отрисуем с помощью React.
  • Также добавим кнопку переключения между двумя представлениями, чтобы иметь возможность перейти к списку пользователей. Я добавлю её в выпадающее меню, но вы можете делать на свой вкус.

После аккуратного кодирования всего упомянутого и последующего совершенствования, у вас получится нечто, схожее с Singe Page Application (SPA): https://codepen.io/chalarangelo/pen/zzXzBv


TL;DR: Чтобы ваш макет выглядел как настоящее веб-приложение, достаточно добавить второе представление и некоторые интерактивные элементы.


Загружаем ещё больше контента


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


// Получает степень прокрутки страницы.
function getScrollPercent() {
  return (
    (document.documentElement.scrollTop || document.body.scrollTop) 
    / ( (document.documentElement.scrollHeight || document.body.scrollHeight) 
    - document.documentElement.clientHeight) 
    * 100);
}

Метод подсчитывает все кейсы и возвращает значение в диапазоне [0,100] (включительно). Если забиндить на window события scroll и resize, то можно быть уверенным, что когда пользователь достигнет конца страницы, то будет подгружен ещё контент. Вот как выглядит наше веб-приложение после добавления бесконечной прокрутки в представление с постами.


TL;DR: Бесконечная прокрутка — главное свойство любого современного веб-приложения. Она легка в реализации и позволяет динамически подгружать контент по мере необходимости.


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


Манифест веб-приложения


Прежде чем мы сможем сказать, что действительно сделали веб-приложение (не говоря уже о прогрессивном веб-приложении), нам нужно поработать с файлом manifest.json, который состоит из кучи свойств нашего приложения, включая name, short_name, icons. Манифест предоставляет клиентскому браузеру информацию о нашем веб-приложении. Но прежде чем мы им займёмся, нам нужно с помощью npm и настройки React поднять приложение и запустить на localhost. Полагаю, что с обеими вещами вы уже знакомы и не столкнётесь с трудностями, поэтому переходим к манифесту.


По моему опыту, чтобы получилось работающее приложение, вам понадобится заполнить так много полей, что я предлагаю воспользоваться Web App Manifest Generator и заполнить, что хотите. Если у вас есть время, чтобы сделать аккуратную иконку, то в этом вам поможет Favicon & App Icon Generator.


После того как всё сделаете, ваш манифест будет выглядеть так:


{
  "name": "Mockup Progressive Web App",
  "short_name": "Mock PWA",
  "description": "A mock progressive web app built with React and mini.css.",
  "lang": "en-US",
  "start_url": "./index.html",
  "display": "standalone",
  "theme_color": "#1a237e",
  "icons": [
    {
      "src": "\/android-icon-48x48.png",
      "sizes": "48x48",
      "type": "image\/png",
      "density": "1.0"
    },
    {
      "src": "\/android-icon-72x72.png",
      "sizes": "72x72",
      "type": "image\/png",
      "density": "1.5"
    }
  ]
}

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


TL;DR: Файл manifest.json используется для определения конкретных свойств веб-приложения, прокладывая нам путь к созданию прогрессивного веб-приложения.


Сервис-воркеры (Service Workers)


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


Мы будем создавать самый простой вариант сервис-воркера, позволяющий кэшировать ответы на запросы, передавая их по мере доступности. Сначала создадим файл service-worker.js, который и будет нашим сервис-воркером.


Теперь давайте разберёмся с тремя основными событиями, с которыми нам придётся работать:


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

Первое, что нам нужно сделать при установке, это воспользоваться CacheStorage Web API для создания кэша для веб-приложения и хранения любого статичного контента (иконок, HTML, CSS и JS-файлов). Это очень просто сделать:


// caches — это глобальная переменная только для чтения, являющаяся экземпляром CacheStorage
caches.open(cacheName).then(function(cache) {
  // Что-нибудь делаем с кэшем
});
// Источник: https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage/open

Можно быстро создать простой обработчик события install, который кэширует наши index.html, JavaScript-файл и manifest.json. Но сначала нужно задать имя кэша. Это позволит нам отделить версии тех же файлов или данных от оболочки приложения. Здесь мы не будем вдаваться в подробности относительно кэшей, но в конце статьи есть полезные ссылки. Помимо имени кэша, нужно определить, какие файлы будут кэшироваться с помощью массива. Вот как выглядит обработчик install:


var cacheName = 'mockApp-v1.0.0';
var filesToCache = [
  './',
  './index.html',
  './manifest.json',
  './static/js/bundle.js'
];

self.addEventListener('install', function(e) {
  e.waitUntil(caches.open(cacheName)
    .then(function(cache) {
      return cache.addAll(filesToCache)
        .then(function() {
          self.skipWaiting();
        });
      }));
});

Меньше чем в 20 строках мы сделали так, что наше веб-приложение использует кэш для своих ресурсов. Позвольте пояснить оду вещь. В ходе разработки наш JS-код компилируется в файл ./static/js/bundle.js. Это одна из причуд нашего development/production-окружения, и мы разберёмся с ней на следующем этапе.


Обработчик activate тоже довольно прост. Его главная задача: обновлять кэшированные файлы, когда что-то меняется в оболочке приложения. Если нам нужно обновить любые файлы, то нам придётся изменить cacheName (желательно в стиле SemVer). Наконец, обработчик fetch проверит, хранится ли в кэше запрошенный ресурс. Если он там есть, то будет передан из кэша. В противном случае ресурс будет запрошен как обычно, а ответ будет сохранён в кэше, чтобы его можно было использовать в будущем. Соберём всё вместе:


self.addEventListener('activate', function(e) {
  e.waitUntil(caches.keys()
    .then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        if (key !== cacheName)
          return caches.delete(key);
      }));
  }));
  return self.clients.claim();
});

self.addEventListener('fetch', function(e) {
  e.respondWith(caches.match(e.request)
    .then(function(response) {
      return response || fetch(e.request)
        .then(function (resp){
          return caches.open(cacheName)
            .then(function(cache){
              cache.put(e.request, resp.clone());
              return resp;
          })
        }).catch(function(event){
          console.log('Error fetching data!');
        })
      })
  );
});

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


if ('serviceWorker' in navigator) {
  navigator.serviceWorker
    .register('./service-worker.js')
    .then(function() { console.log('Registered service worker!'); });
}

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


image


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


TL;DR: Сервис-воркеры позволяют веб-приложениям настраивать кэши и использовать их для загрузки ресурсов без использования сети, превращая веб-приложения в прогрессивные.


Сборка для production


Всё, что мы сделали, прекрасно работает на localhost, но осмотр production-файлов после быстрого выполнения npm run build обнаруживает кучу ошибок, которые нужно исправить. Прежде всего, многие файлы неправильно залинкованы на/из HTML-страницы. Для решения этой проблемы нужно добавить одну строку в package.json:


"homepage" : "."

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


Следующая проблема: наш сервис-воркер указывает на неправильные JS-файлы, потому что static/js/bundle.js больше не существует. Если внимательнее посмотреть на собранные файлы, то станет понятно, что наш JS был преобразован в файл main.{hash}.js, где часть {hash} отличается для каждой сборки. Нам нужно иметь возможность загружать из сервис-воркера файл main.js. Следовательно, нужно переименовать его, но этого сломает ссылку внутри index.html, чего мы не хотим. Для решения обеих проблем воспользуемся сборочными инструментами из реестра npm — renamer и replace. Также нам нужно минифицировать наш service-worker.js, поскольку по умолчанию он не слишком компактен, потому что является частью папки public, так что воспользуемся ещё и утилитой uglify-js.


npm install --save-dev renamer
npm install --save-dev replace
npm install --save-dev uglify-js

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


"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build && npm run build-rename-replace && npm run build-sw",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject",
    "build-sw" : "npm run build-replace-sw-refs && npm run build-minify-sw",
    "build-rename-replace": "npm run build-rename && npm run build-replace",
    "build-rename": "npm run build-rename-js && npm run build-rename-css",
    "build-rename-js": "renamer --regex --find main\\.\\w+\\.js --replace main.js build/static/js/*.js",
    "build-rename-css": "renamer --regex --find main\\.\\w+\\.css --replace main.css build/static/css/*.css",
    "build-replace": "npm run build-replace-js && npm run build-replace-css",
    "build-replace-js": "replace main\\.\\w+\\.js main.js build/index.html",
    "build-replace-css": "replace main\\.\\w+\\.css main.css build/index.html",
    "build-replace-sw-refs": "replace './static/js/bundle.js' './static/js/main.js','./static/css/main.css' build/service-worker.js",
    "build-minify-sw" : "uglifyjs build/service-worker.js --output build/service-worker.js"
  }

Давайте разберёмся, что тут происходит:


  • build-rename запускает два скрипта, каждый из которых меняет имена JavaScript- и CSS-файлов, которые были созданы с желаемыми наименованиями (main.js и main.css соответственно).
  • build-replace запускает два скрипта, каждый из которых меняет меняет ссылки на JavaScript- и CSS-файлы на переименованные версии.
  • build-rename-replace собирает предыдущие две команды в одну.
  • build-sw обновляет в сервис-воркере ссылку на static/js/bundle.js, которая теперь указывает на новый файл main.js, а также добавляет ссылку на main.css. Затем минифицирует сервис-воркер.
  • Наконец, build собирает вместе всё вышеперечисленное в наш процесс сборки по умолчанию, так что все файлы попадают в папку build и готовы к выкладыванию на сайт.

Теперь при запуске npm run build должна генерироваться готовая к production версия нашего прогрессивного веб-приложения, которую можно хостить где угодно, просто копируя файлы из папки build.


TL;DR: Создание веб-приложения для production является интересной проблемой, требующей использования сборочных инструментов и разрешения скриптов. В нашем случае достаточно было обновить имена и ссылки.


Последние шаги


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


После прогона моей development-сборки на localhost я обнаружил несколько моментов, требующих исправления, вроде того, что у картинок нет атрибутов alt, внешние ссылки не имеют атрибута rel="noopener", а само веб-приложение не имеет географической привязки (landmark region), что было легко исправлено с помощью HTML-тега

. Исправив всё, что мог, я получил такой результат в Lighthouse:


image


Как видите, приложение получилось хорошо оптимизированным и качественным. Теперь я могу с гордостью выложить его на Github. Вот ссылка на законченное приложение; а вот ссылка на исходный код. Я взял на себя смелость добавить индикаторы Online/Offline, но вы можете их выкинуть. Теперь я могу установить приложение на смартфон и показать друзьям!


image


image


image


TL;DR: Прежде чем релизить веб-приложение, стоит проверить его качество с помощью Lighthouse и оптимизировать, насколько возможно.


Вот и всё мы создали с нуля прогрессивное веб-приложение. Надеюсь, вы чему-то научились. Спасибо за уделённое время!


Ссылки


  • MDN’s Getting started with AJAX — отличный ресурс для тех, кто хочет больше узнать об AJAX и как его использовать в веб-приложениях.
  • Если выбираете JSON API, то вас могут заинтересовать эти:
    UI Names — ещё один ресурс для генерирования случайных пользователей с большим количеством настроек.
    Robohash — генерирует аватары роботов на основании заданной строки. Удобно при создании пользовательских профилей или placeholder-изображений.
    Adorable Avatars — генерирует смешные аватары на основании заданной строки. Настроек чуть меньше, чем в Robohash, но задачу выполняет.
  • Из огромной экосистемы CSS-фреймворков можно выделить такие популярные продукты, как Bootstrap, Semantic UI, Bulma и Foundation. Предлагаю и свою альтернативу, mini.css, если вам нужно что-то более лёгкое.
  • Для UI-иконок обычно берут FontAwesome, но я рекомендую Feather, более лёгкие и минималистичные.
  • Если хотите больше узнать о diffing виртуального DOM, то очень рекомендую почитать эту статью.
  • Среди всех современных JavaScript-библиотек, React является самой популярной. Но хороши также Preact и VueJS, выбирайте, что больше нравится.
  • Манифесты веб-приложений хорошо задокументированы на сайтах MDN и Google Developers. Также можете воспользоваться Web App Manifest Generator, если хотите легко и быстро сгенерировать manifest.json.
  • Говоря о сервис-воркерах и прогрессивных веб-приложениях, я очень рекомендую создавать своё первое приложение так, как описано здесь и здесь. Также обратите внимание на жизненный цикл сервис-воркера. А если хотите заняться этой темой ещё плотнее, почитайте Indicating Offline (я его использовал для создания Online/Offline-индикаторов) и Offline Recipes for Service Workers.
  • Относительно CacheStorage Web API я рекомендую почитать эту статью, а также а также держать под рукой документацию MDN.
  • Если хотите оценить своё веб-приложение и исправить найденные проблемы, воспользуйтесь Lighthouse и Mobile Speed Test.
  • Наконец, изучите исходный код и демку на Github.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334536/


Метки:  

[Перевод] Генеративные модели от OpenAI

Вторник, 01 Августа 2017 г. 19:49 + в цитатник

Метки:  

Zimbra — выстраиваем коммуникации в компании

Вторник, 01 Августа 2017 г. 19:34 + в цитатник
Внутренние коммуникации в компании чрезвычайно важны, а их организация — отдельная проблема ИТ-департамента. Без коммуникаций невозможно своевременно обмениваться достоверной информацией и, следовательно, поддерживать рабочий процесс. Zimbra полностью закрывает потребности сотрудников любой компании по обмене информацией.

image



Существует два вида внутренних коммуникаций: с вертикальными и с горизонтальными связями.

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

  • «сверху вниз» (от руководителя к подчиненным);
  • «снизу вверх» (от подчиненных к руководителю).


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

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

Как это сделать


Для любой компании важны два направления связи:

Почта


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

Zimbra Collaboration Suite — программный продукт, аналог Microsoft Exchange, который представляет собой электронную почту корпоративного уровня, календарь и средство совместной работы. Zimbra одинаково подходит как крупным компаниям, так и небольшим фирмам. Включает в себя ряд бесплатных и открытых продуктов (Nginx, Apache, MySQL, Postfix и др.) и имеет очень удобный веб-клиент — Zimbra Web Client, который построен с использованием технологии AJAX, обеспечивающей всплывающие подсказки, перемещаемые объекты и контекстные меню. Также включены продвинутые возможности поиска и временные зависимости. Сюда же входят онлайн-документация, модули Zimlet и полноценный интерфейс для администраторов, написанные с помощью Zimbra Ajax Toolkit.



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

За безопасность почты отвечает персонализированная антиспам система SpamAssassin. Zimbra использует SpamAssassin для определения нежелательной коммерческой электронной почты и оценки сообщений. «Спамность» определяется в процентах. Любые сообщения, помеченные между 33-75% считаются спамом и перемещаются в папку Нежелательная почта. Сообщения с процентом «спамности» выше 75% всегда считаются спамом и отбрасываются. Функция Postscreen для фильтрации спама снижает нагрузку на инфраструктуру, отвечающую за SMTP процессы.

Чаты и видеоконференции


Мессенджеры плотно вошли в современную жизнь, а значит нужно поощрять и общение между сотрудниками в таком формате. Зимлет ZeXtras Chat добавляет в Zimbra Web Client полностью интегрированный IM-клиент, с помощью можно общаться как в текстовом чате, так и в формате видеоконференций. ZeXtras Chat Zimlet поддерживает два режима просмотра: компактная и сжимаемая «док-панель» и расширенная «боковая панель», подходящая при большом числе собеседников. Можно устанавливать статусы, управлять контактами и многое другое.





Таким образом с помощью Zimbra Collaboration можно обеспечить коммуникации в компании любого уровня.

Zimbra Collaboration

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

https://habrahabr.ru/post/334662/


Метки:  

5 свежих примеров разбора и улучшения дизайна простыми способами

Вторник, 01 Августа 2017 г. 18:41 + в цитатник
image

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

Стоп Обман: отделяем элементы


image



Этот логотип нам прислал Стоп Обман — команда энтузиастов, которая занимается разоблачением мошеннических интернет-курсов.

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

image

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

image

Пофантазируем о логотипе и его применении в жизни:

image

image

Как итог:
+ Знак стал лучше читаться
— Шляпа и маска не всегда ассоциируется с преступником. Может быть похоже на режим «инкогнито».

Интернет хостинг центр: успокаиваем композицию


Нам прислали такой логотип:
image

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

С цветами знака тоже можно поиграть — в исходном варианте много черных блоков. Можно использовать 3 основных цвета и оттенки.

Итог:
+ Композиция стала уверенней
— Сама задумка довольно скучная

3. SOHO: улучшаем читаемость и добавляем экспрессии


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

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

image

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

image

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

Применим к SOHO:
image

image

image

А букву «S» с фирменным паттерном можно использовать как отдельный знак.

Итог:
+ Название можно прочитать
+ Нет ассоциации с кофе
— Нет ассоциации с чем-то компьютерным, а это может быть важно

Glitch: усиливаем идею


Глитч — это анимационная лаборатория, ребята безумные креативщики и отобразили это в логотипе.

Здесь можно посоветовать максимально усилить логотип. “Glitch” — означает сбой, помеха, глюк, так добавим же этого по максимуму!
image

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

Социальные сети, их тоже можно оформить безумно!
image

Как итог:
+ Теперь идея логотипа считывается сходу
— Такой логотип сложно использовать на носителях



Red Paper Food: развиваем идею


Red Paper Food — очень интересный проект. Это инстаграм-аккаунт программиста, в котором автор размещает фотографии своих бенто-ланчей. Выглядит ярко и безумно вкусно!

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

Главное, что у канала появится фирменное сочетание цветов, которое поможет ему стать узнаваемым.
image

image

image

image

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

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

Почитать предыдущие выпуски можно по ссылкам:
Первый выпуск
Второй выпуск

До встречи, и конечно же, удачного дизайна вашим проектам!
Виктория Слепчевич для Логомашины
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334656/


Метки:  

[Перевод] Сравнение цен на трафик у облачных провайдеров

Вторник, 01 Августа 2017 г. 18:11 + в цитатник
В этой статье я сравниваю цены на внешний трафик из Amazon EC2, Google Cloud Platform, Microsoft Azure и Amazon Lightsail.

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

Для начала сравним два альтернативных варианта.

Вариант 1 — Колокейшн в дата-центре
100 Мбит/с (32,85 ТБ / месяц) за $950 = $28,91 за ТБ или $0,028 за ГБ / месяц

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

Вариант 2 — Google Fiber for Business
1000 Мбит/с (328,5 ТБ / месяц) за $250 = $0,76 за ТБ или $0,00076 за ГБ / месяц

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

Microsoft Azure
1 ТБ / месяц — $88,65 или $0,09 за ГБ

Вот где всё становится безобразным. Цена в 3 раза выше, чем на колокейшне, и в 116 раз выше, чем на Google Fiber.

Google Cloud Platform
1 ТБ / месяц — $122,88 или $0,12 за ГБ

Как такое может быть? Я даже не могу представить, как Google может выставлять такую высокую цену на своей платформе. Это в 4 раза выше, чем на колокейшне, и в 162 раз выше, чем на её собственном сервисе Google Fiber.

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

Amazon EC2
1 ТБ / месяц — $90 или $0,09 за ГБ

Снова в 3 раза дороже, чем на колокейшне, и в 116 раз дороже, чем на Google Fiber, а если к вас идут входящие данные, то они будут брать ещё $10 в месяц, поднимая цену до $0,10 за гигабайт.

Amazon Lightsail
2 ТБ / месяц — $10 или $0,005 за ГБ

На первый взгляд выглядит отлично, но это меня и бесит, потому что здесь гигантское «пошёл ты» для клиентов Amazon EC2, которые платят в 18 раз больше за свои первые 2 ТБ трафика.

Amazon даёт бесплатно 2 ТБ подписчикам на план Lightsail за $10 в месяц и только 1 ГБ в месяц бесплатно лояльным пользователям EC2.

Любой, кто сидит на EC2 с пятью или менее серверами t2.micro и использует хоть сколько-то трафика, должен немедленно перейти на Lightsail, если нет какой-то непреодолимой причины не делать этого. И я не могу представить, что это за непреодолимая причина может быть, потому что инстансы Lightsail могут работать с другими сервисами AWS.

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

За $50 в месяц вы можете получить 10 ТБ исходящего трафика по $0,005 за гигабайт.

Заключение
Amazon EC2, Microsoft Azure и Google Gloud Platform — все они серьёзно дурят своих пользователей с тарифами на трафик.

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

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

Хотите сегодня расшевелить рынок облачного хостинга? Дайте трафик по нормальным ценам.

Для записи: «Я люблю Amazon AWS!». Это супергибкий и прекрасный сервис — мне просто не нравятся их тарифы на трафик ;)
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334632/


Метки:  

Поиграем в Firebase

Вторник, 01 Августа 2017 г. 18:04 + в цитатник
Внутри: настольные игры, NFC метки, Firebase, ESP 8266, RFID-RC522, Android и щепотка магии.

image Меня зовут Оксана и я Android-разработчик в небольшой, но очень классной команде Trinity Digital. Тут я буду рассказывать об опыте создания настольной игрушки на базе Firebase и всяких разных железяк.

Так уж вышло, что желание запилить что-то забавное у нас совпало с необходимостью провести митап по Firebase в формате Google Developer Group в Петрозаводске. Стали мы думать, что бы такое устроить, чтобы и самим интересно, и на митапе показать можно, и на развитие потом работать, а в итоге увлеклись не на шутку и придумали целую интеллектуальную настольную игру.

Идея:


Допустим, есть целая куча игр разной степени “настольности” — MTG, Манчкин, DND, Эволюция, Мафия, Scrabble, тысячи их. Мы очень любим настолки за их атмосферность и “материальность”, то есть за возможность держать в руках красивые карточки/фишки, разглядывать, звучно хлопать ими об стол. И все настолки по-разному хороши, но имеют ряд недостатков, которые мешают погрузиться в игру с головой:

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

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

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

Задача:


Надо сделать маленькую, простенькую игру вроде “магического боя”. Парочка оппонентов швыряет друг в друга заклинаниями, выигрывает тот, кто первым прикончит соперника. У игроков есть некоторые статы, допустим, здоровье и мана. Каждое заклинание — это карта, заклинание стоит сколько-то маны и производит какой-то эффект (лечит, калечит, или еще что-нибудь).

Для реализации нам понадобится следующее:


  • куча NFC меток чтобы сделать из них карты (привет билеты московского метро!);
  • две штуки (для каждого игрока) ESP8266 + RFID-RC522 чтобы их считывать, когда делается ход и слать в сеть;
  • Firebase — чтобы хранить данные, обрабатывать ходы и изменять значения в модели в соответствии правилам;
  • Android — чтобы отображать все происходящее (свои статы, чужие статы) для игроков.



Всякие штуки типа “hello world” про Firebase я освещать не буду, благо материалов на этот счет итак достаточно, в том числе и на хабре. Всякие тонкости модели тоже не буду упоминать, чтобы не загружать деталями. Интереснее, как мы будем читать, записывать и обрабатывать данные.

Немножко про модель



Так в нашей базе выглядят игровые партии.image
”35:74:d6:65” — это id партии
states — это игроки
turns — это последовательность ходов

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

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

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



  • игрок выбирает карту, подносит ее к одному из считывателей (смотря к кому он хочет применять эффекты — к себе или к оппоненту);
  • тот пишет в Firebase Database — “сыграна карта N на игрока M”;
  • Firebase функция видит, что в последовательности ходов появилась новая запись, и обрабатывает ее: отнимает у игрока ману за сыгранную карту, приписывает целевому игроку эффекты с текущей карты, а потом применяет все эффекты, которые уже висят на игроках и уменьшает их длительность на 1;
  • ну а Android клиент просто отслеживает изменения в Firebase Database и отображает актуальные статы игроков в удобочитаемом виде.

image

Плавно продвигаемся к железкам и коду


А железки у нас такие: микроконтроллер ESP 8266 и считыватель RFID/NFC RFID-RC522. ESP 8266 в нашем случае хорош тем, что он небольшого размера, кушает мало, есть встроенный WI-FI модуль, а также Arduino совместимость (что позволит писать прошивки в привычной Arduino IDE).
Для прототипа мы взяли плату Node MCU v3, которая сделана на основе ESP 8266. Она позволяет заливать прошивки и питаться прямо через USB, что в рамках прототипирования вообще красота. Писать для нее можно на C и на Lua. Оставив в стороне нашу любовь к скриптовым языкам в целом и к Lua в частности, мы выбрали C, т.к. практически сразу нашли необходимый стек библиотек для реализации нашей идеи.

Ну а RFID-RC522 — это, наверное, самый простой и распространенный считыватель карт. Модуль работает через SPI и имеет следующую распиновку для подключения к ESP 8266:
image
Talk is cheap, show me the code!

Задача у нас такая:


  • Прочитать карточку;
  • Если это карточка-ключ для создания партии, создать в Firebase новую партию;
  • Если это игровая карта, то получить карту и заслать ее в Firebase (создать новый ход);
  • Помигать лампочкой.

Сканнер


Используется библиотека MFRC522. Взаимодействие со сканером идет через SPI:

void Scanner::init() {
    SPI.begin();      // включаем шину SPI
    rc522->PCD_Init();   // инициализируем библиотеку
    rc522->PCD_SetAntennaGain(rc522->RxGain_max); // задаем максимальную мощность
}

String Scanner::readCard() {  
    // если прочитали карту
    if(rc522->PICC_IsNewCardPresent() && rc522->PICC_ReadCardSerial()) {
        // переводим номер карты в вид XX:XX
        String uid = "";
        int uidSize = rc522->uid.size;
        for (byte i = 0; i < uidSize; i++) {
    
            if(i > 0)
                uid = uid + ":";
            if(rc522->uid.uidByte[i] < 0x10)
                uid = uid + "0";
            uid = uid + String(rc522->uid.uidByte[i], HEX);       
        } 
        return uid;
    }
    return "";
}

Firebase


Для Firebase есть замечательная библиотека FirebaseArduino, которая из коробки позволяет отправлять данные и отслеживать события. Поддерживает создание и отправку Json запросов.

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

Firebase.setInt("battles/" + battleId + "/states/" + player + "/hp", 50);
if(firebaseFailed()) return;

Где firebaseFailed() это:

int Cloud::firebaseFailed() {
    if (Firebase.failed()) {
         digitalWrite(ERROR_PIN, HIGH); // мигаем лампочкой
         Serial.print("setting or getting failed:");
         Serial.println(Firebase.error()); // печатаем в консоль
         delay(1000);
         digitalWrite(ERROR_PIN, LOW); // мигаем лампочкой
         return 1;
    }
    return 0;
}

Json запрос можно отправить следующим образом:

StaticJsonBuffer<200> jsonBuffer;
JsonObject& turn = jsonBuffer.createObject();  
turn["card"] = cardUid;
turn["target"] = player;
Firebase.set("battles/" + battleId + "/turns/" + turnNumber, turn);
if(firebaseFailed()) return 1; 

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

Теперь про специально обученные Firebase функции


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

exports.newTurn = functions.database.ref('/battles/{battleId}/turns/{turnId}').onWrite(event => {
  // нас интересует только создание нового хода, а не обновления
  if (event.data.previous.val())
    return;

  // читаем ходы
  admin.database().ref('/battles/' + event.params.battleId + '/turns').once('value')
    .then(function(snapshot) {
      // выясняем, кто кастит в этот ход
      var whoCasts = (snapshot.numChildren() + 1) % 2;
      // читаем игроков
      admin.database().ref('/battles/' + event.params.battleId + '/states').once('value')
      .then(function(snapshot) {
          var states = snapshot.val();
          var castingPlayer = states[whoCasts];
          var notCastingPlayer = states[(whoCasts + 1) % 2];
          var targetPlayer;
          if (whoCasts == event.data.current.val().target)
              targetPlayer = castingPlayer;
          else
              targetPlayer = notCastingPlayer;
          
          // сколько маны нужно отнять
          admin.database().ref('/cards/' + event.data.current.val().card).once('value')
          .then(function(snapshot) {
              var card = snapshot.val();
              // отнимаем
              castingPlayer.mana -= card.mana;
              
              // применяем эффекты с текущей карты
              var cardEffects = card.effects;
              if (!targetPlayer.effects)
              targetPlayer.effects = [];
              for (var i = 0; i < cardEffects.length; i++)
                  targetPlayer.effects.push(cardEffects[i]);
              
              // применяем все эффекты, которые уже есть на игроках
              playEffects(castingPlayer);
              playEffects(notCastingPlayer);
              
              // обновляем игроков
              return event.data.adminRef.root.child('battles').child(event.params.battleId)
                      .child('states').update(states);
          })
      })
  })
});

Функция playEffects выглядит следующим образом (да, там eval, но мы думаем что в демо-проекте это вполне допустимо):

function playEffects(player) {
    if (!player.effects)
        return;
    for (var i = 0; i < player.effects.length; i++) {
        var effect = player.effects[i];
        if (effect.duration > 0) {
            eval(effect.id + '(player)');
            effect.duration--;
        }
    }
}

Каждый из эффектов будет примерно таким:

function fire_damage(targetPlayer) {
    targetPlayer.hp -= getRandomInt(0, 11);
}


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

image

То есть у каждого из них есть имя, здоровье и мана. А если в них что-то прилетит, то появятся еще и эффекты:

image

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

exports.effectFinished = functions.database.ref('/battles/{battleId}/states/{playerId}/effects/{effectIndex}')
.onWrite(event => {
    effect = event.data.current.val();
    if (effect.duration === 0)
        return
    event.data.adminRef.root.child('battles').child(event.params.battleId).child('states')
            .child(event.params.playerId).child('effects').child(event.params.effectIndex).remove();
});

И осталось сделать так, чтобы вся эта красота была видна на экране телефона.



Например, вот так:
image

Да, именно так:

image

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

image

С чтением данных из Firebase на Android все достаточно просто: вешаем слушатели на определенные узлы в базе, ловим DataSnapshot`ы и отправляем их в UI. Вот так будем показывать список партий на первом экране (я сильно сокращаю код, чтобы выделить только моменты про получение и отображение данных):

public class MainActivity extends AppCompatActivity {

    // ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ...

        FirebaseDatabase database = FirebaseDatabase.getInstance();
        // слушатель на узле "battles" нашей базы (он получает данные когда добавлен, 
        // и потом каждый раз когда что-то изменилось в списке партий)
        database.getReference().child("battles").addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot battles) {

                final List battleIds = new ArrayList();
                for (DataSnapshot battle : battles.getChildren())
                    battleIds.add(battle.getKey());

                ArrayAdapter adapter = new ArrayAdapter<>(MainActivity.this,
                        android.R.layout.simple_list_item_1, 
                        battleIds.toArray(new String[battleIds.size()]));
                battlesList.setAdapter(adapter);
                battlesList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView

https://habrahabr.ru/post/334560/


Метки:  

Android O: особенности поддержки новой операционной системы

Вторник, 01 Августа 2017 г. 17:42 + в цитатник

Всем привет! Совсем скоро состоится важное событие – выход Android O. Поддержка новых версий операционной системы – обязанность любого серьезного продукта. Каждое обновление Android заставляет многих разработчиков серьезно поработать для сохранения работоспособности имеющихся функций и привнесения нового благодаря возможностям новых версий Android.


В данной статье мы рассмотрим основные изменения Android O и оценим их возможное влияние.


image


image


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


Изменения в Android O можно разделить на две категории:


  1. Потенциально «ломающие» текущую работоспособность и требующие дополнительных усилий для поддержки;


    Угроза Target >= O Target < O Эффект
    Background Location Limits Affected Affected Ограничение на запрос геолокации
    Background Execution Limits Affected OK Изменение списка доступных бродкастов в манифесте;
    Изменение времени работы сервисов в фоне.
    Notification Channels Affected OK Доработки для каналов нотификаций
    WindowManager Affected OK Влияние на работу перекрывающих окон
    Privacy (Build.Serial/net.dns/e.t.c.) Affected Affected Изменение доступности пользовательских идентификаторов
    AccountManager.
    getAccounts()
    Affected OK Запрос списка аккаунтов на устройстве возвращает null

  2. Возможности для реализации новых функций.
    Новые возможности Применение
    Android Enterprise Улучшение контроля над девайсом
    Autofill Framework Автозаполнение полей ввода
    Notification Channels Улучшение UX
    Picture in Picture Улучшение UX
    Adaptive Icon Консистентность с прошивкой вендора
    Accessibility button and fingerprint gestures Улучшение UX (accessibility кнопка в navigation bar, отлавливание жестов по сканеру отпечатка пальцев)
    Webview Apis (напр., Safebrowsing) Улучшение встроенных возможностей Webview
    Pinning shortcuts and Widgets Программное создание ярлыков и виджетов в лаунчере

На наш взгляд это наиболее значимые (по крайней мере для «Лаборатории Касперского») изменения в Android O. Рассмотрим каждое по отдельности.


Background Location Limits


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


  • Приложение не в фоне (запущено Activity, которое находится в состоянии Started или Paused);
  • Приложение имеет активный Foreground-сервис;
  • Другое Foreground-приложение имеет соединение с текущим (как через bind service, так и через content provider).

Таким образом, для Foreground-приложений поведение будет таким же, как и на предыдущих версиях Android.


В случае, если foreground service отсутствует, то запрос геолокации будет изменен:


  • Fused Location Provider (FLP)
    • Для Background-приложений система будет определять новое местоположение только несколько раз в час, даже если приложение явно запросило больше обновлений
    • Для Foreground-приложений логика работы останется без изменений
  • Geofencing
    • Background-приложения смогут получать обновления от geofencing-api чаще, чем обновления от Fused Location Provider
  • GNSS Measurements and GNSS Navigation Message
    • Для приложений, находящихся в фоне не будут приходить обновления для сервисов GnssMeasurement и GnssNavigationMessage
  • Location Manager
    • Для Background-приложений система будет определять новое местоположение только несколько раз в час

Background execution limits


Ограничение на фоновую работу приложения – ключевое изменение Android O, которое будет заметно в большой степени лишь при переходе на targetSdk “O”. В случае, если targetSdk <= 25, то если приложение находится в фоне и было переведено системой в Cached-состояние (когда система может свободно убить процесс в любой момент), и при этом оно не имеет активных компонентов, система отпустит все WakeLock (индикатор, что приложение не должно быть в состоянии сна) этого приложения. Важно отметить, что в случае, если приложение не targetSDK < O, то в настройках можно выставить политику поведения такую же, как если бы приложение было бы с targetSDK O.


Для приложений с targetSdk “O” background execution limits состоят из двух категорий:


  1. Ограничение фоновых сервисов
    После того как приложение перешло в background, у него есть «окно» в несколько минут, в течение которого сервисы могут запускаться и работать. После истечения этого интервала все сервисы останавливаются, а запуск новых будет приводить к падению приложения. Google старается минимизировать количество работающих фоновых сервисов и предлагает использовать JobScheduler и GcmNetworkManager.
    В случае если необходимо выполнять длительные задачи в фоне, рекомендуется использовать foregroundService, который будет явно говорить пользователю, что приложение работает.
    Стоит обратить внимание, что после того как вызвали Context.startForegroundService() необходимо в течение 5 секунд вызвать startForeground(), в противном случае система может показать ANR.
  2. Ограничений на регистрацию broadcasts в манифесте
    Новая версия Android продолжает дело, начатое Android 7.0 (наверняка все помнят приложения, которые переподнимались при каждой смене мобильной станции). Но если в 7-ой версии в манифесте нельзя было зарегистрировать всего лишь несколько бродкастов, то теперь таких бродкастов стало большинство.

Notification Channels


Notification Channels — инструмент для группировки нотификаций в тематические группы, которыми пользователь сможет управлять напрямую. Если приложение собрано с target >= O, тогда необходимо поддержать хотя бы один из каналов нотификаций. В случае, если targetApi < O, тогда работа с нотификациями внутри продукта останется прежней.


WindowManager


В Android O вводится новый тип окон (для targetSDK O), которые могут быть выведены поверх других окон – TYPE_APPLICATION_OVERLAY. При этом несколько старых типов окон стали deprecated, и теперь при их использовании генерируется RuntimeException.
Эти типы окон теперь могут использоваться только системными приложениями:



Privacy (Build.Serial/net.dns/e.t.c.)


В Android O появляются некоторые улучшения, призванные помочь пользователю управлять доступом к своим идентификаторам. Эти улучшения включают:


  • Ограничение на использование постоянных (не сбрасываемых) устройство-зависимых идентификаторов
  • Обновление системой Wi-Fi стека, связанного с изменениями прошивки Wi-Fi-чипсета на устройствах типа Pixel, Pixel XL и Nexus 5x для рандомизации MACадресов во время сканирований сетей
  • Обновление в механизме, при помощи которого приложения запрашивали информацию об учётной записи и предоставление большего контроля над данными пользователя

AccountManager.getAccounts()


Начиная с Android O, разрешения GET_ACCOUNTS недостаточно для получения доступа к списку учетных записей. Теперь существует два варианта для приложений с targetSDK O:


  • Использовать AccountManager.newChooseAccountIntent().
  • Использовать метод, определяемый аутентификатором, для доступа к учетной записи.

Android Enterprise


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


Autofill Framework


C появлением Autofill Framework API появилась возможность более удобного заполнения пользовательских данных в приложения, чем при использовании Accessability. При вызове фреймворка нужно будет сопоставить packageName продукта, для которого произошел вызов на автозаполнение, после чего предоставить данные для ввода. Для верной идентификации полей логина и пароля нужно создать и поддерживать базу с resourceId контролов или другой служебной информацией, позволяющей верно идентифицировать UI-элементы для автозаполнения.


Picture in Picture


Android O позволяет запускать активности в режиме Picture-In-Picture, который является специальным типом multi-window mode. Google рекомендует использовать данный режим исключительно для приложений, отображающих видео.


Adaptive Icon


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


Pinning shortcuts and Widgets


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


Вывод


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


P.S.
Автор статьи — Александр Шиндин ayushindin.
Саша написал статью и смело заболел, поэтому доверил выложить статью на Хабр мне =)
Пожелаем ему скорейшего выздоравления!

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

https://habrahabr.ru/post/334652/


Метки:  

Подлинность ваших видео теперь неоспорима благодаря Prover

Вторник, 01 Августа 2017 г. 17:28 + в цитатник
Сегодня я напишу про интересный проект интересных людей. Иван Писарев и Илья Свирин показали себя в проекте Нордавинд, самостоятельно разработав аппаратно-программные, очень простые и очень навороченные решения для разных сфер, от здоровья до безопасности. И вот недавно у них появилась идея…



Четыре миллиарда людей по всему миру владеют гаджетами. Создаваемый ими видеоконтент давно перестал использоваться лишь в развлекательных целях – сегодня это необходимая часть медийной, финансовой, страховой, юридической и медицинской отраслей. Выдаваемые за правду “фейки” не раз приводили к скандалам, а то и трагедиям, поэтому потребность в подтверждении подлинности видео-файлов необычайно высока. Сервис Prover (https://prover.io), подтверждающий достоверность видео с привязкой к конкретному времени и устройству, был создан именно с этой целью.

Технология Prover гарантирует, что контент был записан в конкретное время в конкретном месте камерой конкретного устройства, и подтверждает отсутствие признаков подлога и редактирования. Это стало возможным благодаря использованию сразу двух ведущих блокчейн-платформ: Emercoin и Ethereum.

Для верификации видео-материалов Prover предлагает два способа верификации видео-материалов. Первый — использование swype-кода. Пользователь, включивший камеру смартфона, видит сгенерированный в блокчейне swype-код – координатную сетку из 9 точек по 3 в ряд. Для его ввода пользователю необходимо перемещать в пространстве телефон, чтобы виртуальная линия swype прошла по требуемой траектории. После завершения съемки хэш полученного видеофайла со всеми данными автоматически сохранится в Prover.

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

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

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

  • дата и время получения индивидуального swype-кода;
  • сгенерированный swype-код;
  • хэш файла видеоданных (сам файл видеоданных хранится у пользователя);
  • дата и время загрузки хэша.


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

Где же все это может пригодиться?

  1. Автострахование (КАСКО) — в случае наступления страхового случая, в качестве доказательства клиент сможет представить видеозапись, заверенную системой Prover;
  2. Подтверждение авторства видео — ведя запись видео, пользователь может навсегда закрепить за ней свое авторство и иметь возможность его подтвердить;
  3. Удаленный контроль пациентов — клиники и страховые компании смогут подтверждать, что больной получил должную терапию в полном объеме. Пациент же сможет доказать, что он надлежащим образом выполнил все предписания врачей;
  4. Онлайн-игры и квесты — технология Prover встраивается в мобильные приложения, позволяя регистрировать наступление игровых событий;
  5. Отчеты о проделанной работе — удаленная проверка производства работ (строительство, монтаж, уборка, патрулирование, курьерская доставка и т.п.).;
  6. Фиксация нарушений ПДД и общественного порядка — время, дата и место записи видео-свидетельства для предоставления правоохранительным органам;
  7. Образовательные проекты — удаленная идентификация пользователей и верификация их действий внутри образовательной платформы;
  8. Видео-сообщения юридического характера — защита и подтверждение видео-сообщений без очного визита к должностным лицам.


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

Сайт проекта Prover — https://prover.io
Рекомендую обязательно взглянуть Whitepaper
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334650/


[Из песочницы] Кластеризация маркеров на карте Google Maps API

Вторник, 01 Августа 2017 г. 16:40 + в цитатник
Привет, Хабр! Хочу рассказать о моем опыте разработки карты с кластеризованными маркерами на google maps api и React.js. Кластеризация — это группировка близлежащих маркеров, меток, точек в один кластер. Это помогает улучшить UX и отобразить данные визуально понятнее, чем куча наехавших друг на друга точек. Компания, в которой я работаю, создает уникальный продукт для СМИ, это мобильное приложение, смысл которого заключается в съемке фото/видео/стрим материалов и возможности получить отличную компенсацию от СМИ в том случае, если редакция использует ваш материал в публикации. Я занимаюсь разработкой SPA приложения на стеке react/redux для модерации контента, присылаемого пользователями. Недавно передо мной встала задача сделать интерактивную карту на которой можно было бы увидеть местоположение пользователей и отправить им push уведомление, если поблизости происходит интересное событие.

Вот что мне предстояло сделать:



Первое что пришло мне на ум, поискать готовое решение для react.js. Я нашел 2 топовых библиотеки google-map-react и react-google-maps. Они представляют собой обертки над стандартным API Google maps, представленные в виде компонент для react.js. Мой выбор пал на google-map-react потому-что она позволяла использовать в качестве маркера любой JSX элемент, напомню что стандартные средства google maps api позволяют использовать в качестве маркера изображение и svg элемент, в сети есть решения, описывающие хитрую вставку html конструкций в качестве маркера, но google-map-react представляет это из коробки.

Едем дальше, на макете видно что если маркеры находятся близко к друг другу, они объединяются в групповой маркер — это и есть кластеризация. В readme google-map-react я нашел пример кластеризации, но он был реализован с помощью recompose — это утилита, которая создает обертку над function components и higher-order components. Создатели пишут чтобы мы думали что это некий lodash для реакта. Но тем, кто незнаком с recompose врятли сразу будет все понятно, поэтому я адаптировал этот пример и убрал лишнюю зависимость.

Для начала зададим свойства для google-map-react и state компоненты, отрендерим карту с заранее подготовленными маркерами:
(api key получаем здесь)

const MAP = {
  defaultZoom: 8,
  defaultCenter: { lat: 60.814305, lng: 47.051773 },
  options: {
    maxZoom: 19,
  },
};

state = {
  mapOptions: {
    center: MAP.defaultCenter,
    zoom: MAP.defaultZoom,
  },
  clusters: [],
};

//JSX 


  {this.state.clusters.map(item => {
    if (item.numPoints === 1) {
      return (
        
      );
    }

    return (
      
    );
  })}


Маркеров на карте не будет, так как массив this.state.clusters пустой. Для объединения маркеров в группу используем библиотеку supercluster

Для примера сгенерируем точки с координатами:

const TOTAL_COUNT = 200;

export const susolvkaCoords = { lat: 60.814305, lng: 47.051773 };

export const markersData = [...Array(TOTAL_COUNT)]
  .fill(0) // fill(0) for loose mode
  .map((__, index) => ({
    id: index,
    lat:
      susolvkaCoords.lat +
      0.01 *
        index *
        Math.sin(30 * Math.PI * index / 180) *
        Math.cos(50 * Math.PI * index / 180) +
      Math.sin(5 * index / 180),
    lng:
      susolvkaCoords.lng +
      0.01 *
        index *
        Math.cos(70 + 23 * Math.PI * index / 180) *
        Math.cos(50 * Math.PI * index / 180) +
      Math.sin(5 * index / 180),
  }));

При каждом изменении масштаба/центра карты будем пересчитывать кластеры:

handleMapChange = ({ center, zoom, bounds }) => {
  this.setState(
    {
      mapOptions: {
        center,
        zoom,
        bounds,
      },
    },
    () => {
      this.createClusters(this.props);
    }
  );
};

createClusters = props => {
  this.setState({
    clusters: this.state.mapOptions.bounds
      ? this.getClusters(props).map(({ wx, wy, numPoints, points }) => ({
          lat: wy,
          lng: wx,
          numPoints,
          id: `${numPoints}_${points[0].id}`,
          points,
        }))
      : [],
  });
};

getClusters = () => {
  const clusters = supercluster(markersData, {
    minZoom: 0,
    maxZoom: 16,
    radius: 60,
  });

  return clusters(this.state.mapOptions);
};

В методе getClusters мы скармливаем сгенерированные точки в supercluster, и на выходе получаем кластеры. Таким образом supercluster просто объединил лежащие рядом координаты точек и выдал новую точку со своими координатами и массивом points, где лежат все вошедшие точки.

Демо можно посмотреть здесь
Исходный код примера здесь
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334644/


Метки:  

Альтернативные планетарные данные для геоинформационных систем

Вторник, 01 Августа 2017 г. 16:23 + в цитатник

      Mandelbrot planet


Современные геоинформационные системы и сервисы (QGIS, ArcGIS, MapBox и т.д.; далее ГИС) и используемые ими форматы данных стали стандартным средством для представления карт земной поверхности и даже поверхности некоторых соседних планет. Но есть разновидность карт, где средства геоинформационных систем пока практически нигде не применяются. И это карты, которые получаются в результате процедурной генерации, например, в видеоиграх.


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


Third day of creation planet


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


Yattskry planet


Результирующие данные представляются в виде понятном для ГИС. В настоящее время векторные данные выкладываются в ESRI Shapefile-ах, а растровая информация в GeoTiff-ах и SRTM DEM-ках. Соответственно к данным можно применять всю мощь современных ГИС и представлять их как заблагорассудится, вплоть до изменения проекции, отрисовывания хилшейдинга или контуров высот.


stereographic projection


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


Vitruvian Man planet


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

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

https://habrahabr.ru/post/334642/


Метки:  

[Из песочницы] Внедрение зависимостей через поля — плохая практика

Вторник, 01 Августа 2017 г. 15:13 + в цитатник
Перевод статьи Field Dependency Injection Considered Harmful за авторством Vojtech Ruzicka

image

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

Типы внедрений


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

Конструктор


private DependencyA dependencyA;
private DependencyB dependencyB;
private DependencyC dependencyC;

@Autowired
public DI(DependencyA dependencyA, DependencyB dependencyB, DependencyC dependencyC) {
    this.dependencyA = dependencyA;
    this.dependencyB = dependencyB;
    this.dependencyC = dependencyC;
}

Сеттер


private DependencyA dependencyA;
private DependencyB dependencyB;
private DependencyC dependencyC;

@Autowired
public void setDependencyA(DependencyA dependencyA) {
    this.dependencyA = dependencyA;
}

@Autowired
public void setDependencyB(DependencyB dependencyB) {
    this.dependencyB = dependencyB;
}

@Autowired
public void setDependencyC(DependencyC dependencyC) {
    this.dependencyC = dependencyC;
}

Поле


@Autowired
private DependencyA dependencyA;
@Autowired
private DependencyB dependencyB;
@Autowired
private DependencyC dependencyC;

Что не так?


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

Нарушение принципа единственной ответственности


Добавлять новые зависимости просто. Возможно даже слишком просто. Нет никакой проблемы добавить шесть, десять или даже более зависимостей. При использовании конструкторов для внедрения, после определенного момента число аргументов конструктора становится слишком большим и тут же становится очевидно, что что-то не так. Наличие слишком большого количества зависимостей обычно означает, что у класса слишком много зон ответственности. Это может быть нарушением принципов единственной ответственности (single responsibility) и разделения ответственности (ориг.: separation of concerns) и является хорошим индикатором, что класс возможно стоит более внимательно изучить и подвергнуть рефакторингу. При использовании внедрения через поля такого явного тревожного индикатора нет, и таким образом происходит неограниченное разрастание внедренных зависимостей.

Сокрытие зависимостей


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

Зависимость от DI-контейнера


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

Однако при внедрении прямо в поля вы не предоставляете прямого способа создания экземпляра класса со всеми необходимыми зависимостями. Это означает, что:

  • Существует способ (путем вызова конструктора по-умолчанию) создать объект с использованием new в состоянии, когда ему не хватает некоторых из его обязательных зависимостей, и использование приведет к NullPointerException
  • Такой класс не может быть использован вне DI-контейнеров (тесты, другие модули) и нет способа кроме рефлексии предоставить ему необходимые зависимости

Неизменность


В отличие от способа с использованием конструктора, внедрение через поля не может использоваться для присвоения зависимостей final-полям, что приводит к тому, что ваши объекты становятся изменяемыми

Внедрение через конструктор vs сеттер


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

Сеттеры


Сеттеры следует использовать для инъекций опциональных зависимостей. Класс должен быть способен функционировать, даже если они не были предоставлены. Зависимости могут быть изменены в любое время после создания объекта. Это может быть, а может и не быть преимуществом в зависимости от обстоятельств. Иногда предпочтительно иметь неизменяемый объект. Иногда же полезно менять составные части объекта во время выполнения — например управляемые бины MBean в JMX.
Официальная рекомендация из документации по Spring 3.x поощряет использование сеттеров над конструкторами:
Команда Spring главным образом выступает за инъекцию через сеттеры, потому что большое количество аргументов конструктора может стать громоздким, особенно если свойства являются необязательными. Сеттеры также делают объекты этого класса пригодными для реконфигурации или повторной инъекции позже. Управление через JMX MBeans является ярким примером

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

Конструкторы


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

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

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

Что касается Spring 4.x, официальная рекомендация из документации изменилась и теперь инъекция через сеттер более не предпочтительна над конструктором:
Команда Spring главным образом выступает за инъекцию через конструктор, поскольку она позволяет реализовывать компоненты приложения как неизменяемые объекты и гарантировать, что требуемые зависимости не null. Более того, компоненты, внедренные через через конструктор, всегда возвращаются в клиентский код в полностью инициализированном состоянии. Как небольшое замечание, большое число аргументов конструктора является признаком «кода с запашком» и подразумевает, что у класса, вероятно, слишком много обязанностей, и его необходимо реорганизовать, чтобы лучше решать вопрос о разделении ответственности.

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

Заключение


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

https://habrahabr.ru/post/334636/


Метки:  

Как создать бизнес-предложение, в основе которого результат НИОКР и технологий

Вторник, 01 Августа 2017 г. 14:18 + в цитатник


МФТИ в партнерстве с компанией еНано (группа РОСНАНО) открыл набор в группу обучения по новой программе повышения квалификации «Коммерциализация результатов НИОКР и технологий». Программа дает практические инструменты для оценки коммерческих перспектив исследований и разработок и создания бизнес-предложения на их основе.

Обучение проходит в онлайн-формате c 21 августа по 13 октября.
Вы будете работать с собственным или учебным проектом под руководством автора и преподавателя программы:

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

Автор и преподаватель программы — Владимир Александрович Антонец, доктор физико-математических наук, профессор базовой кафедры РОСНАНО в МФТИ и отделения экономики экономического факультета РАНХиГС, ведущий научный сотрудник Института прикладной физики РАН, международный эксперт в области коммерциализации результатов научных исследований и разработок, организатор первого в РФ регионального технологического инкубатора. Имеет более 200 научных публикаций, автор более 20 учебно-методических работ, электронных курсов и учебников.

Даты обучения: 21 августа – 13 октября 2017 года
Стоимость обучения: 18 тыс. рублей
Объем программы: 72 академических часа, 8 недель, 9 академических часов в неделю
Форма обучения: заочная с использованием систем дистанционного обучения. Обучение проходит на платформе партнера программы www.edunano.ru. Слушатели принимают участие в вебинарах, изучают материалы электронного курса, выполняют индивидуальную практическую работу под руководством преподавателя.
Аттестация: в дистанционном формате.
Итоговый документ: удостоверение МФТИ о повышении квалификации установленного образца.

Подробная информация и запись на сайте программы.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334630/


Метки:  

Гигабитный ГОСТ VPN. TSS Diamond

Вторник, 01 Августа 2017 г. 14:07 + в цитатник
VPN канал — необходимость практически для всех компаний, которые имеют удаленные филиалы или просто удаленных сотрудников. Для организации этих самых каналов существует довольное большое количество технологий и протоколов (IPSec, GRE. L2TP и т.д.), которые поддерживаются большинством современного оборудования. Однако существует определенная категория организаций, которые вынуждены (именно вынуждены) использовать решения поддерживающие отечественные криптоалгоритмы — ГОСТ VPN. При этом реализовать этот ГОСТ на Linux-подобных системах не составляет особого труда. Однако получить сертификат ФСБ (как средство СКЗИ) — практически невозможно для зарубежных решений (Cisco, Check Point, Fortinet и т.д.). В связи с этим, выбор оборудования резко сужается. До сих пор в подобных случаях рассматривали следующие варианты:
  • S-terra
  • АПКШ Континент
  • Ideco МагПро ГОСТ-VPN
  • Vipnet
  • Застава
Однако, на текущий момент весьма трудно найти решение которое поддерживало бы Гигабитный ГОСТ VPN. Существуют различные «хитрые» способы обойти эту проблему, например поставить несколько устройств на каждой стороне и с помощью балансировки увеличить общую пропускную способность канала используя несколько VPN-туннелей.
Пример от S-terra:

Не всегда данное решение применимо и не всегда «по карману». В поисках компромисса мы узнали о существовании еще одного весьма интересного решения — TSS Diamond. Компания TSS заявляет о возможности своих «железок» организовать VPN канал с пропускной способностью даже больше чем Гигабит. И это с одной железки, без агрегации… Мы решили не верить маркетинговым материалам и протестировать все самостоятельно. Для этого вендор любезно предоставил нам на тест две «железки» — Diamond VPN/FW Enterprise 5111.

Затем мы быстро собрали простейшую схему для теста:

Т.е. два устройства подключены напрямую друг к другу (оптическими линками). Для тестирования пропускной способности VPN-туннеля использовался Cisco Trex.

Настройка
Вкратце опишем процедуру настройки. Вся конфигурация осуществляется через интуитивно понятный Web-интерфейс. В данном случае первый шлюз выступает в роли VPN-сервера, второй — в роли VPN-клиента.

Настройка сервера
1) Настройка сетевых интерфейсов:


2) Добавление сертификатов (install new PKI...):

результат:


3) Настройки VPN подключения:

Состояние должно быть в статусе Running


4) Теперь необходимо прописать маршрут, чтобы «завернуть» трафик в VPN-туннель:


Настройка клиента
1) Настройка сетевых интерфейсов:


2) Добавляем сертификат:


3) Настройки VPN подключения:

Проверяем, что статус Running:


4) «Заворачиваем» трафик с помощью статического маршрута:


После этого в журнале событий можно найти лог об успешном VPN-соединении:


Проверка пропускной способности
Как было сказано ранее, для тестирования пропускной способности VPN-туннеля был использован Cisco Trex. Тестировали как маленькими, так и большими пакетами, причем дуплексом, т.е. сразу в двух направлениях (upload/download). Вот несколько результатов:
1) Пакет 64 байта


2) Пакет 594 байта


3) Пакет 1500 байтов


4) Пакет 9000 байтов


В данном случае все тесты проводились для L3 VPN. Для L2 VPN будут примерно такие же параметры.

Что же пишут в даташите на эту железку? Там значатся следующие параметры:
Пропускная способность VPN — 2,6 Гбит/с
Пропускная способность МЭ в базовой комплектации — 7,5 Гбит/с

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

Сертификация
Естественно, что при выборе устройства с ГОСТ VPN, первый интересующий вопрос — наличие сертификатов. Устройства TSS Diamond обладают следующими сертификатами соответствия:
  • «Средства вычислительной техники. Защита от несанкционированного доступа к информации. Показатели защищенности от несанкционированного доступа к информа-ции» (Гостехкомиссия России, 1992) – по 3 классу защищенности;
  • «Защита от несанкционированного доступа к информации. Часть 1. Программное обеспечение средств защиты информации. Классификация по уровню контроля отсутствия недекларированных возможностей» (Гостехкомиссия России, 1999) – по 2 уров-ню контроля
  • а также документов:
  • «Требования к системам обнаружения вторжений» (ФСТЭК России, 2011);
  • «Профиль защиты систем обнаружения вторжений уровня сети четвертого класса за-щиты. ИТ.СОВ.С4.ПЗ» (ФСТЭК России, 2012);
  • «Требования к межсетевым экранам» (ФСТЭК России, 2016);
  • «Профиль защиты межсетевых экранов типа «А» четвертого класса защиты ИТ.МЭ.А4.ПЗ (ФСТЭК России, 2016)»;
  • •«Профиль защиты межсетевых экранов типа «Б» четвертого класса защиты ИТ.МЭ.Б4.ПЗ (ФСТЭК России, 2016)»;
  • «Профиль защиты межсетевых экранов типа «В» четвертого класса защиты ИТ.МЭ.В4.ПЗ (ФСТЭК России, 2016)».

Криптографическая подсистема изделия DCrypt имеет сертификат соответствия по классу — КС1 КС2 КС3.

Выводы
На наш субъективный взгляд, данное оборудование неплохо подходит для решения задачи организации ГОСТ VPN-туннеля с высокой пропускной способностью (например для связи двух ЦОД-ов). Все заявленные функции выполняются. Требовать от этого устройства чего-то больше (кроме VPN) не вижу смысла. Кроме того, в линейке TSS Dimond есть и более «мелкие» модели, которые подойдут для небольших и средних филиалов (Diamond VPN/FW 1101, 2111, 3101, 4101, 4105). Самая младшая модель 1101 на тестах выдает не менее 100 Мбит ГОСТ VPN (пакетами 1500).

Если есть дополнительные вопросы по TSS Diamond, то можете смело обращаться к нам.

P.S. Если в списке решений по организации ГОСТ VPN отсутствует какое-то известное вам оборудование (или софт), то напишите пожалуйста это в комментариях.
Какое решение вы используете для организации сертифицированного ГОСТ VPN?

Проголосовал 1 человек. Воздержавшихся нет.

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

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

https://habrahabr.ru/post/334534/


Книга «jQuery в действии. 3-е издание»

Вторник, 01 Августа 2017 г. 13:41 + в цитатник
image Эта книга — для веб-разработчиков, желающих углубиться в jQuery. Цель авторов — сделать вас профессионалом jQuery, будь ваш уровень начальным или продвинутым. Книга охватывает всю библиотеку целиком, включая некоторые дополнительные инструменты и фреймворки, такие как Bower и QUnit, рекомендуя лучшие практики. Каждый метод API представлен в удобном для применения синтаксическом блоке, описывающем параметры и возвращаемые значения.

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

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

Дорожная карта


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

Глава 1 дает представление о философии jQuery и о том, как эта библиотека следует так называемым принципам ненавязчивого JavaScript. Здесь обсуждается, что такое jQuery, какие проблемы она пытается решить и почему вы можете захотеть задействовать ее в ваших веб-проектах.

Глава 2 охватывает выбор DOM-элементов на основе использования селекторов и повествует о том, как создать ваш собственный селектор. Мы также познакомим вас с таким термином, как коллекция jQuery (или объект jQuery), применяемым для ссылки на объект JavaScript, возвращаемый методами jQuery. Он содержит набор элементов, выбирая которые вы можете работать с библиотекой.

Глава 3 расширяет главу 2, показывая, как улучшить или создать новую выборку элементов, начиная с предыдущей выборки. Вы также научитесь создавать новые DOM-элементы с помощью jQuery.

Глава 4 фокусируется на многих методах jQuery, предназначенных для работы с атрибутами и свойствами, и различиях между ними. Кроме того, она объясняет, как хранить пользовательские данные в одном или нескольких DOM-элементах.

Глава 5 целиком посвящена работе с именами класса элемента, клонированию и установке содержимого DOM-элементов, изменению дерева DOM посредством добавления, перемещения или замены элементов.

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

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

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

Глава 9 посвящена вспомогательным функциям — функциям с пространством имен в jQuery, обычно не работающих с DOM-элементами.

Глава 10 рассматривает одно из важнейших понятий последних лет — Ajax. Мы увидим, как jQuery облегчает использование Ajax на веб-страницах, защищая нас от всех популярных подводных камней, при этом значительно упрощая наиболее распространенные типы взаимодействий Ajax (такие как возврат объектов JSON).

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

Глава 12 — первая из части III, где мы переходим к более сложным вопросам, большая часть которых не связана строго с ядром библиотеки. Здесь мы обсудим, как расширить функциональность jQuery с помощью создания плагинов для нее. Эти плагины могут быть в двух вариантах: методы и вспомогательные функции. Мы рассмотрим оба варианта.

Глава 13 объясняет, как избежать того, что называется callback hell (дословно — «ад обратного вызова»), описывая реализацию jQuery-промисов. Как вы узнаете, это тонкая и спорная тема, служившая предметом дискуссий на протяжении многих лет.

Глава 14 познакомит вас с тестированием: что это и почему важно. Мы сосредоточим внимание на одном конкретном виде тестирования — модульном. Затем рассмотрим QUnit, JavaScript-фреймворк, применяемый некоторыми проектами jQuery (jQuery, jQuery UI и jQuery Mobile) для модульного тестирования кода.

Глава 15, последняя, начинается с советов и рекомендаций по улучшению производительности кода, который использует jQuery, благодаря правильному способу выбора элементов. Затем мы рассмотрим несколько инструментов, фреймворков и шаблонов, не относящихся напрямую к библиотеке, но тех, которые можно применять для написания быстрого, надежного и красивого кода. В частности, эта глава объясняет, как организовать ваш код в модулях, как загрузить модули, используя RequireJS, и как управлять зависимостями клиентской стороны с помощью Bower. Наконец, мы покажем вам, как jQuery вписывается в приложения одной страницы, бегло просмотрев Backbone.js.

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

Отрывок. 9.3. Управление объектами и коллекциями JavaScript


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

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

9.3.1. Усечение строк


Это трудно объяснить, но до ECMAScript 5 у объекта String не было метода удаления пробельных символов в начале и конце строки. Такие базовые функциональные возможности являются обязательной частью класса String в большинстве других языков, но по каким-то таинственным причинам в JavaScript не было этого полезного свойства в предыдущих версиях. Таким образом, вы не можете использовать данную функцию в версиях Internet Explorer, предшествующих 9.

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

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

Метод $.trim() определяется следующим образом.
Синтаксис функции: $.trim
$.trim(value)

Удаляет все начальные или конечные пробельные символы из переданной строки и возвращает результат.
Пробельными данная функция считает любые символы, соответствующие в JavaScript регулярному выражению \s, то есть не только символ пробела, но и символы перевода страницы, новой строки, возврата, табуляции и вертикальной табуляция, а также символ Юникода \u00A0.
Параметры
value (Строка) Строковое значение для усечения. Это исходное значение не изменяется.
Возвращает
Усеченную строку.

Небольшой пример усечения значения в текстовом поле с помощью данной функции:
var trimmedString = $.trim($('#some-field').val());

Имейте в виду: функция $.trim() преобразует параметр, который вы передаете, в тип его эквивалента String, так что если ошибочно передадите ей объект, то получите строку "[object Object]".

А сейчас посмотрим на ряд функций, которые работают с массивами и другими объектами.

9.3.2. Итерации по свойствам и элементам коллекций


Часто при наличии нескалярных величин в составе других компонентов требуется итерировать по элементам. Вне зависимости от того, будет элемент контейнера массивом JavaScript (содержащим любое количество других значений JavaScript, включая другие массивы) или экземпляром объекта JavaScript (содержащим свойства), язык JavaScript позволяет обойти их все в цикле. Обход элементов массивов выполняется с помощью цикла for; обход свойств объектов — цикла for...in (доступны и другие конструкции, но в данный момент не будем обращать на них внимания).

Приведем примеры для всех случаев:
var anArray = ['one', 'two', 'three'];
for (var i = 0; i < anArray.length; i++) {
   // Здесь будет что-то делаться с anArray[i]
}
var anObject = {one: 1, two: 2, three: 3};
for (var prop in anObject) {
   // Здесь будет что-то делаться с prop
}

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

Несколько лет назад в JavaScript был добавлен метод объекта Array под названием forEach(). К сожалению, будучи более поздним дополнением, он не поддерживается в некоторых браузерах, в первую очередь Internet Explorer до версии 9. Вдобавок из-за принадлежности объекту Array данный метод не может быть использован для итерации по другим типам объектов. Но в этом случае jQuery спешит на помощь!

Как вы знаете, библиотека предоставляет метод each(), который позволяет легко обойти все элементы в коллекции jQuery, не используя сложный синтаксис оператора for. Для массивов, массивоподобных объектов и объектов у jQuery есть аналогичная вспомогательная функция $.each().

Действительно, очень удобно, когда для организации итераций по элементам массива или свойствам объекта можно применять один и тот же синтаксис. Более того, его также можно задействовать в Internet Explorer 6–8. Cинтаксис функции выглядит следующим образом.

Синтаксис функции: $.each
$.each(collection, callback)

Обобщенная функция итератора, которая может быть использована для обхода как объектов, так и массивов. Массивы и массивоподобные объекты со свойством длины (например, объекты функции arguments) итерируются по числовым индексам от 0 до длины – 1. Другие объекты итерируются через названные свойства.
Параметры
collection (Массив|Объект) Массив (или массивоподобный объект), по элементам которого должна пройти итерация, либо объект, по свойствам которого она должна пройти.
callback (Функция) Функция, которая будет вызываться для каждого элемента в коллекции. Если коллекция является массивом (либо массивоподобным объектом), то данная функция вызывается для каждого элемента массива, а если объектом, то для каждого свойства объекта. Первый параметр функции callback — индекс элемента массива или имя свойства объекта. Второй параметр — значение элемента массива или свойства объекта.

Контекст функции (this) вызова содержит значение, передающееся во втором параметре.
Возвращает
Ту же переданную коллекцию.

Этот унифицированный синтаксис подходит для итерации по массивам, массивоподобным объектам и объектам, с тем же форматом вызова функции. Перепишем предыдущий пример с применением данной функции:
var anArray = ['one', 'two', 'three'];
$.each(anArray, function(i, value) {
   // Здесь что-то делается
});
var anObject = {one:1, two:2, three:3};
$.each(anObject, function(name, value) {
   // Здесь что-то делается
});

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

Обратите внимание: при выполнении итерации по коллекции можно выйти из цикла, возвращая значение false из функции-итератора. И наоборот, возврат truthy-значения (значения, вычисляемого true) аналогичен использованию continue, что означает немедленную остановку функции и совершение следующей итерации.
jQuery 3: добавленные функции
jQuery 3 предоставляет возможность для итерации по элементам DOM коллекции jQuery с помощью цикла for-of, что является частью спецификации ECMAScript 6. Благодаря этой особенности теперь можно написать код наподобие следующего:
var $divs = $('div');
for (var element of $divs) {
   // Здесь что-то делается с элементом
}

Пожалуйста, обратите внимание: мы не ставим знак доллара перед переменной element, чтобы подчеркнуть, что ее значение будет принадлежать элементу DOM, а не коллекции jQuery.

ПРИМЕЧАНИЕ
Применение функции $.each() может быть удобным с точки зрения синтаксиса, но это, как правило, медленнее (чуть-чуть), чем использование старомодного цикла for. Выбор за вами.

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

9.3.3. Фильтрация массивов


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

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

Синтаксис функции: $.grep
$.grep (array, callback[, invert])

Выполняет цикл по элементам массива, вызывая функцию обратного вызова для каждого значения. Возвращаемое значение функции обратного вызова определяет, должно ли войти это значение в новый массив, который возвращается как значение функции $.grep(). Если параметр invert опущен или имеет значение false и возвращаемое значение функции обратного вызова равно true, то данные включаются в новый массив. Если параметр invert имеет значение true и возвращаемое значение функции обратного вызова равно false, то данные также включаются в новый массив. Исходный массив не изменяется.

Параметры
array (Массив) Массив, элементы которого проверяются на возможность включения в коллекцию. При выполнении функции не изменяется.
callback (Функция|Строка) Функция, возвращаемое значение которой определяет, должно ли текущее значение войти в коллекцию. Она получает два параметра: текущее значение данной итерации и индекс этого значения в пределах исходного массива. Возвращаемое значение true приводит к включению данных при условии, что значение параметра invert не равно true, в противном случае результат меняется на противоположный.
invert (Логический тип) Если определен как true, то инвертирует нормальное действие функции.
Возвращает
Массив отобранных значений.

Предположим, мы хотим отфильтровать массив, выбрав все значения больше 100. Это можно сделать с помощью такой инструкции:
var bigNumbers = $.grep(originalArray, function(value) {
                                return value > 100;
                          });

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

Хотя функция $.grep() и не использует регулярные выражения напрямую (невзирая на свое название), регулярные выражения JavaScript, применяемые в функциях обратного вызова, позволяют успешно решать вопрос о включении или исключении значений из этого массива. Рассмотрим пример, когда в массиве требуется идентифицировать значения, не соответствующие шаблону почтового индекса Соединенных Штатов (также известного как ZIP codes).

Почтовый индекс в США состоит из пяти десятичных цифр, за которыми могут следовать символ дефиса и еще четыре десятичные цифры. Такая комбинация задается регулярным выражением вида /^\d{5}(-\d{4})?$/. Его можно применить для фильтрации исходного массива и извлечь ошибочные записи:
var badZips = $.grep(
                           originalArray,
                           function(value) {
                              return value.match(/^\d{5}(-\d{4})?$/) !== null;
                           },
                           true
);

Примечательно, что в этом примере метод match() класса String позволяет определить, соответствует ли значение шаблону; в параметре invert функции $.grep() передается значение true для исключения всех значений, соответствующих шаблону.

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

9.3.4. Преобразование массивов


Данные не всегда представлены в нужном нам формате. Еще одна операция, которая часто выполняется в веб-приложениях, ориентированных на работу с данными, — преобразование одного набора значений в другой. Написать цикл for для создания одного массива из другого достаточно просто, но jQuery упрощает эту операцию с помощью вспомогательной функции $.map().
Рассмотрим простейший пример, который демонстрирует функцию $.map() в действии.
var oneBased = $.map(
      [0, 1, 2, 3, 4],
      function(value) {
         return value + 1;
      }
);

Эта инструкция преобразует переданный массив следующим образом:
[1, 2, 3, 4, 5]


Синтаксис функции: $.map
$.map(collection, callback)

Итерирует по элементам массива или объекта, вызывая функцию обратного вызова для каждого элемента массива и собирая возвращаемые значения функции в новый массив.
Параметры
collection (Массив|Объект) Массив или объект, значения которых должны быть преобразованы в значения в новом массиве.
callback (Функция) Функция, возвращаемое значение которой является преобразованным значением элемента нового массива, возвращаемого функцией $.map().

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

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

Рассмотрим чуть более сложный пример. Допустим, у вас есть массив строк, возможно собранных из полей формы, предположительно являющихся числовыми значениями, и требуется преобразовать этот массив строк в соответствующий ему массив Number. Поскольку нет никакой гарантии, что строки не содержат нечисловых значений, понадобится принять меры предосторожности. Рассмотрим следующий фрагмент, который также доступен в файле chapter-9/$.map.html, предоставленном с книгой, и в JS Bin:
var strings = ['1', '2', '3', '4', 'S', '6'];
var values = $.map(strings, function(value) {
   var result = new Number(value);
   return isNaN(result) ? null : result;
});

В начале есть массив строк, каждая из которых, как ожидается, представляет числовое значение. Но опечатка (или, возможно, ошибка пользователя) привела к тому, что вместо ожидаемого символа 5 имеется символ S. Наш программный код обрабатывает этот случай, проверяя экземпляр Number, созданный конструктором, чтобы увидеть, было ли успешным преобразование из строки в число. Если оно не удалось, то возвращаемое значение будет константой NaN. Но интереснее всего то, что по определению значение NaN не равно никакому другому значению, даже самому себе! Поэтому логическое выражение Number.NaN == Number.NaN даст в результате false!

Поскольку вы не можете использовать оператор сравнения для проверки на равенство NaN (что, кстати, означает Not a Number — «не число»), JavaScript предоставляет метод isNaN(), который и позволил проверить результат преобразования строки в число.

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

Другая полезная особенность функции $.map() состоит в том, что она изящно обрабатывает случаи, когда функция преобразования возвращает массив, добавляя возвращаемое значение в массив результата. Рассмотрим следующий пример:
var characters = $.map(
   ['this', 'that'],
   function(value) {
      return value.split('');
   }
);

Эта инструкция преобразует массив строк в массив символов, из которых составлены строки. После ее выполнения значения переменной characters таковы:
['t', 'h', 'i', 's', 't', 'h', 'a', 't']

Данный результат получен с помощью метода JavaScript split(), который возвращает массив из символов строки, если в качестве разделителя была передана пустая строка. Такой массив возвращается как результат функции преобразования и затем включается в массив результата.

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

9.3.5. Другие полезные функции для работы с массивами JavaScript


Случалось ли так, что нужно было узнать, содержит ли массив JavaScript некоторое специфическое значение и, возможно, даже определить его местоположение в массиве?
Если да, то вы по достоинству оцените функцию $.inArray().

Синтаксис функции: $.inArray
$.inArray(value, array[, fromIndex])

Возвращает индекс первого вхождения значения value в массив array.
Параметры
value (Любой) Значение, которое требуется найти в массиве.
array (Массив) Массив, в котором будет производиться поиск.
fromIndex (Число) Индекс массива, с которого начинается поиск. По умолчанию равняется 0.
Возвращает
Индекс первого вхождения искомого значения в массиве или –1, если значение не найдено.

Несложный, но показательный пример применения данной функции:
var index = $.inArray(2, [1, 2, 3, 4, 5]);

Другая полезная функция для работы с массивами создает массив JavaScript из других объектов, подобных массиву. Взгляните на следующий отрывок:
var images = document.getElementsByTagName('img');

Это заполнит переменные image всеми изображениями HTMLCollection, записанными на странице.

Довольно непросто иметь дело с подобными объектами, потому что у них недостаточно нативных методов JavaScript Array, таких как sort() и IndexOf(). Преобразование HTMLCollection (и других аналогичных объектов) в массив JavaScript существенно упрощает работу. Функция $.makeArray из библиотеки jQuery — как раз то, что нужно в данном случае.

Синтаксис функции: $.makeArray
$.makeArray(object)

Преобразует объект, подобный массиву, в массив JavaScript.
Параметры
object (Объект) Любой объект для преобразования в нативный Array.
Возвращает
Полученный в результате массив JavaScript.

Данная функция предназначена для использования в коде, который редко обращается к jQuery. Она пригодится и при обращении с объектами типа массива arguments в пределах функций. Представьте, что у вас есть следующие функции и вы хотите отсортировать их аргументы:
function foo(a, b) {
      // Аргументы сортировки здесь
}


Можно получить все аргументы одновременно, используя массив arguments. Проблема в том, что он не относится к типу Array, так что вы не можете написать:
function foo(a, b) {
      var sortedArgs = arguments.sort();
}

Этот код выдаст ошибку, потому что массив arguments не поддержвиает метод JavaScript Array sort(), который пригодился бы для сортировки аргументов. Здесь может помочь $.makeArray(). Проблему можно решить, преобразовав аргументы в реальный массив, а затем отсортировав его элементы:
function foo(a, b) {
      var sortedArgs = $.makeArray(arguments).sort();
}

После внесения этого изменения sortedArgs будет содержать массив с отсортированными аргументами, переданными функции foo().
Допустим, сейчас у вас есть следующий оператор:
var arr = $.makeArray({a: 1, b: 2});

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

Другая редко используемая функция, которая может быть полезной в работе с массивами, созданными не средствами jQuery, называется $.unique().
Синтаксис функции: $.unique
$.unique(array)

Получает массив элементов DOM и возвращает массив уникальных элементов из оригинального массива.
Параметры
array (Массив) Массив элементов DOM, который требуется исследовать.
Возвращает
Массив элементов DOM, состоящий из уникальных элементов массива, переданного функции.
Эта функция предназначена для использования с массивами элементов DOM, созданных за пределами jQuery. Хотя многие люди думают, что ее можно применять с массивами строк или чисел, мы хотим подчеркнуть: $.unique() работает только с массивами элементов DOM.

Прежде чем углубиться в описание следующей функции, рассмотрим пример работы $.unique(). Обратите внимание на разметку:
foo
bar
baz
don
wow

Теперь представьте, что по какой-то причине вам нужно получить , имеющие класс black в качестве массива элементов DOM, а затем добавить все на странице в эту коллекцию и наконец отфильтровать ее, чтобы удалить дубликаты. Можно достичь результата, написав следующий код (который включает в себя ряд заявлений для определения разницы в числе элементов):
var blackDivs = $('.black').get();
console.log('Черные div-ы: ' + blackDivs.length);
var allDivs = blackDivs.concat($('div').get());
console.log('Увеличенные div-ы: ' + allDivs.length);
var uniqueDivs = $.unique(allDivs);
console.log('Уникальные div-ы: ' + uniqueDivs.length);


Если захотите поэкспериментировать с этим примером, то он доступен в файле chapter-9/$.unique.html, предоставленном с книгой, и в JS Bin (http://jsbin.com/borin/edit?html,js,console).

jQuery 3: переименованные методы
jQuery 3 переименовала вспомогательную функцию $.unique() в $.uniqueSort() для указания на то, что эта функция также может сортировать. Несмотря на данное изменение, в jQuery 3 вы можете по-прежнему вызывать $.unique(), которая в настоящее время является просто псевдонимом для $.uniqueSort(), но сейчас не рекомендуется так делать, ведь это название устарело и будет удалено в следующих версиях библиотеки.

А если необходимо объединить два массива? У jQuery есть функция для такой задачи — $.merge.

Синтаксис функции: $.merge
$.merge(array1,array2)

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

Обратите внимание на код:
var arr1 = [1, 2, 3, 4, 5];
var arr2 = [5, 6, 7, 8, 9];
var arr3 = $.merge(arr1, arr2);

После выполнения этого фрагмента массив arr2 останется прежним, а массивы arr1 и arr3 будут содержать следующие элементы:
[1, 2, 3, 4, 5, 5, 6, 7, 8, 9]

Заметьте: есть два вхождения 5, так как вспомогательная функция $.merge() не удаляет дубликаты.

Увидев, как jQuery упрощает работу с массивами, рассмотрим способ, который поможет управлять простыми объектами JavaScript.

» Более подробно с книгой можно ознакомиться на сайте издательства
» Оглавление
» Отрывок
Для Хаброжителей скидка 20% по купону — jQuery
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334622/


Метки:  

Распознавание дорожных знаков с помощью CNN: Инструменты для препроцессинга изображений

Вторник, 01 Августа 2017 г. 13:03 + в цитатник
Привет, Хабр! Продолжаем серию материалов от выпускника нашей программы Deep Learning, Кирилла Данилюка, об использовании сверточных нейронных сетей для распознавания образов — CNN (Convolutional Neural Networks)

Введение


За последние несколько лет сфера компьютерного зрения (CV) переживает если не второе рождение, то огромный всплеск интереса к себе. Во многом такой рост популярности связан с эволюцией нейросетевых технологий. Например, сверточные нейронные сети (convolutional neural networks или CNN) отобрали себе большой кусок задач по генерации фич, ранее решаемых классическими методиками CV: HOG, SIFT, RANSAC и т.д.

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


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

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

  • Chapter 6: Deep Feedforward Networks — глава из книги Deep Learning от I.Goodfellow, Y.Bengio и A.Courville. Очень рекомендую.
  • CS231n Convolutional Neural Networks for Visual Recognition — популярный курс от Fei-Fei Li и Andrej Karpathy из Стэнфорда. В курсе содержатся отличные материалы сделан упор на практику и проектирование.
  • Deep Learning — курс от Nando de Freitas из Оксфорда.
  • Intro to Machine Learning — бесплатный курс от Udacity для новичков с доступным изложением материала, затрагивает большое количество тем в машинном обучении.

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

Вместо того, чтобы повторять основы, данная серия статей фокусируется на нескольких конкретных архитектурах нейронных сетей: STN (spatial transformer network), IDSIA (сверточная нейросеть для классификации дорожных знаков), нейросеть от NVIDIA для end-to-end разработки автопилота и MultiNet для распознавания и классификации дорожной разметки и знаков. Приступим!

Тема данной статьи — показать несколько инструментов для предобработки изображений. Общий пайплайн обычно зависит от конкретной задачи, я же хотел бы остановиться именно на инструментах. Нейросети — совсем не те магические черные ящики, какими их любят преподносить в медиа: нельзя просто взять и «закинуть» данных в сетку и ждать волшебных результатов. По правилу shit in — shit out в лучшем случае, вы получите score хуже на несколько пунктов. А, скорее всего, просто не сможете обучить сеть и никакие модные техники типа нормализации батчей или dropout вам не помогут. Таким образом, работу нужно начинать именно с данных: их чистки, нормализации и нормировки. Дополнительно стоит задуматься над расширением (data augmentation) исходного картиночного датасета с помощью аффинных преобразований типа вращения, сдвигов, изменения масштаба картинок: это поможет снизить вероятность переобучения и обеспечит лучшую инвариантность классификатора к трансформациям.

Инструмент 1: Визуализация и разведочный анализ данных


В рамках этого и следующего постов мы будем использовать GTSRB — датасет по распознаванию дорожных знаков в Германии. Наша задача — обучить классификатор дорожных знаков, используя размеченные данные из GTSRB. В общем случае, лучший способ получить представление об имеющихся данных — построить гистограмму распределения train, validation и/или test наборов данных:



Базовая информация о нашем датасете:

Number of training examples = 34799
Number of validation examples = 4410
Number of testing examples = 12630
Image data shape = (32, 32, 3)
Number of classes = 43

На данном этапе matplotlib — ваш лучший друг. Несмотря на то, что используя лишь pyplot можно отлично визуализировать данные, matplotlib.gridspec позволяет слить 3 графика воедино:

gs = gridspec.GridSpec(1, 3, wspace=0.25, hspace=0.1)
fig = plt.figure(figsize=(12,2))
ax1, ax2, ax3 = [plt.subplot(gs[:, i]) for i in range(3)]

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

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

  • Визуализация изображений. По графику сразу видно множество слишком темных или слишком светлых изображений, поэтому должна быть проведена своего рода нормализация данных, чтобы устранить вариацию яркости.
  • Проверка выборки на несбалансированность. В случае, если в выборке превалируют экземпляры какого-либо класса, необходимо использовать методы undersampling или oversampling.
  • Проверить, что распределения train, validation и test выборок похожи. Это можно проверить, взглянув на гистограммы выше, либо используя ранговый коэффициент корреляции Спирмена. (через scipy)

Инструмент 2: IPython Parallel для scikit-image


Для того, чтобы улучшить сходимость нейронной сети, нужно привести все изображения к единому освещению путем (как рекомендовано в статье LeCun о распознавании дорожных знаков) преобразования их цветовой гаммы в градации серого. Это можно сделать как с помощью OpenCV, так и с помощью отличной библиотеки на Python scikit-image, которая может быть легко установлена с помощью pip (OpenCV же требует самостоятельной компиляции с кучей зависимостей). Нормализация контрастности изображений будет осуществляться с помощью адаптивной нормализации гистограммы (CLAHE, contrast limited adaptive histogram equalization):
skimage.exposure.equalize_adapthist.

Отмечу, что skimage обрабатывает изображения одно за другим, используя лишь одно ядро процессора, что, очевидно, неэффективно. Чтобы распараллелить предобработку изображений, используем библиотеку IPython Parallel (ipyparallel). Одно из преимуществ этой библиотеки — простота: реализовать распараллеленный CLAHE можно всего несколькими строчками кода. Сначала в консоли (с установленной ipyparallel) запустим локальный кластер ipyparallel:

$ ipcluster start



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

from skimage import exposure

def grayscale_exposure_equalize(batch_x_y):
    """Processes a batch with images by grayscaling, normalization and
    histogram equalization.
    
    Args:
        batch_x_y: a single batch of data containing a numpy array of images
            and a list of corresponding labels.
    
    Returns:
        Numpy array of processed images and a list of labels (unchanged).
    """
    x_sub, y_sub = batch_x_y[0], batch_x_y[1]
    x_processed_sub = numpy.zeros(x_sub.shape[:-1])
    for x in range(len(x_sub)):
        # Grayscale
        img_gray = numpy.dot(x_sub[x][...,:3], [0.299, 0.587, 0.114])
        # Normalization
        img_gray_norm = img_gray / (img_gray.max() + 1)
        # CLAHE. num_bins will be initialized in ipyparallel client
        img_gray_norm = exposure.equalize_adapthist(img_gray_norm, nbins=num_bins)
        
        x_processed_sub[x,...] = img_gray_norm
    return (x_processed_sub, y_sub)

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

import multiprocessing
import ipyparallel as ipp
import numpy as np

def preprocess_equalize(X, y, bins=256, cpu=multiprocessing.cpu_count()):
    """ A simplified version of a function which manages multiprocessing logic. 
    This function always grayscales input images, though it can be generalized
    to apply any arbitrary function to batches.
    Args:
        X: numpy array of all images in dataset.
        y: a list of corresponding labels.
        bins: the amount of bins to be used in histogram equalization.
        cpu: the number of cpu cores to use. Default: use all.
    Returns:
        Numpy array of processed images and a list of labels.
    """
    rc = ipp.Client()

    # Use a DirectView object to broadcast imports to all engines
    with rc[:].sync_imports():
        import numpy
        from skimage import exposure, transform, color        

    # Use a DirectView object to set up the amount of bins on all engines
    rc[:]['num_bins'] = bins

    X_processed = np.zeros(X.shape[:-1])    
    y_processed = np.zeros(y.shape)

    # Number of batches is equal to cpu count
    batches_x = np.array_split(X, cpu)
    batches_y = np.array_split(y, cpu)
    batches_x_y = zip(batches_x, batches_y)

    # Applying our function of choice to each batch with a DirectView method
    preprocessed_subs = rc[:].map(grayscale_exposure_equalize, batches_x_y).get_dict()

    # Combining the output batches into a single dataset
    cnt = 0
    for _,v in preprocessed_subs.items():
        x_, y_ = v[0], v[1]
        X_processed[cnt:cnt+len(x_)] = x_
        y_processed[cnt:cnt+len(y_)] = y_
        cnt += len(x_)
    
    return X_processed.reshape(X_processed.shape + (1,)), y_processed

Наконец, применим написанную функцию к обучающей выборке:

# X_train: numpy array of (34799, 32, 32, 3) shape
# y_train: a list of (34799,) shape
X_tr, y_tr = preprocess_equalize(X_train, y_train, bins=128)

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


Результат нормализации изображений и переноса их цветовой гаммы в градации серого


Нормализация распределения для изображений формата RGB (я использовал другую функцию для rc[:].map)

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


num_bins: 8, 32, 128, 256, 512

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

Наконец, используем ipython magic %store, чтобы сохранить результаты для дальнейшего использования:

# Same images, multiple bins (contrast augmentation)
%store X_tr_8
%store y_tr_8
# ...
%store X_tr_512
%store y_tr_512

Инструмент 3: Онлайн-аугментация данных


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

Для начала обозначим все планируемые преобразования, используя numpy и skimage:

import numpy as np
from skimage import transform
from skimage.transform import warp, AffineTransform

def rotate_90_deg(X):    
    X_aug = np.zeros_like(X)
    for i,img in enumerate(X):
        X_aug[i] = transform.rotate(img, 270.0)
    return X_aug

def rotate_180_deg(X):    
    X_aug = np.zeros_like(X)
    for i,img in enumerate(X):
        X_aug[i] = transform.rotate(img, 180.0)
    return X_aug

def rotate_270_deg(X):    
    X_aug = np.zeros_like(X)
    for i,img in enumerate(X):
        X_aug[i] = transform.rotate(img, 90.0)
    return X_aug

def rotate_up_to_20_deg(X):
    X_aug = np.zeros_like(X)
    delta = 20.
    for i,img in enumerate(X):
        X_aug[i] = transform.rotate(img, random.uniform(-delta, delta), mode='edge')
    return X_aug

def flip_vert(X):
    X_aug = deepcopy(X)
    return X_aug[:, :, ::-1, :]

def flip_horiz(X):
    X_aug = deepcopy(X)
    return X_aug[:, ::-1, :, :]

def affine_transform(X, shear_angle=0.0, scale_margins=[0.8, 1.5], p=1.0):
    """This function allows applying shear and scale transformations
    with the specified magnitude and probability p.
    
    Args:
        X: numpy array of images.
        shear_angle: maximum shear angle in counter-clockwise direction as radians.
        scale_margins: minimum and maximum margins to be used in scaling.
        p: a fraction of images to be augmented.
    """
    X_aug = deepcopy(X)
    shear = shear_angle * np.random.rand()
    for i in np.random.choice(len(X_aug), int(len(X_aug) * p), replace=False):
        _scale = random.uniform(scale_margins[0], scale_margins[1])
        X_aug[i] = warp(X_aug[i], AffineTransform(scale=(_scale, _scale), shear=shear), mode='edge')
    return X_aug

Масштабирование и рандомные повороты rotate_up_to_20_deg увеличивают размер выборки, сохраняя принадлежность изображений к исходным классам. Отражения (flips) и вращения на 90, 180, 270 градусов могут, напротив, поменять смысл знака. Чтобы отслеживать такие переходы, создадим список возможных преобразований для каждого дорожного знака и классов, в которые они будут преобразованы (ниже приведен пример части такого списка):
label_class label_name rotate_90_deg rotate_180_deg rotate_270_deg flip_horiz flip_vert
13 Yield 13
14 Stop
15 No vehicles 15 15 15 15 15
16 Vehicles over
3.5 ton
prohibited
17 No entry 17 17 17
Часть таблицы преобразований. Значения в ячейках показывают номер класса, который примет данное изображение после трансформации. Пустые ячейки означают, что данное преобразование недоступно для этого класса.

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

import pandas as pd

# Generate an augmented dataset using a transform table
augmentation_table = pd.read_csv('augmentation_table.csv', index_col='label_class')

augmentation_table.drop('label_name', axis=1, inplace=True)
augmentation_table.dropna(axis=0, how='all', inplace=True)

# Collect all global functions in global namespace
namespace = __import__(__name__)

def apply_augmentation(X, how=None):
    """Apply an augmentation function specified in `how` (string) to a numpy array X.
    
    Args:
        X: numpy array with images.
        how: a string with a function name to be applied to X, should return 
            the same-shaped numpy array as in X.
    
    Returns:
        Augmented X dataset.
    """
    assert augmentation_table.get(how) is not None
    
    augmentator = getattr(namespace, how)
    return augmentator(X)

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

import numpy as np

def flips_rotations_augmentation(X, y):
    """A pipeline for applying augmentation functions listed in `augmentation_table`
    to a numpy array with images X.
    """
    # Initializing empty arrays to accumulate intermediate results of augmentation
    X_out, y_out = np.empty([0] + list(X.shape[1:]), dtype=np.float32), np.empty([0])
    
    # Cycling through all label classes and applying all available transformations
    for in_label in augmentation_table.index.values:
        available_augmentations = dict(augmentation_table.ix[in_label].dropna(axis=0))
        images = X[y==in_label]

        # Augment images and their labels
        for kind, out_label in available_augmentations.items():
            X_out = np.vstack([X_out, apply_augmentation(images, how=kind)])
            y_out = np.hstack([y_out, [out_label] * len(images)])

    # And stack with initial dataset
    X_out = np.vstack([X_out, X])
    y_out = np.hstack([y_out, y])
    
    # Random rotation is explicitly included in this function's body
    X_out_rotated = rotate_up_to_20_deg(X)
    y_out_rotated = deepcopy(y)

    X_out = np.vstack([X_out, X_out_rotated])
    y_out = np.hstack([y_out, y_out_rotated])

    return X_out, y_out

Отлично! Теперь у нас есть 2 готовые функции аугментации данных:

  • affine_transform: кастомизируемые аффинные преобразования без вращения (название я выбрал не очень удачное, потому что, что вращение является одним из аффинных преобразований).
  • flips_rotations_augmentation: случайные вращения и преобразования на основе augmentation_table.csv, меняющие классы изображений.

Финальный шаг — это создать генератор батчей:

def augmented_batch_generator(X, y, batch_size, rotations=True, affine=True,
                              shear_angle=0.0, scale_margins=[0.8, 1.5], p=0.35):
    """Augmented batch generator. Splits the dataset into batches and augments each
    batch independently.
    
    Args:
        X: numpy array with images.
        y: list of labels.
        batch_size: the size of the output batch.
        rotations: whether to apply `flips_rotations_augmentation` function to dataset.
        affine: whether to apply `affine_transform` function to dataset.
        shear_angle: `shear_angle` argument for `affine_transform` function.
        scale_margins: `scale_margins` argument for `affine_transform` function.
        p: `p` argument for `affine_transform` function.
    """
    X_aug, y_aug = shuffle(X, y)
    
    # Batch generation
    for offset in range(0, X_aug.shape[0], batch_size):
        end = offset + batch_size
        batch_x, batch_y = X_aug[offset:end,...], y_aug[offset:end]
        
        # Batch augmentation
        if affine is True:
            batch_x = affine_transform(batch_x, shear_angle=shear_angle, scale_margins=scale_margins, p=p)
        if rotations is True:
            batch_x, batch_y = flips_rotations_augmentation(batch_x, batch_y)
        
        yield batch_x, batch_y

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


Сгенерированные с помощью augmented_batch_generator изображения

Замечание: аугментация нужна для train-сета. Test-сет мы тоже предобрабатываем, но не аугментируем.

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


Слева: гистограмма распределения данных из augmented batch generator. Справа: изначальный train. Как видно, значения различаются, но распределения схожи.

Переход к нейронным сетям


После того, как выполнена предобработка данных, все генераторы готовы и датасет готов к анализу, мы можем перейти к обучению. Мы будем использовать двойную свёрточную нейронную сеть: STN (spatial transformer network) принимает на вход предобработанные батчи изображений из генератора и фокусируется на дорожных знаках, а IDSIA нейросеть распознает дорожный знак на изображениях, полученных от STN. Следующий пост будет посвящён этим нейросетям, их обучению, анализу качества и демо-версии их работы. Следите за новыми постами!


Слева: исходное предобработанное изображение. Справа: преобразованное STN изображение, которое принимает на вход IDSIA для классификации.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/334618/


Метки:  

[Из песочницы] 6 советов по запуску стартапа конструктора чего-угодно

Вторник, 01 Августа 2017 г. 12:59 + в цитатник
Конструкторы документов, свитеров, резюме, ботов, сайтов, постов для социальных сетей — подобные проекты постоянно попадаются на глаза. Концепция конструктора действительно актуальна и универсальна для многих товаров и услуг. Но почему некоторые конструкторы вроде Tilda “взлетают”, а многие проваливаются в самом начале пути? Попробуем разобраться какие ошибки ведут к провалу и как правильно подойти к созданию конструктора.

Не создавайте конструктор ради конструктора


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

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

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

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

Не создавайте конструктор за одну ночь


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

Кирилл Гришанин, партнер WB–Tech объясняет касаемо разработки: «Прежде, чем что-то разработать, это что-то надо спроектировать и прописать все возможные ситуации (ответы программы на действия пользователя — тест-кейсы). В случае конструктора число пользовательских сценариев очень велико, из-за чего их трудозатратно спланировать».

Кирилл приводит в пример успешного стартапа «конструктор» Readymag и акцентирует, что проект создавался несколько лет: «Таким, какой он сейчас, проект делали года три точно. Еще из наиболее успешных — Tilda. Оба проекта развивались очень постепенно, они не собирались сразу выпускать столько фич, сколько там есть сейчас».

Добавьте шаблонов и популярных решений


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

Не перебарщивайте с «фишечками»


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

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

Добавьте подсказок


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

На старте мы сами совершили эту ошибку, не дописав подсказки к некоторым полям. Например, создавая у нас набор кнопок соцсетей для сайта, человек должен был указать адрес своего ресурса. До введения подсказки к полю «Адрес сайта», люди регулярно вводили туда невалидные данные (например, давали ссылку на соцсеть, а не на свой сайт). Добавив четкую подсказку, что и в каком виде вставлять в поле, мы снизили количество ошибок ввода до 1%», — рассказывает Олег Лисовенко.

Тестируйте, тестируйте и опять тестируйте, то что уже тестировали


Длинной, но поучительной историей делится Ирина Черепанова, директор по продукту uKit: «Один из важных уроков для нас —это эксперименты с моделью монетизации. Два года назад мы стартовали как конструктор сайтов с триальной моделью (вы получаете время на тестирование, а с определенного дня должны платить за систему) и единым тарифом. Гипотеза о том, что небольшие компании и частные специалисты будут готовы платить несколько долларов за сайт, подтвердилась, но параллельно мы проводили сплит-тестирование, показывая части новых пользователей иные условия: фримиум.

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

При этом продукт, рынок, экономика или десятки факторов, о части из которых вы не всегда знаете наверняка (например, мы не сразу выяснили, как погода влияет на графики оплат, а связь есть), находятся в постоянном изменении. Мы решили перепроверять ранее полученные выводы. Периодически возвращались к тестам «триал против фримиума». На второй год мы увидели, что условно-бесплатная модель, дававшая важный эффект быстрого набора базы (к концу первого года у нас было 300 000 пользователей, а второго — уже 1,3 млн), на дистанции показывает себя менее прибыльной.

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

https://habrahabr.ru/post/334616/


Метки:  

[Перевод] Дотянуться до миллениалов: тренды и техники мобильного маркетинга

Вторник, 01 Августа 2017 г. 12:59 + в цитатник
Среднестатистический американец проводит за смартфоном почти пять часов в день. Почему же тогда мобильная реклама работает столь неэффективно?

image

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

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

Мобильные технологии стирают грань между цифровым и офлайн-шоппингом


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

Сегодня ритейлеры могут направить собираемую во время проведения безналичных мобильных транзакций информацию в CRM-системы и улучшить индивидуальный опыт каждого покупателя на основе истории покупок, геолокационных данных и временных меток. Starbucks, к примеру, собирает информацию о своих лояльных клиентах с помощью собственного брендового мобильного приложения. Оно помогает определить их текущее местоположение, какие напитки они покупают или какой тип музыки слушают (в приложении можно создавать плейлисты). Приложение Sephora to Go рекомендует новые продукты на основе истории покупок пользователя и отправляет на смартфон или умные часы пользователя пуш-уведомление всякий раз когда он находится рядом с магазином.

image image

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

image image

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

Что от этого получают покупатели (или те миллениалы, у которых еще сохранилась привычка посещать магазины вживую)? Многим нравится гармоничная непосредственность бесконтактных контекстных платежей: оплата происходит быстрее чем с чипованным банковскими картами. С другой стороны, такие платежи проще и безопаснее, чем ношение с собой обычного бумажника с наличными. Современные POS-терминалы принимают Android Pay, Apple Pay, а в последнее время еще и Selfie Pay — новый сервис, разработанный Visa совместно с BMO, позволяющий подтверждать личность пользователей с помощью биометрических проверок, и, в частности, селфи. В отличие от селфи в социальных сетях, мобильные данные в случае с Selfie Pay защищены с помощью технологии токенизации. И конечно же, все маркетинговые пуш-уведомления требуют предварительного согласия потребителей для подписки на них.

Сокращение видео для улучшения маркетинговых показателей


Более половины всех просмотров на YouTube происходят с мобильных устройств. Звучит впечатляюще с учетом того, что еще несколько лет назад буферизация видео на мобильных устройствах делала их просмотр очень трудным делом. Средняя скорость скачивания на мобильных устройствах сегодня превышает 19.27 Мбит/c, что на 30% выше, чем в прошлом году. Благодаря технологическим улучшениям, рекламщики сегодня могут отдавать покупателям больше цифрового контента на лету. Очевидно, что люди по-разному взаимодействуют с контентом на мобильных устройствах, поэтому маркетологи сокращают длительность видео, добавляют поверх них текстовые накладки для пользователей в общественных местах, у которых нет под рукой наушников.

image image

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

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

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


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

image image

Чатбот Whole Foods предлагает рецепты и упрощает процесс покупки ингредиентов.

image image

Похожим образом посетители Burger King и Pizza Hut могут оформить еду напрямую с помощью ботов в Facebook Messenger и Twitter. Однако чат-боты способны не просто заменить продавцов для ускорения приема заказов. То многообразие данных, которое эти боты собирают о каждом отдельно взятом пользователе Facebook, позволяет брендам изучать предпочтения пользователей и персонализировать процесс общения соответствующим образом. Алгоритмы глубокого машинного обучения позволяют постепенно улучшать ботов, вплоть до того, что со временем те научатся составлять нешуточную конкуренцию продавцам-консультантам локальных магазинов в плане предсказания потребительского поведения. Бренды будут продавать как основные и сопутствующие товары прямо в списке входящих сообщения приложения, по соседству с чатами друзей.

image image

Ритейл-бренды пользуются Facebook Messenger для отправки обновлений по статусам доставки и новых предложений.

Интернет вещей как способ приблизить потребителя к покупке


Брендам сегодня доступно множество изощренных способов сбора потребительских данных за счет использования Интернета вещей. Голосовые помощники, такие как Alexa, Siri, Google Assistant, Cortana и Clova от Line позволяют брендам буквально выслушать своих потребителей. Более 8 миллионов владельцев Amazon Echo и Alexа могут с легкостью отдать голосовую команду и сделать заказ у любого из поставщиков растущей сети партнеров Amazon, в том числе и таких известных брендов, как, например, Domino’s, Uber и Jamie Oliver.

Носимые устройства, подключенные к сети объекты и умные упаковки позволяют приблизить покупателя к покупке. Например, кнопки Amazon Dash подключаются к домашнему Wi-Fi пользователей и аккаунтам Amazon. Всякий раз, когда у подписчика Amazon Prime заканчивается чистящее средство, батарейки или другая хозяйственная принадлежность, простое нажатие на кнопку Dash формирует заказ и продукт доставляется в течение двух дней или даже быстрее.

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

image image

Echo Dot для Alexa заключил партнерские соглашения с передовыми брендами для включения возможности шоппинга с помощью голосовых команд.

Нативная реклама: видео привлекает больше просмотров, а мобильный поиск — больше кошельков


Snap недавно вышел на IPO со стоимостью акции в 24 доллара за единицу. Неплохой показатель для компании, уверенно захватывающей все больше B2C-бюджета на рынке и обещающей своим клиентам доступ к аудитории миллениалов — самой желанной на сегодняшний день демографической группе. Snap успешно продвигает концепцию нативной рекламы, затраты на которую в индустрии в целом, судя по некоторым оценкам, составит 53% всех выделенных на медийную рекламу в этом году средств, и большая часть этих денег придется на мобильную рекламу.

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

image image

Местная поисковая реклама стала проще с применением интеграции одних приложений внутри других, в частности, интеграции OpenTable в Google Maps.

image image

Поисковые рекламные блоки, самый популярный тип нативной рекламы (и до сих пор самый доступный), преобразуются в новый формат по мере того, как интернет-гиганты вроде Google, Apple и Tencent интегрируют в свои мобильные экосистемы все больше новых приложений. К примеру, пользователи могут воспользоваться Lyft или забронировать столик с помощью OpenTable и все это — в приложении Maps. Поисковые партнерские соглашения создают выигрышную ситуацию как для вендоров, получающих легкий доступ на рынок, так и для издателей, создающих таким образом мобильные экосистемы. Например, размер средней выручки WeChat с каждого отдельного пользователя, по некоторым подсчетам, составляет 7 долларов. В настоящий момент платформой WeChat пользуются более 8 тыс. брендов. Перед нами очень выгодный способ расширения функциональности приложения и сохранения пользователей и их заинтересованности в нем.

Резюме


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

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

https://habrahabr.ru/post/319756/


Метки:  

Hack. Sleep. Repeat

Вторник, 01 Августа 2017 г. 12:59 + в цитатник
Привет. Меня зовут Дима, и я бэкенд-разработчик в Avito. Мне довелось поучаствовать в кучке хакатонов: мелких и крупных, российских и зарубежных, внешних и внутри компаний, удалённых, распределённых и классических. Хочу рассказать, как они помогли познакомиться с омским дедом, заразиться криптобактериями, запустить виртуальный космический корабль в эрланг-вселенную и спасти человечество от вымирания.



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

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

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

Проекты


ndrctl


Название произносится как “indirectly”. Многопользовательская двухмерная игра в открытой вселенной. Космические корабли могут летать, атаковать друг друга и космические объекты. В будущем — торговать и прочие прелести. Но это всё недостаточно упорото. А что если сделать управление кораблём опосредованным (отсюда название проекта)? Предположим, что нельзя просто отправить корабль лететь влево. Но можно поставить два двигателя слева и справа и разрешить устанавливать тягу каждому из них. Хочешь лететь налево? Разверни корабль в нужную сторону, управляя тягой обоих двигателей, затем газ в пол. Плюс десять упоротости. Как сделать ещё веселее? Управлять кораблём можно с помощью кода. Обычного такого, пхп или питонячьего. Ещё плюс десять. Примерно была устроена шкала упоротости. Как видите, в текущем виде идея ещё не была достойна реализации.

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

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

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

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


Фото: FB HackdayRussia

cryptobact


На устройстве пользователя (ноутбук, телефон, планшет) живут бактерии. Они умеют питаться, размножаться, атаковать врагов. Многопользовательская игра в почти реальном мире.


Фото: hackaphone.ru

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

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

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

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

go-android-rpc


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

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

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

apisal


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

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


Фото: pvsm.ru

moov


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

resurrect-the-evolution


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

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

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

Ситуации


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

***


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

***


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

***


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

***


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

***


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

***


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

***


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

Тактика


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

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

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

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

Польза


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

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

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

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

Подготовка


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

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


Фото: hackaphone.ru

Лучше всего регулировать длительность сна можно газировкой. При достаточном количестве выпитого не было ещё ни одного проспавшего больше часа. Алкоголь категорически не подходит: очень спать хочется, а думается сильно труднее. На распределённом хакатоне работали дома у товарища. Была возможность варить ядрёный кофе. Отличная штука для борьбы со сном. И выясните вопрос с кормёжкой. Походы за едой могут отнимать очень много времени. Газировку и еду при необходимости приносите с собой.

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

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


Фото: hackaphone.ru

Послесловие


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

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

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

https://habrahabr.ru/post/334604/


Метки:  

DeNet — платформа для децентрализованного web хостинга на базе блокчейн

Вторник, 01 Августа 2017 г. 12:59 + в цитатник
Привет! Меня зовут Шелестов Денис. Программировать начал с 7-ми лет. В 16 лет, учась в 9-м классе, основал свой первый стартап – Всемирный рейтинг программистов, на котором сейчас зарегистрировано более 70-ти тысяч кодеров – и на первой же презентации перед инвестором привлек инвестиции. Также являюсь сооснователем еще нескольких интересных бизнесов.

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

У меня дома есть ноутбук как и у Вас, который постоянно подключен к интернету и никогда почти не выключается. Как-то раз я пошел в душ, где задумался о том, что У МЕНЯ В ДОМА СТОИТ НОУТБУК, КОТОРЫЙ МОЖЕТ ХОСТИТЬ 10 СТОРОННИХ САЙТОВ ОДНОВРЕМЕННО.
Почему? Потому что максимальная нагрузка на сторонние сайты клиентов была 500-700 в день. И тут меня еще больше осенило. Почти у каждого из нас есть либо полностью неиспользуемые (постоянно) устройства, либо используемые но не всю мощность устройства. Я сейчас говорю про миллионы компьютеров подключенных к сети и находящихся в онлайне. Почему бы не сделать такую систему, в которой серверами будут выступать компьютеры обычных людей?
У меня появилась такая идея — соединить компьютеры в единую сеть, где простые пользователи сдают в аренду мощность и (интернет) своих устройств, а кто-то кому это мощность нужна — берут в аренду нужное количество устройств. Получается, нужен какой-то продукт который будет использовать компы людей вместо серверов.

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

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

Что мы сейчас видим:
  • Высокая скорость доступа, за счет выбора оптимального пути загрузки для каждого пользователя сети
  • Максимальная защищенность данных, нельзя узнать у кого хранится сайт, а тот у кого хранится сайт, никогда не сможет получить доступ к тем данным сайта, которые у него хранятся
  • Удешевление услуги хостинга
  • Простые люди получают возможность заработать на своих устройствах
  • Государство не сможет бороться с хостинг-компанией, так как придется бороться со всей сетью
  • Невозможность заблокировать сайт — разные IP

Вопросы и задачи которые перед нами стоят сейчас:
  • Динамичный DNS (Нужна привычная адресация сайтов на устройства которые то включаются — то выключаются)
  • Работы сайта для обычных посетителей (нужно как-то собирать блоки из устройств в один блок на стороне клинта, без установки сторонних приложений)
  • Экономика — сколько, когда, за что и кому платить. Пока выявили для себя такие моменты: — Хранение данных, Обращение к данным, Загрузка и выгрузка данных, Исполнение приложений/скриптов, Доступность.
  • База данных (Пока есть варианты с использованием облачной базы данных), в дальнейшем скорее всего будет облачная децентрализованная база данных под этой же системой.
  • БЛОКЧЕЙН. Трендовая тема, но она здесь как-никак кстати. Кому и сколько платить? Блокчейн будет подтверждать используемость сдаваемого в аренду устройства, а также подтверждать новые версии сайтов/приложений которые будут размещаться на арендуемых устройствах.


У меня есть мысль, что есть очень много геймеров у которых есть немного свободного пространства для постоянной раздачи мощности. Например, с 12:00 до 19:00 пока вас нет дома — отдаете 99% мощности. Окупаете при этом интернет, розетку и еще и получаете $ на обед на каждый день. А может быть просто окупите интернет и розетку. А есть майнер пулы, есть еще сообщества с множеством разрозненных компов, ну вы уловили мысль…

Если наша идея понятна, не сочтите за труд ответить на пару вопросов)))

Доверили бы свой сайт децентрализованному хостингу, зная что он супер-защищен и доступен 99.99% времени?
Почему да?
Почему нет?

Поделились ли бы вы мощностями своих девайсов за N рублей в день?
Если да, то сколько это N рублей?
Если нет, то почему?
Доверили бы свой сайт децентрализованному хостингу, зная что он супер-защищен и доступен 99.99% времени?

Проголосовало 4 человека. Воздержавшихся нет.

Поделились ли бы вы мощностями своих девайсов за N рублей в день?

Проголосовало 4 человека. Воздержавшихся нет.

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

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

https://habrahabr.ru/post/334614/


Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 1075 1074 [1073] 1072 1071 ..
.. 1 Календарь