...

суббота, 28 июня 2014 г.

Дайджест интересных материалов из мира веб-разработки и IT за последнюю неделю №115 (22 — 28 января 2014)

Только зарегистрированные пользователи могут оставлять комментарии.

Войдите, пожалуйста.




Метки лучше разделять запятой. Например: общение, социальные сети, myspace.com, подростки, мердок


или закрыть

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Подробный обзор Wolfram Programming Cloud (Облака Программирования Wolfram)


23 июня 2014 г., менее недели назад, после долгой разработки, вышел в свет новый продукт от компании Wolfram Research, который называется Wolfram Programming Cloud (Облако Программирования Wolfram). Об этом своем блоге написал Стивен Вольфрам и его пост был переведен на Хабрахабре.


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


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






Из обзора вы узнаете о том, как работать с Wolfram Programming Cloud, создавать формы ввода и API, использовать Wolfram Desktop и пр.


В видео рассмотрены конкретные примеры работы в Облаке с географическими данными, API ВКонтакте, отправкой сообщений на e-mail из Облака, обработкой и подгрузкой изображений (как с устройств пользователя, так и из сети Интернет), применение встроенных функций Wolfram Language и др.


Основные коды на языке Wolfram, использованные в видео-обзоре:


График рельефа местности


CloudDeploy@FormFunction[
{"city" -> "ComputedCity"},
Module[{data},
data = GeoElevationData[GeoBoundingBox[GeoDisk[#city, Quantity[10, "Kilometers"]]]];
Grid[{{#city},
{ListPlot3D[data, MeshFunctions -> {#3 &}, Mesh -> {{1, 0}}, MeshStyle -> Thick,
ColorFunction -> ColorData["HypsometricTints"], ColorFunctionScaling -> False,ImageSize -> 600]}},
Alignment -> {Center,Center}]]&,
"HTML"]





Приложение для обработки изображений


im1=Import["путь к файлу или веб-ссылка"];

im2=Import["путь к файлу или веб-ссылка"];

images =RemoveAlphaChannel[ColorConvert[#, "RGB"] ,White]&/@{im1, im2};

webString[str_]:=StringReplace[ExportString[Cell[str], "HTML", "FullDocument" -> False],"<span>"|"</span>" -> ""]

CloudDeploy[
FormFunction[
{{"im1","Первая картинка"} -> "Image",
{"im2",webString@"Вторая картинка"} -> "Image"},
Module[{images,imDims,minX,minY,image,head},
images = RemoveAlphaChannel[ColorConvert[#, "RGB"] ,White]&/@{#im1, #im2};
imDims = ImageDimensions /@ images;
minX = Min[imDims[[;; , 1]]];
images = ImageResize[#, minX] & /@ images;
imDims = ImageDimensions /@ images;
minY = Min[imDims[[;; , 2]]];
Table[image[i] = ImageData[ImageCrop[images[[i]], {minX, minY}]], {i, 1, Length[images]}];
head = 1;
Image@Table[head = Replace[head, {1 -> 2, 2 -> 1}];image[head][[i, j]], {i, 1, minY}, {j, 1, minX}]]&,
"PNG",
AppearanceRules -> <|"Title" -> webString@"СМЕШИВАТЕЛЬ ИЗОБРАЖЕНИЙ",
"Description" -> webString@ "Выберите два изображения, смесь которых вы хотите получить.",
"SubmitLabel" -> webString@"Готово"|>]]





Работа с API ВКонтакте


$VkAPIAccessToken ="ваш accesstoken";

VkAPIMethod[method_, {options___}] := Module[{response},
"response" /.ImportString[URLFetch["http://ift.tt/1huYTUH" <> method, "Parameters" -> {"access_token" -> $VkAPIAccessToken, options}], "JSON"]];

message :=
Module[{fromId, date, text, Body, Subject,password},
{currentId, fromId, date,text} = {"id", "from_id", "date", "text"} /.VkAPIMethod["wall.get", {"owner_id" -> "-1172233", "offset" -> "0","count" -> "1"}][[2]];
Body = ToString[TableForm@{Row[{"От пользователя: ","http://vk.com/id" <> ToString@fromId}],
DateString[AbsoluteTime[{1970, 1, 1, 0, 0, 0}] + date, {"Hour", ":","Minute", ":", "Second", " ", "Day", ".", "Month", ".","Year"}], text}];
Subject ="Новое сообщение в группе Русскоязычной поддержки Wolfram Mathematica ВКонтакте";
password = CloudSymbol["pass"];
If[currentId === lastId, Null,
SendMail["To" -> "r.a.osipov@gmail.com", "Subject" -> Subject,"Body" -> Body, "Password" -> password];
lastId = currentId]]

message;



Надеюсь, что этот видео-обзор заинтересует вас и позволит вам быстрее начать работать с Wolfram Programming Cloud!


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Умные часы или просто часы? (Опрос)

Умные часы, способные связаться со смартфоном, просто часы с различными дополнениями вроде пульсометра — они всё больше входят в моду, становятся обычным бытовым предметом. Или не становятся? По этой причине я решил провести небольшой опрос на эту тему.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Entity Framework и производительность

В процессе работы над проектом веб-портала, я исследовал возможности улучшить производительность, и наткнулся на небольшую статью про микро-ORM Dapper, который был написан авторами проекта StackOverflow.com. Изначально их проект был написан на Linq2Sql, а теперь все критичные к производительности места переписаны с использованием означенного решения.

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

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


Но статья не о том, насколько EF ускоряет разработку, и не о том, что не очень хорошо иметь часть запросов написанных на linq, а часть сразу на sql. Здесь я приведу решение, позволяющее совместить EF-сущности и Linq2Entities запросы с одной стороны и «чистую производительность» ADO.Net с другой. Но сначала немного предыстории. Все, кто с такими проектами работал, как я полагаю, сталкивались с тем, что per-row вызовы работают весьма медленно. И многие, вероятно, пытались оптимизировать это, написав огромный запрос и втиснув в него все, что только можно. Это работает, но выглядит очень страшно — код метода огромен, его трудно поддерживать и невозможно тестировать. Первый этап решения, который я опробовал, это материализация всех нужных сущностей, каждой отдельным запросом. А соединение/преобразование их в доменную структуру происходит раздельно с материализацией.

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



int clientId = 42;
var policies = context.Set<policy>().Where(x => x.active_indicator).Where(x => x.client_id == clientId);




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

var coverages = policies.SelectMany(x => x.coverages);
var premiums = coverages.Select(x => x.premium).Where(x => x.premium_type == SomeIntConstant);




Сущности, связанные посредством NavProps, также можно подгрузить посредством Include, но с этим возникают свои трудности, проще(и производительнее, об этом далее) оказалось сделать как в означенном примере.

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

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



var tasks = workflows.SelectMany(x => x.task)
.Where(x => types.Contains(x.task_type))
.GroupBy(x => new { x.workflow_id, x.task_type})
.Select(x => x.OrderByDescending(y => y.task_id).FirstOrDefault());




Как выяснилось, EF генерирует очень неудачный запрос, и всего лишь передвинув GroupBy с последнего места на первое, я приблизил скорость выполнения этих запросов к остальным, получив около 30-35% уменьшения итогового времени исполнения.

var tasks = context.Set<task>
.GroupBy(x => new { x.workflow_id, x.task_type})
.Select(x => x.OrderByDescending(y => y.task_id).FirstOrDefault())
.Join(workflows, task => task.workflow_id, workflow => workflow.workflow_id, (task, workflow) => task)
.Where(x => types.Contains(x.task_type));




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

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

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

В качестве прототипа решения, я попробовал реализовать материализацию через PetaPoco, и был сильно впечатлен тестовым результатом, разница в во времени материализации целевой группы запросов составила 4.6х (756ms против 3493ms). Хотя правиьнее было бы сказать, что я был разочарован производительностью EF.

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

Решение полагается на то, что при генерации запросов, EF в запросе укажет имена полей для датасета, соответсвующие именам свойств объектов, которые он сгенерировал для контекста. Альтернативно, можно полагаться на порядок следования этих полей, что также работает. Чтобы извлечь запрос и параметры из запроса, используется метод ToObjectQuery, а уже на результирующем объекте используются метод ToTraceString и свойство Parameters. Далее следует простой цикл чтения, взятый из MSDN, «Изюминкой» решения являются материализаторы. PetaPoco эмитирует код материализатора в runtime, я же решил сгенерировать код для них с помощью T4 Templates. За основу взял файл, который генерирует сущности для контекста, считывая при этом .edmx, использовал из него все вспомогательные классы, и заменил непосредственно генерирующий код.

Пример сгенерированного класса:



public class currencyMaterialize : IMaterialize<currency>, IEqualityComparer<currency>
{
public currency Materialize(IDataRecord input)
{
var output = new currency();
output.currency_id = (int)input["currency_id"];
output.currency_code = input["currency_code"] as string;
output.currency_name = input["currency_name"] as string;
return output;
}

public bool Equals(currency x, currency y)
{
return x.currency_id == y.currency_id;
}

public int GetHashCode(currency obj)
{
return obj.currency_id.GetHashCode();
}
}




Код, который эмитирует PetaPoco, условно идентичен этому, что в том числе подтвержаются одинаковым временем исполнения.

Как видно, класс также реализует интерфейс IEqualityComparer, из чего уже должно быть понятно, что на объектах, материализованных таким образом, обычное сравнение ReferenceEquals уже не работает, в отличие от объектов, которые материализует EF, и для того, чтобы сделать в памяти Distinct, и нужно было такое дополнение.

Результат изысканий я оформил в виде Item Template и опубликовал в галерее Visual Studio. Краткое описание, как использовать, там присутствует. Буду рад, если кого то заинтересует решение.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Возобновились продажи Parallella board от Adapteva

Здравствуйте.


Компания Adapteva в четверг, 26 июня, разослала всем о возобновлении продаж их open source плат Parallella board. Сами продажи начались вчера. На хабре ранее упоминалось, например здесь http://ift.tt/YjjNqe.




Напомню, Parallella board — это высокопроизводительная плата, которая базируется на SoC Xilinx ZYNQ 7010 (или ZYNQ 7020), а также Adapteva Epiphany III с 16 ядрами. Первый кристалл содержит в себе два ядра ARM Cortex-A9 и FPGA уровня Artix-7, плюс куча периферийных контроллеров (Ethernet, USB 2.0, NAND, SPI, I2C и т.д). Второй чип является собственной разработкой Adapteva. Плата предназначена для вычислений и призвана показать всю мощь взаимодействия ARM, FPGA и DSP ядер. Успешно прошла Kickstarter.


Сама плата имеет несколько модификаций, в зависимости от ZYNQ 7010 или ZYNQ 7020, а также в наличии или отсутствии GPIO выходов. Итак всего три варианта. Информация на сайте http://ift.tt/17kS4Lz.


Прошу прощение за какие-либо неправильности, пишу первый раз.


P.S. Сам, давно думал приобрести ее, продажи ожидал около года. Сегодня решился, но разочаровался. увидев строку следующего содержания.

Sorry, we don't ship to Russia

Может народ подскажет, как приобрести ее, очень хотелось бы попробовать ZYNQ и Epiphany III. Я бы отблагодарил за труды.

К тому же, отдельно демоплаты с ZYNQ продаются от 600$.

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


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


С днем рождения, Элон Маск!


«I would like to die on Mars; just not on impact.»



image

Дата рождения: 28 июня 1971

Место рождения: Южная Африка

Образование: физика, экономика

Дети: 5 шт

Книги, оказавшие влияние: «Автостопом по галактике» (Дуглас Адамс), «Основание» ( Айзек Азимов)

Компании: Zip2, X.com, PayPal, SolarСity, Tesla Motors, SpaseX, HyperLoop

Награды: бизнесмен года (2013, Fortune), CEO года (2013, The Wall Street Journal) и др

Интервью (статьи на Хабре):

Интервью с Элоном Маском. Часть 1 — о том, как он хотел стать физиком, но стал предпринимателем

Интервью с Элоном Маском. Часть 2 — про массу, про Марс и про MBA


Экскурсия по SpaceX (2011)



Под катом самое свежее(вроде бы) видео интервью на английском

Elon Musk: 5 Areas That Will Have the Most Important Effect on Humanity | Inc. Magazine

(кто найдет там что-нибудь интересное — пишите в комменты)




This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


GlobalsDB в другом обличии и тонкости работы с этой базой данных

Здравствуйте, дорогие хабрачитатели.

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



Мной разработан программный продукт, позволяющий с помощью графического интерфейса манипулировать данными внутри GlobalsDB, а также и в СУБД Caché. Про GlobalsDB уже было написано несколько полезных и обучающих статей, с которыми вы можете ознакомиться в разделе «читайте также». Сама по себе GlobalsDB достаточно проста по своей структуре, и имеет небольшой, но достаточный набор функций для реализации серверных приложений практически любой сложности. Отличительными её особенностями являются простота, свободное распространение и использование устойчивого, испытанного механизма хранения данных в так называемых глобалах.


GlobalsDB Admin




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

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



О возможностях



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

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


Установка, настройка и управление



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


  1. Устанавливаем NodeJS, если он не был ранее установлен;

  2. Распаковываем последнюю версию GlobalsDB Admin;

  3. Меняем в файле config.js абсолютный путь к mgr каталогу вашей базы данных и другие интересующие вас настройки;

  4. Убеждаемся, что модуль node_modules/globalsDB/cache.node подходит для вашей системы/базы данных. Если архив с GlobalsDB Admin был распакован не в ОС Windows, вам нужно будет отыскать cache***.node модуль в директории с установленной базой данных, переименовать его в cache.node и указать к нему путь в файле config.js (или переместить модуль в директорию node_modules/globalsDB). Так же возможен вариант скачать *.node модуль с официального сайта;

  5. Убеждаемся, что GlobalsDB (или инстанс Caché, путь к базе данных которого был прописан в config.js) запущен, и NodeJS умеет выполнять команды (по крайней мере node --version должен давать что-то разумное);

  6. Выполняем node run в директории проекта, и если сообщений об ошибках не появилось, то по умолчанию станет доступен веб-клиент на знакомом 127.0.0.1.




Если же вам потребуется запустить серверное приложение в фоновом режиме, установите forever, выполнив npm install -g forever, а затем запустив приложение: forever start run.js.




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

Клавиатура

Выбор узла: стрелки вверх/вниз, выбор действия (переход, редактирование, копирование, удаление) — стрелки влево/вправо, клавиша Enter — выполнение действия над узлом, клавиша Backspace — возврат, клавиши -/+ — уменьшение или увеличения масштаба.


Указатель и сенсорный экран

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


Так же все подробности о том, как установить и обращаться с этим инструментом вы можете посмотреть в этом скринкасте.


GlobalsDB tips and tricks



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

При первой установке базы данных она выглядит как чёрный ящик. Бегло перелистав документацию по интерфейсу NodeJS, можно было наткнуться на первую нужную функцию global_directory, чтобы узнать, лежит ли в базе данных по умолчанию хоть что-то. Подключившись и получив результат окажется, что там пусто, что было достаточно ожидаемым. Но на самом деле это не совсем так. В корне располагаются некоторое количество системных глобалов, а они скрыты. Например, получится достать глобал с именем "%", или "%IS". Чтобы отобразить этот глобал в GlobalsDB Admin, достаточно нажать на + (добавить) у корневого узла и ввести его имя, например, "%IS" без установки значения. Нажав «add», можно будет просмотреть содержимое данного глобала:



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


Другим любопытным моментом есть то, что самой GlobalsDB безразлично, какие username, password и namespace будут переданы функции db.open. С одной стороны, в GlobalsDB отсутствует такое понятие как пользователь, но с другой, документация по функции open говорит писать именно так. Всё потому, что приложение можно очень просто перенастроить для работы с, например, самой базой данных Caché — достаточно указать соответствующий путь к папке mgr, и готово — теперь работа идёт в указанном пространстве имён от прав пользователя, под которым был выполнен вход. Таким образом, GlobalsDB Admin может взаимодействовать не только непосредственно с базой данных Globals, а и с другими продуктами InterSystems.


Заключение



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

Читайте также




Знакомство с GlobalsDB

Немного о GlobalsDB Node.JS API

Хорошее описание преимуществ GlobalsDB + NodeJS

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Samsung и Google повысят уровень защиты информации в Android


сегодня в 13:31


Добрый день, Хабр!

Компании Samsung Electronics и Google на днях объявили, что часть технологии Samsung KNOX будет интегрирована в новую версию операционной системы Android. Новая версия Android, которая была презентована на этой неделе на Google I/O, включит в себя новые функции для корпоративных пользователей и IT-администраторов — например, отдельное хранилище для управления и защиты бизнес-информации. Новая функциональность обеспечит систему защиты, соответствующую последним корпоративным требованиям к мобильным устройствам. Этот анонс — несомненно, хорошая новость для зарегистрированных разработчиков программного обеспечения для Samsung KNOX (ISVs) и прочих разработчиков, которые теперь смогут расширить потенциальный рынок за счет обширного Android-сообщества, прикладывая при этом минимальные усилия.






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


В настоящее время Samsung KNOX обеспечивает платформу Android решениями высокого уровня защиты и соответствует критериям Правительства США, Агентства по оборонным информационным системам США и другим международным стандартам безопасности для мобильных устройств. Платформа Samsung KNOX получила одобрение STIG (Security Technical Implementation Guide) версии 1 от Агентства по оборонным информационным системам США в мае 2013 года, а в апреле 2014 года Samsung KNOX было получено STIG версии 2. Также правительство Великобритании недавно опубликовало рекомендации по безопасности для пользователей, в которых рекомендовало использовать платформу Samsung KNOX при работе на устройствах Android. Помимо этого были сертифицированы на соответствие требованиям MDFPP Common Criteria следующие устройства, использующие платформу KNOX: GALAXY S4, GALAXY Note 3, GALAXY Note Pro 12.2 (февраль 2014 года), а в мае 2014 года — GALAXY S5 и Note 10.1 (2014 edition).


Компания Samsung также предлагает комплексные решения по управлению KNOX и предоставляет доступ к специализированному магазину приложений и услуг. В дополнение к компонентам Samsung KNOX, которые будут включены в новую версию операционной системы Android, Samsung продолжит развитие таких запатентованных услуг как KNOX EMM и KNOX Marketplace.




Только зарегистрированные пользователи могут оставлять комментарии.

Войдите, пожалуйста.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


История одного логотипа

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

С чего все начиналось

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


Вот так выглядел наш исходный прототип


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

Кроме того, необходимо было отстроиться от текущих на момент создания проекта коллег-конкурентов (Usarium, Arenrorium):



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

Вот еще, какие были ограничения мы поставили при создании нового лого:

— не должно быть полного адреса сайта, несмотря на размещение домена в зоне .ORG;

— проект имеет глобальные амбиции, поэтому только латиница;

— логотип создавался «на живую», т.е. внедрялся уже в действующий сайт и обновленную главную страницу.


Работа закипела


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

Далее работали над метафорой аренды/проката. Чтобы легко читалось, что это аренда вещей и массовый продукт.


Вот какие идеи рождались в процессе работы.









Все это не подходило.


Решили остановиться на словосочетании и поиграть с цветом.



Были варианты, где обыгрывалась буква R



Попытка в одном цвете и ещё вариант несерьезной надписи.



Всё не то!!!


Варианты буквы R с глобусом отдельно нам тоже не понравились:













Внезапно! Приглянулось вроде…



Но сразу же забраковываем. Слишком не серьёзно и не ясно.

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


Выбираем таблички.



Метафора напоминает буллит на карте или сноску/комментарий. Оцениваем разные варианты:



Пробуем на сайте:




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


Смотрим однотонные варианты.



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

Геометрически обосновываем решение. Берём за основу иконку с сайта.



Пробуем на сайте.




Вариант, где лого выезжает за пределы, нравится всем. Выглядит уверенно и нестандартно. Останавливаемся на нём и поправляем цвет. Результат вполне хорош.


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


Условия создания логотипа

Логотип разрабатывался в течение недели в свободном режиме, на него было потрачено 5000 рублей на троих (графический дизайнер, генератор идей и менеджер-критик).


Результат



Как можно использовать


Можно использовать в черно-белом варианте. Можно применять в офлайн-материалах. А также — делать водным знаком.


Что скажете?


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


И, надеемся, наш опыт вам пригодится!


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


[Перевод] Начинаем работать с browserify



Введение




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


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


Что такое Browserify?




Browserify позволяет вам использовать стиль node.js модулей для работы в браузере. Мы определяем зависимости и потом Browserify собирает их в один маленький и чистенький JavaScript файл. Вы подключаете ваши JavaScript файлы используя require("./ваш_файл.js"); выражение. Так же вы можете использовать публичные модули из npm. Для Browserify так же не составляет никакого труда создание source map'ов (карт исходных файлов до компрессии), так что даже не смотря на конкатинацию, вы сможете отлаживать отдельные части пакета ровно так же, как вы и привыкли это делать с отдельными файлами.

Зачем импротировать node-модули?




Импортирование модулей — это как благословение: вместо того, чтобы шерстить сайты в поисках ссылок на скачку той или иной JavaScript библиотеки — вы просто подключаете их используя require() (предварительно проверив, что они установлены через npm) и всё! Вы так же можете использовать такие популярные JavaScript библиотеки, как jQuery, Underscore, Backbone и даже Angular (неофициальный порт). Они все доступны для скачивания и работы через npm. Если вы работаете над сайтом, который уже использует node, вы просто упрощаете себе разработку, ведь теперь вы можете использовать общую архитектуру всех ваших JS скриптов. Мне действительно нравится такой подход!

Что вам потребуется




Чтобы начать работать с Browserify, вам необходимо иметь следующее:

node.js

npm – по умолчанию поставляется с node.js

Browserify – я объясню, как его установить

Ну, и, соответственно, набор JS файлов, с которыми вы хотите работать.


Начало работы




Чтобы начать работу, вам необходимо иметь установленные node и npm. Если вы уж совсем застряли, попробуйте эти инструкции по установке Node.js через менеджер пакетов. Вам не придется выполнять никаких дополнительных телодвижений, чтобы начать использовать Browserify. Мы используем node исключительно потому, что npm работает поверх него. Как только вы получили npm, вы можете установить Browserify используя следующую команду:

npm install -g browserify




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

Error: EACCES, mkdir '/usr/local/lib/node_modules/browserify'




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

Создаем ваш первый Browserify файл




Давайте начнем с создания файда, который мы будем обрабатывать с помощью Broserify. Например, давайте возьмем суперпопулярный модуль Underscore. Мы будем использовать его для поиска супермена. Я назвал мой JS файл main.js и положил его в папку js.

Начнем с резервирования прееменной _ под Underscore, используя метод require() Browserify'а:



var _ = require('underscore');




Теперь, мы будем использовать функции each() и find() из подключенной нами библиотеки Underscore, Мы произведем поиск в двух массивах имен и на каждой итерации будем выводить значение выражения условия поиска супермена в консоль с помощью console.log. Лекс Лютер может только мечтать об этом. Наш конечный вариант кода будет выглядеть как-то так:

var _ = require('underscore'),
names = ['Bruce Wayne', 'Wally West', 'John Jones', 'Kyle Rayner', 'Arthur Curry', 'Clark Kent'],
otherNames = ['Barry Allen', 'Hal Jordan', 'Kara Kent', 'Diana Prince', 'Ray Palmer', 'Oliver Queen'];

_.each([names, otherNames], function(nameGroup) {
findSuperman(nameGroup);
});

function findSuperman(values) {
_.find(values, function(name) {
if (name === 'Clark Kent') {
console.log('It\'s Superman!');
} else {
console.log('... No superman!');
}
});
}




Мы бы хотели быть уверены, что Browserify сможет найти npm модуль, когда попробует добавить его в проект. Что ж, для того, чтобы это сделать, вам необходимо открыть терминал, перейти в директорию, в которой лежит ваш JavaScript проект, и запустить команду установки Underscore в эту директорию:

npm install underscore




Для тех, кто не знаком с механизмом работы node и npm поясню, что этот код создаст директорию node_modules в папке проекта. В этой директории будет располагаться ваш модуль Underscore. Команда получит последнюю версию Underscore из npm-репозитория (http://ift.tt/KacD7F). С этим модулем в нашей директории node_modules, Browserify сможет легко найти и использовать его.

Запуск Browserify в первый раз




Когда мы запустим Browserify, он захочет собрать новый JavaScript файл со всеми прикрепленными к нему модулями. В нашем случае, он соберет JavaScript модуль с Underscore внутри. Нам потребуется только выбрать имя для нашего нового фалйа. Я, например, решил назвать его findem.js. Я запускаю команду из корневой папки проекта:

browserify js/main.js -o js/findem.js -d




Это команда считывает ваш main.js и пишет его содержимое в findem.js (разумеется, включая пакетные зависимости. прим. пер.), который был указан с помощью опции -o. Я включил в запрос еще и опцию -d, поэтому наша команда вдобавок еще и сгенерирует source map для нашего файла. Благодаря этому, мы сможем отлаживать underscore и main.js как два отдельных файла.

Использование выходного файла Browserify




Подключается выходной Browserify файл ровно так же, как и любой другой JS файл:

<script src="js/findem.js"></script>


Испротирование ваших собственных JavaScript файлов




Совсем не здорово, если наше приложение будет состоять из одних папок node_modules. Чтобы подключить ваш собственный JavaScript код, вы можете использовать тот же подход с функцией require(). Данная строка кода импортирует JS файл с именем your_module.js в переменную greatestModuleEver:

greatestModuleEver = require('./your_module.js');




Чтобы импортировать ваш JavaScript таким образом, мы должны оформить наш JavaScript код как модуль. Чтобы это сделать, определить module.exports. Один из способов это сделать показан ниже.

module.exports = function(vars) {
// Ваш код
}




Примечание!

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

Наш пример с модулем




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

module.exports = function() {
return ['Barry Allen', 'Hal Jordan', 'Kara Kent', 'Diana Prince', 'Ray Palmer', 'Oliver Queen', 'Bruce Wayne', 'Wally West', 'John Jones', 'Kyle Rayner', 'Arthur Curry', 'Clark Kent'];
}




Что ж, теперь мы импортируем этот модуль в нашу переменную names = require("./names.js");:

var _ = require('underscore'),
names = require('./names.js');

findSuperman(names());

function findSuperman(values) {
_.find(values, function(name) {
if (name === 'Clark Kent') {
console.log('It\'s Superman!');
} else {
console.log('... No superman!');
}
});
}




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

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



Passing in Variables and Sharing Modules Across Our App




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

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



module.exports = function (values) {
var foundSuperman = false;

_.find(values, function(name) {
if (name === 'Clark Kent') {
console.log('It\'s Superman!');
foundSuperman = true;
} else {
console.log('... No superman!');
}
});

return foundSuperman;
}





Я добавил возвращаемое значение для нашей функции findSuperman(). Если она найдет супермена, вернет true, в противном случае — false. А дальше пускай решает код, который вызывает этот модуль. Но как бы то нибыло, мы упустили одну вещь: наш код использует Underscore, но мы не объявили его. После добавления Underscore, наш код принял такой вид:

var _ = require('underscore');

module.exports = function (values) {
...
}




Когда мы используем Browserify, он просматривает все наши JS файлы на предмет импорта модулей, строит дерево зависимостей, и это позволяет ему подключать модуль всего один раз, т.е. в нашем примере, мы подключаем Underscore в главном файле, и так же подключаем его в findsuperman.js, но когда Browserify соберет это всё воедино, он добавит его всего один раз. Круто, не правда ли?

Наше нынешнее JavaScript приложение в данный момент использует наш новый модуль с новым возвращаемым значением true/false. В случае нашего примера, мы просто используем document.write чтобы сказать, смогли мы найти супермена в списке имен, или же нет:



var _ = require('underscore'),
names = require('./names.js'),
findSuperman = require('./findsuperman.js');

if (findSuperman(names())) {
document.write('We found Superman');
} else {
document.write('No Superman...');
}




Нам даже больше не требуется подключать Underscore в наш главный файл, поэтому мы можем смело удалить эту строчку, он по-прежнему будет подключен в конце файла findsuperman.js.

Управление npm-зависимостями Browserify через package.json




Предположим, у вас есть друг, который так же хотел бы использовать ваш код. Будет довольно глупо ожидать от него, что он откуда-то узнает, что для работы вашего модуля ему сперва потребуется подключить underscore. Чтобы решить эту проблему, мы можем создать файл под названием package.json в корневой директории нашего проекта. Этот файл дает вашему проекту имя (убедитесь в отсутствии пробелов), описание, устанавливает ему автора и версию, и, что самое главное, npm зависимости. Те же, кто уже сталкивался с разработкой под node — мы используем тот же механизм:

{
"name": "FindSuperman",
"version": "0.0.1",
"author": "Patrick Catanzariti",
"description": "Code designed to find the elusive red blue blur",
"dependencies": {
"underscore": "1.6.x"
},
"devDependencies": {
"browserify": "latest"
}
}




Список зависимостей в данный момент ограничен нашем "underscore": "1.6.x", где первая часть зависимости — это имя, и вторая — версия. "lastest" или "*" позволит вам получить самую последнюю версию, которая есть в npm. Так же, вы можете указать номер версии как 1.6 (фиксированным числом) или 1.6.х (для версий от 1.6.0 до 1.7, не включительно).

Мы также можем подключить browserify как зависимость, но т.к. это не зависимость, необходимая для запуска проекта — любой пользователь сможет найти файл findsuperman.js без необходимости прогона Browserify. Но мы подключим его как одну из devDependencies — модулей, необходимых разработчикам, чтобы поддерживать приложение.


Теперь, когда у нас есть файл package.json, нам не придется заставлять нашего друга запускать npm install underscore. Он может просто запустить npm install и все необходимые зависимости будут установлены в директорию node_modules.


Автоматизация процесса Browserify




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



npm сам по себе может запускать консольные скрипты, как если бы вы печатали их самостоятельно. Чтобы это сделать, просто создайте раздел scripts в package.json. Это делается следующим образом:

"scripts": {
"build-js": "browserify js/main.js > js/findem.js"
}




Чтобы теперь всё это запустить, вам достаточно написать в командной строке:

npm run build-js




Но это тоже не особо удобно. Нам по-прежнему требуется запускать эту команду каждый раз. И это весьма раздражает. Лучше всего использовать npm модуль watchify. Watchify прост, лёгок и сэкономит вам кучу времени. Он будет отслеживать изменения в ваших JS скриптах и автоматически перезапускать Browserify.

Теперь добавим его в package.json к devDependencies, и не забудем прописать дополнительную строку в разделе scripts (она будет напрямую запускать наш модуль watchify, если не требуется пересборка пакетов).



"devDependencies": {
"browserify": "latest",
"watchify": "latest"
},
"scripts": {
"build-js": "browserify js/main.js > js/findem.js",
"watch-js": "watchify js/main.js -o js/findem.js"
}




Чтобы это запустить, просто напишите команду:

npm run watch-js




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

"watch-js": "watchify js/main.js -o js/findem.js -v"




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

121104 bytes written to js/findem.js (0.26 seconds)
121119 bytes written to js/findem.js (0.03 seconds)


Генерируем Source Maps в npm




Чтобы сгенерировать source maps используя npm, добавьте -d после вашей команды browserify (или watchify):

"scripts": {
"build-js": "browserify js/main.js > js/findem.js -d",
"watch-js": "watchify js/main.js -o js/findem.js -d"
}




Для того, чтобы иметь оба (один для дебага, другой для продакшена) файла, вам надо написать что-то вроде этого:

"watch-js": "watchify js/main.js -o js/findem.js -dv"


Grunt




Множество людей (да и я в том числе) уже знакомы с Grunt, и, к счастью, продолжают его использовать. К счастью потому, что Browserify прекрасно работает с этой билд-системой!

Нам потребуется изменить наш package.json, добавив туда директиву на подключение Grunt. Мы больше не будем использовать секцию scripts, это переляжет на плечи Grunt'a:



{
"name": "FindSuperman",
"version": "0.0.1",
"author": "Patrick Catanzariti",
"description": "Code designed to find the elusive red blue blur",
"dependencies": {
"underscore": "1.6.x"
},
"devDependencies": {
"browserify": "latest",
"grunt": "~0.4.0",
"grunt-browserify": "latest",
"grunt-contrib-watch": "latest"
}
}




Мы добавили сл. зависимости в наш проект:

grunt – чтобы убедиться, что у нас установлен Grunt для нашего проекта.

grunt-browserify – модуль, который позволит вам использовать browserify внутри вашего проекта.

grunt-contrib-watch – модуль, который будет отслеживать изменения ваших файлов и вызывать Browserify каждый раз при сохранении изменений в любом из наблюдаемых файлов.


Потом мы создадим файл, который назовем Gruntfile.js и положим его в корень проекта. Внутри этого Gruntfile.js мы должны написать следущее:



module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-browserify');

grunt.registerTask('default', ['browserify', 'watch']);

grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
browserify: {
main: {
src: 'js/main.js',
dest: 'js/findem.js'
}
},
watch: {
files: 'js/*',
tasks: ['default']
}
});
}




Мы начали наш Gruntfile с загрузки необходимых npm модулей, которые мы подключили в package.json:

grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-browserify');




Мы регистрируем одну (и единственную) группу задач, которая будет запускаться по умолчанию (browserify и watch):

grunt.registerTask('default', ['browserify', 'watch']);




Далее мы уконфигурируем Grunt с помощью initConfig:

grunt.initConfig({




После этого, нам надо показать, где лежит наш package.json:

pkg: grunt.file.readJSON('package.json'),




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

browserify: {
main: {
src: 'js/main.js',
dest: 'js/findem.js'
}
}




Теперь мы создадим watch-задачу для детектирования изменений в оыode> каталоге:

watch: {
files: 'js/*',
tasks: ['default']
}




Из-за наших новых зависимостей для разработки(devDependencies) нам требуется сперва запустить npm install. Запускать эту команду придется только один раз, в дальнейшем вы будете пользоваться благами Grunt'а.

Генерирование Source Maps в Grunt




С версией 2.0.1 пакета grunt-browserify несколько изменился процесс генерирования source maps, т.к. интернет кишил неправильными решениями. Теперь, чтобы заставить Grunt и Browserify правильно создавать source map'ы, достаточно просто добавить флаг debug: true в bundleOptions:

browserify: {
main: {
options: {
bundleOptions: {
debug: true
}
},
src: 'js/main.js',
dest: 'js/findem.js'
}
}




Это тяжело выглядящее решение позволит нам в будущем передавать опции в Browserify простым и изящным способом.

Gulp




Gulp npm build.

Для того, чтобы повторить всё то, что мы описали выше для Gulp, необходимо для начала установить его (глобально):



npm install -g gulp




Мы изменим наш package.json для подключения пары новых devDependencies, которые нам нужны:

"devDependencies": {
"browserify": "latest",
"watchify": "latest",
"gulp": "3.7.0",
"vinyl-source-stream": "latest"
}




Мы добавили следующее:

watchify – Мы использовали и описывали его работу еще при работе с npm

gulp – Подключаем, собственно, Gulp

vinyl-source-stream – Виртуальная файловая система для чтения/записи файлов

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

Browserify имеет API для работаы с потоками напрямую из Gulp. Большая часть руководств рекомендуют использовать gulp-browserify плагин, но сам Browserify предпочитает, чтобы работа с ним осуществлялась через его потоковый API. Мы используем vinyl-source-stream чтобы получить выходные данные Browserify и сохранить их в файл с помощью Gulp.


Потом мы создаем файл gulpfile.js в корне нашего проекта. Здесь будет лежать вся функциональность Gulp'а:



var browserify = require('browserify'),
watchify = require('watchify'),
gulp = require('gulp'),
source = require('vinyl-source-stream'),
sourceFile = './js/main.js',
destFolder = './js/',
destFile = 'findem.js';

gulp.task('browserify', function() {
return browserify(sourceFile)
.bundle()
.pipe(source(destFile))
.pipe(gulp.dest(destFolder));
});

gulp.task('watch', function() {
var bundler = watchify(sourceFile);
bundler.on('update', rebundle);

function rebundle() {
return bundler.bundle()
.pipe(source(destFile))
.pipe(gulp.dest(destFolder));
}

return rebundle();
});



gulp.task('default', ['browserify', 'watch']);




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

sourceFile – местоположение и название исходного Browserify-файла (в нашем случае js/main.js)

destFolder – местоположение финального файла

destFile – имя, которое мы хотим дать нашему финальному файлу

Следующий код я объясню более детально:


Как Browserify работает с Gulp



Первая задача в нашем gulpfile.js — это «browserify»:

gulp.task('browserify', function() {




Здесь мы передаем наш исходный файл main.js в npm пакет Browserify:

return browserify(sourceFile)




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

.bundle()




Здесь мы перекидываем информацию из потока в файл с названием findem.js и сохраняем его в директорию js.

.pipe(source(destFile))
.pipe(gulp.dest(destFolder));




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

Объединяем Watchify и Gulp




Как мы уже поняли, использовать Browserify напрямую доставляет немало боли (хе-хе, прим. пер) и намного проще запускать его автоматически, когда изменяется один из файлов пакета. Чтобы реализовать подобную схему, мы будем ещё раз использовать npm модуль watchify.

Мы начнём с установки задачи, которая называется наблюдателем:



gulp.task('watch', function() {




Мы присваиваем модуль наблюдателя переменной bundler (т.к. мы будем использовать его дважды):

var bundler = watchify(sourceFile);




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

bundler.on('update', rebundle);




Так что же такое rebundle()? Это очень похоже на то, что делает наша задача Browserify:

function rebundle() {
return bundler.bundle()
.pipe(source(destFile))
.pipe(gulp.dest(destFolder));
};

return rebundle();
});




При какой-то острой необходимости, вы можете объединить browserify и watchify вместе, но я бы рекомендовал вам оставить их отдельно друг от друга, по крайней мере в этой статье. Для более глубокого изучения, вы можете посмотреть на gulpfile.js Дана Тэлло.

Чтобы закончить наш gulpfile.js, нам нужно создать нашу задачу по умолчанию (работает по тому же принципу, что и grunt).



gulp.task('default', ['browserify', 'watch']);




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

gulp




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

Вы можете так же запустить задачу Browserify вручную:



gulp browserify




Аналогично с вашей задачей-наблюдателем:

gulp watch




Генерируем Source Maps используя Gulp и Browserify




Для того, чтобы сгенерировать source map для вашего JavaScript, добавьте { debug: true } в обе функции bundle().

Наша browserify задача будет похожа на что-то следующее:



gulp.task('browserify', function() {
return browserify(sourceFile)
.bundle({debug:true})
.pipe(source(destFile))
.pipe(gulp.dest(destFolder));
});





Функция rebundle() в нашей watch-задаче будет выглядеть так:

function rebundle() {
return bundler.bundle({debug:true})
.pipe(source(destFile))
.pipe(gulp.dest(destFolder));
}


Заключение




И всё же это только рассвет Browserify, и, могу сказать с полной уверенностью, он стоит на пути к улучшению и совершенствованию. В своём нынешнем состоянии, он является весьма полезным инструментом структурирования вашей модульной системы JavaScript приложения и особенно полезным для тех, кто использует Node на своей серверной части. Код становится намного чище и проще для Node разработчиков, когда вы начинаете использовать npm модули в обоих частях вашего приложения. Если вы ещё не пробовали Browserify, настоятельно рекомендую попробовать его в вашем следующем проекте и посмотреть, как он перевернет ваш мир!

Прочие ресурсы




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

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Moto 360: умные и красивые часы от Motorola


Еще в марте на Хабре проскакивала новость о том, что Motorola и LG планируют выпустить умные часы на платформе Android Wear. LG с этой задачей уже справились, выпустив LG G Watch, да и Google Motorola уже вот-вот отгрузит первую партию Moto 360 (так называется девайс) для продажи.


Во всяком случае, журналистам TheVerge удалось немного потестировать тестовый образец Moto 360. Кроме того, удалось «подержать в руках» и персональный девайс исполнительного директора Motorola. По словам журналистов, и тестовый образец «для всех», и личное устройство работали одинаково хорошо (внешний вид у них также практически идентичен, что немудрено — ведь это одна и та же модель).


Под катом — штук 10 фотографий общим объемом в 2-3 МБ.


Первые впечатления


Журналистам часы Moto 360 понравились: на руке сидит хорошо, выглядят тоже отлично, при этом устройство можно назвать практичным, это не украшение. Собственно, дизайн умных гаджетов становится все более интересным (например, вот фитнес-трекер Activité, который никак не похож на трекер).



Moto 360 будут поставляться в разных цветовых решениях, включая «черный-на-черном» — весьма стильно, да.




Дизайн


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


Экран яркий и достаточно большой (1,8 дюйма). По словам журналистов, сенсорный дисплей весьма отзывчив на прикосновения, лагов и «залипаний» нет.


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


Функциональность


В общем-то, Moto 360 умеет делать то, что умеют и другие умные часы. Это связь со смартфоном (Bluetooth 4.0 LE.), а значит, возможность получать уведомления о сообщениях и вызовах прямо на дисплей носимого устройства.



Это — фитнес-трекер, показывающий, сколько человек прошел за день, и сколько шагов было сделано.



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



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



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




Немного видео



Цена и заказ


Скорее всего, цена будет составлять около 250 долларов США (точнее пока сказать не получится). Заказать часики можно будет либо у производителя, плюс запросить уведомление о поступлении устройства в продажу на сайте Madrobots.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.