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

Поиск сообщений в predefglas

 -Подписка по e-mail

 

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 10.12.2014
Записей:
Комментариев:
Написано: 94





Заметки фрилансера: как перестать бояться и начать работать на себя

Пятница, 06 Января 2017 г. 07:37 + в цитатник
Привет! Последние несколько лет я занимался фрилансом на Upwork (бывший oDesk) и вот наконец решился решил поделиться своим опытом и наблюдениями с Хабрасообществом в небольшом цикле статей. Начать хотелось бы издалека: кому на мой взгляд стоит рассмотреть фриланс как основной вид своей деятельности + хотелось бы разобрать основные «отпугивающие» факторы, которые мешают многим решиться. Кому небезразлична тема фриланса и Upwork в частности — добро пожаловать под кат.
Читать дальше >

Метки:  

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

Среда, 07 Декабря 2016 г. 01:38 + в цитатник
Уже шесть лет я публикую регулярные обзоры свежих статей по теме интерфейсов, новых инструментов и коллекций паттернов, интересных кейсов и исторических рассказов. Из лент нескольких сотен тематических подписок отбирается примерно 5% стоящих публикаций, которыми интересно поделиться. Предыдущие материалы: апрель 2010-октябрь 2016.

Читать дальше >

Метки:  

Функциональная безопасность, Часть 2 из 2. МЭК 61508: кем быть, Шерлоком Холмсом или Дата Туташхиа?

Воскресенье, 11 Сентября 2016 г. 00:14 + в цитатник
источник#1; источник#2 Безопасности на хабре посвящен целый хаб, и, пожалуй, никто особенно не задумывается, что именно вкладывается в понятие «безопасность», и так все ясно: информационная безопасность (security). Однако, есть еще и другая сторона безопасности, safety, связанная с рисками для здоровья и жизни людей, а также окружающей среды. Поскольку информационные технологии сами по себе опасности не представляют, то обычно говорят о функциональной составляющей, то есть о безопасности, связанной с правильным функционированием компьютерной системы. Если информационная безопасность стала критична с появлением интернета, то функциональная безопасность рассматривалась и до появления цифрового управления, ведь аварии происходили всегда. Данная статья продолжает серию публикаций на тему функциональной безопасности. Во вводной части 1: — обоснована важность оценивания и обеспечения функциональной безопасности для компьютерных систем управления; — рассмотрены архитектуры систем, для которых необходимо оценивать и обеспечивать функциональную безопасность; к таким системам относятся АСУ ТП (Industrial Control Systems) на базе программируемых логических контроллеров (ПЛК), встроенные системы (Embedded Systems) и уровень устройств (Device Layer) для интернета вещей; — кратко представлено множество стандартов, относящихся к функциональной безопасности в различных сферах применения. Для того чтобы сделать еще один шаг, необходимо продолжить рассмотрение стандарта МЭК 61508 «Функциональная безопасность систем электрических, электронных, программируемых электронных, связанных с безопасностью» (IEC 61508 Functional safety of electrical/electronic/programmable electronic safety-related systems). Дело в том, что функциональная безопасность – это достаточно формализованное свойство, поскольку системы, важные для безопасности, являются предметом государственного лицензирования во всех странах. Изучение стандартов и заложенной в них терминологии – это не самое веселое занятие в мире, но, при прагматичном подходе, технический уровень специалиста может от этого повыситься. Толкование терминологии является своего рода «технической юриспруденцией», а хитросплетению сюжетных линий в изложении требований может позавидовать любой автор детектива. Я не стану уверять, что, изучая стандарты, все сразу станут техническими Шерлоками Холмсами. Хотя, знание основ стандартизации (то есть, технического законодательства), лежит в основе работы любого сыщика технического эксперта. Изучение стандартов – это скорее путь Дата Туташхиа из полузабытого ныне романа Чабуа Амирэджиби (а есть еще экранизация – «Берега»), путь не столько вперед, сколько в глубину, не столько в действие, сколько в осмысление. Общие сведения о МЭК 61508 Стандарт оперирует термином электрическая/ электронная/ программируемая электронная (Э/Э/ПЭ) система (electrical/electronic/programmable electronic). Особенностью стандарта является риск-ориентированный подход. В зависимости от риска, который техногенный объект создает для окружающей среды, жизни и здоровья людей, устанавливаются риски для отказов систем управления. Например, обратим внимание на системы защиты атомных реакторов. Для них в режиме постоянной работы отказы должны происходить не чаще, чем один раз в 1000 лет эксплуатации (10 миллионов часов наработки на отказ). Такие показатели задаются не для единичного объекта, а для «флота», т.е. для множества однотипных объектов. Вроде бы, отказы являются достаточно редкими событиями, ведь ни одна атомная электростанция не проработает тысячу лет. Однако, если учесть, что в мире эксплуатируется более 400 атомных реакторов, то для «флота» мы уже получим цифру один отказ в 2,5 года, что звучит гораздо более удручающе. Во время Чернобыльской и Фукусимской ядерных катастроф системы аварийной защиты не сработали так, как ожидалось проектировщиками. Это еще один аргумент в пользу важности рассмотрения функциональной безопасности. Для снижения значений рисков ниже заданных показателей реализуется комплекс организационно-технических мер, которые также регламентированы в МЭК 61508, в зависимости от допустимой величины риска отказа. Кроме того, МЭК 61508 представляет собой верхний уровень целого семейства отраслевых стандартов, которые детализируют требования к функциональной безопасности для систем управления медицинским оборудованием, автомобильным и железнодорожного транспортом, АСУ ТП и т.д. Первая редакция МЭК 61508 была разработана с 1998 по 2000 годы. В Российской Федерации первая редакция была принята в качестве государственного стандарта ГОСТ Р МЭК 61508 в 2007 году. В настоящее время в мире действует вторая редакция МЭК 61508, выпущенная в 2010. В Российской Федерации вторая редакция МЭК 61508 также является актуальной с 2012 года (ГОСТ Р МЭК 61508-2012). Серия стандартов МЭК 61508 включает 7 частей, которые в сумме содержат около 600 страниц текста. О назначении частей легко догадаться по их названиям. Конечно, между частями МЭК 61508 существуют довольно сложные связи, что отражено в рисунках самого стандарта: Overall framework of the IEC 61508 series (IEC 61508, Figure 1). Терминология МЭК 61508: базовые термины по безопасности Для того, чтобы разобраться с концепцией функциональной безопасности, пожалуй, начать надо, не с начала и не с конца, а с середины, а именно с четвертой части (МЭК 61508-4), где изложена основная терминология. Как видим, термины разделены на 8 групп (3.1-3.8). Эти группы логически связаны между собой. На мой взгляд, самыми важными являются группы 3.1 (Safety terms) и 3.5 (Safety functions and safety integrity). Далее термины выборочно цитируются согласно русскоязычному тексту МЭК 61508-4, а затем дается их авторская интерпретация. Итак, первый раздел по терминологии, 3.1 «Термины, относящиеся к безопасности». Смотреть термины, относящиеся к безопасности»3.1.1 вред (harm): Физическое повреждение или ущерб, причиняемый здоровью людей, имуществу или окружающей среде. 3.1.2 опасность (hazard): Потенциальный источник причинения вреда 3.1.6 риск (risk): Сочетание вероятности события причинения вреда P(t) и тяжести этого вреда C. 3.1.7 допустимый риск (tolerable risk): Риск, который приемлем при данных обстоятельствах на основании существующих в обществе ценностей. 3.1.11 безопасность (safety): Отсутствие неприемлемого риска. 3.1.12 функциональная безопасность (functional safety): Часть общей безопасности, обусловленная применением управляемого оборудования (УО) и системы управления УО, и зависящая от правильности функционирования систем, связанных с безопасностью, и других средств по снижению риска. 3.1.13 безопасное состояние (safe state): Состояние УО, в котором достигается безопасность. Я попытался связать все сущности в единое целое, и в результате получилась следующая схема (пожалуй, можно назвать ее онтологией). Важно отметить, что компьютерная система управления (КСУ) является лишь одной из многих мер по снижению рисков. Существует множество так называемых пассивных мер защиты, например, ремень безопасности в автомобиле или в самолете. Риск является показателем безопасности, и на понятии риска необходимо будет обратить внимание в дальнейшем, при рассмотрении этих самых показателей. Пока приведу простой пример. Ходит зачем-то человек по краю крыши. Вероятность падения с крыши при прочих равных условиях не зависит от высоты здания. А вот степень ущерба зависит. Тогда и риск падения с крыши 10-этажного здания будет выше, чем риск падения с крыши одноэтажного здания. А вот риск падения с крыши 10-этажного здания практически равен риску падения с крыши 100-этажного здания, поскольку, если вероятность падения одинакова, то и последствия (ущерб) падения здесь, к сожалению, также одинаковы. Интересным, на мой взгляд, является понятие допустимого (приемлемого) риска. Оно зависит от исторического и гуманитарного контекста. Правда ли, что наивысшими ценностями современного общества является человеческая жизнь и забота об окружающей среде, которая формирует и поддерживает эту самую жизнь? Реальное состояние техногенных объектов демонстрирует, насколько государство и общество реализуют провозглашенные ценности. Еще одним принципиальным понятием является «безопасное состояние». Например, одна из важнейших систем безопасности, система противоаварийной защиты (ПАЗ), должна остановить функционирование управляемого объекта. Как это происходит? Как правило, путем разрыва электрических цепей (это уже зависит от технологических алгоритмов управления оборудованием), что происходит путем перевода выходных дискретных сигналов в состояние «логический 0» (так называемый принцип de-energize to trip, чтобы система могла отработать и при аварийной потере электроснабжения). При необходимости, «логический 0» может быть инвертирован в «логическую 1» через промежуточные реле. Терминология МЭК 61508: термины, относящиеся к функциям безопасности и полноте безопасности (safety integrity) В первой части цикла статей я уже вкратце упоминал, что понятие функциональной безопасности включает в себя реализуемые функции безопасности и полноту (интегрированность) выполнения этих функций. В МЭК 61508-4, раздел 3.5 «Функции безопасности и полнота безопасности» приводятся соответствующие термины. Смотреть термины, относящиеся к функциям безопасности и полноте безопасности3.5.1 функция безопасности (safety function): Функция, реализуемая Э/Э/ПЭ системой, связанной с безопасностью, или другими мерами по снижению риска, предназначенная для достижения или поддержания безопасного состояния УО по отношению к конкретному опасному событию 3.5.4 полнота безопасности (safety integrity): Вероятность того, что система, связанная с безопасностью, будет удовлетворительно выполнять требуемые функции безопасности при всех оговоренных условиях в течении заданного интервала времени. 3.5.5 полнота безопасности программного обеспечения (software safety integrity): Составляющая полноты безопасности системы, связанной с безопасностью, касающаяся систематических отказов, проявляющихся в опасном режиме и относящихся к программному обеспечению. 3.5.6 полнота безопасности, касающаяся систематических отказов (systematic safety integrity): Составляющая полноты безопасности системы, связанной с безопасностью, касающаяся систематических отказов, проявляющихся в опасном режиме. 3.5.7 полнота безопасности аппаратных средств (hardware safety integrity): Составляющая полноты безопасности системы, связанной с безопасностью, касающаяся случайных отказов аппаратуры, проявляющихся в опасном режиме. 3.5.8 уровень полноты безопасности; УПБ [safety integrity level (SIL)]: Дискретный уровень (принимающий одно из четырех возможных значений), соответствующий диапазону значений полноты безопасности, при котором уровень полноты безопасности, равный 4, является наивысшим уровнем полноты безопасности, а уровень полноты безопасности, равный 1, соответствует наименьшей полноте безопасности. 3.5.9 стойкость к систематическим отказам (systematic capability): Мера уверенности (выраженная в диапазоне ССО 1 — ССО 4) в том. что систематическая полнота безопасности элемента соответствует требованиям заданного значения уровня полноты безопасности (УПБ) для определенной функции безопасности элемента, если этот элемент применен в соответствии с указаниями, определенными для этого элемента в соответствующем руководстве по безопасности. 3.5.16 режим работы (mode of operation): Способ выполнения функции безопасности либо в режиме: — с низкой частотой запросов (low demand mode), в котором функция безопасности выполняется только по запросу и переводит УО в определенное безопасное состояние, а частота запросов не превышает одного в год или — с высокой частотой запросов (high demand mode), в котором функция безопасности выполняется только по запросу и переводит УО в определенное безопасное состояние, а частота запросов превышает один в год, или — непрерывном режиме (continuous mode), в котором функция безопасности поддерживает УО в безопасном состоянии, как и при нормальном функционировании. С точки зрения приводимого определения полноты безопасности (safety integrity), это свойство фактически сводится к безотказному выполнению функций безопасности, т.е. рассматривается, как часть безотказности, которая, в свою очередь, является составляющей классической надежности. На самом деле, из других положений МЭК 61508 следует, что полнота безопасности является более сложным свойством, связанным с такими атрибутами, как ремонтопригодность, готовность, долговечность, информационная безопасность. Терминологические и таксономические аспекты составляющих надежности и безопасности представляют собой смежную область знаний. Возможно, в последующих публикациях есть смысл разобраться в этом подробней. Еще одним центральным понятием в МЭК 61508 является уровень полноты безопасности (Safety Integrity Level, SIL). Значение SIL устанавливает в зависимости от того, насколько влияние управляемого оборудования создает риск для людей и окружающей среды. Исходя из этого, установлен риск отказа и для самой компьютерной системы управления. Например, в начале статьи я уже говорил, что для системы защиты атомного реактора наработка на отказ должна составлять не менее, чем 10 миллионов часов. Это соответствует SIL3. Вообще, принято считать, что SIL4 могут соответствовать лишь наиболее простые устройства. Для программируемых логических контроллеров (ПЛК), используемых в АСУ ТП, достижимым является SIL3. Из структуры определений также следует, что полнота безопасности делится на две составляющие: полнота безопасности, касающаяся систематических отказов (сюда же попадает полнота безопасности программного обеспечения) и полнота безопасности аппаратных средств. Первая составляющая требует применять меры защиты от систематических отказов, вызванных ошибками проектирования. Для этого необходимо совершенствовать процессы проектирования и разработки, тестирования, управления конфигурацией, проектного менеджмента и т.п. Это отдаленно напоминает уровни Capability Maturity Model Integration (CMMI), но напрямую к ним не трассируется. Для каждого из значений SIL определен набор методов защиты от систематических отказов, причем их количество и «строгость» возрастает с повышением SIL. Полнота безопасности аппаратных средств связана с защитой от случайных отказов и обеспечивается применением компонентов с высоким уровнем безотказности и самодиагностики, и, конечно же, резервированием. Здесь есть интересный фокус, который применяют многие разработчики ПЛК. Можно достичь уровня SIL2 при одноканальной конфигурации ПЛК. Тогда резервированная конфигурация даст SIL3. При этом процессы разработки (systematic capability), должны соответствовать SIL3. Теперь, по аналогии с предыдущим разделом, попробуем применить структуру окружения (опасность, ущерб, риски, контмеры, управляемое оборудование) для компьютерной системы управления (КСУ). Здесь речь идет об опасностях для выполнения функций безопасности КСУ, поскольку их невыполнение связано с риском. Для снижения этого риска применяются различные меры по обеспечению полноты безопасности. Как мы уже знаем, эти меры направлены на защиту от случайных и систематических отказов. Попробуем теперь совместить полученную схему со схемой из предыдущего размера. Получается такая вот двухуровневая структура, демонстрирующая терминологическую среду функциональной безопасности «на пальцах». Терминология МЭК 61508: еще несколько полезных терминов Итак, согласно МЭК 61508-4, у нас еще осталось шесть из восьми разделов по терминологии. Следующий терминологический раздел: 3.2 «Оборудование и устройства». Здесь приводятся достаточно тривиальные определения, относящиеся к типам программного и аппаратного обеспечения, используемых в системах, важных для безопасности. Приведу лишь определение для упоминаемого выше управляемого оборудования. Смотреть термины, относящиеся к оборудованию и устрйствам3.2.1 управляемое оборудование; УО [equipment under control (EUС)]: Оборудование, машины, аппараты или установки, используемые для производства, обработки, транспортирования, в медицине или в других процессах. В разделе 3.3 «Системы: общие аспекты» также содержать понятные технарям определения. В разделе 3.4 «Системы: аспекты, связанные с безопасностью» содержится важное определение, отвечающее на вопрос: «а что именно подразумевается под системой, связанной с безопасностью?» Смотреть термины, относящиеся к аспектам, связанные с безопасностью3.4.1 система, связанная с безопасностью (safety-related system): Система, которая: — реализует необходимые функции безопасности, требующиеся для достижения и поддержки безопасного состояния УО и — предназначена для достижения своими средствами или в сочетании с другими Э/Э/ПЭ системами, связанными с безопасностью, и другими средствами снижения риска необходимой полноты безопасности для требуемых функций безопасности. Раздел 3.6 «Сбой, отказ и ошибка» дает определение этим досадным происшествиям. Кроме того, в данном разделе даются определения уже известным нам случайным и систематическим отказам, а также опасным и безопасным отказам. Далее следуют определение показателей безопасности, которые есть смысл рассмотреть в отдельной публикации. Смотреть термины, относящиеся к сбоям, отказам и ошибкам3.6.1 сбой (fault): Ненормальный режим, который может вызвать снижение или потерю способности функционального блока выполнять требуемую функцию. 3.6.4 отказ (failure): Прекращение способности функционального блока выполнять необходимую функцию либо функционирование этого блока любым способом, отличным от требуемого. 3.6.5 случайный отказ аппаратуры (random hardware failure): Отказ, возникающий в случайный момент времени, который является результатом одного или нескольких возможных механизмов ухудшения характеристик аппаратных средств. 3.6.6 систематический отказ (systematic failure): Отказ, связанный детерминированным образом с некоторой причиной, который может быть исключен только путем модификации проекта, либо производственного процесса, операций, документации, либо других факторов. 3.6.7 опасный отказ (dangerous failure): Отказ элемента и/или подсистем и/или системы, которые принимают участие в реализации функций безопасности, в результате чего: а) функция безопасности не выполняется, когда это требуется (для режимов с низкой или высокой частотой запросов) либо отказывает (для непрерывного режима), что приводит к переводу УО в опасное или потенциально опасное состояние; б) снижается вероятность того, что функция безопасности при необходимости будет корректно выполнена. 3.6.8 безопасный отказ (safe failure): Отказ элемента и/или подсистем и/или системы, которые принимают участие в реализации функций безопасности, в результате чего: а) приводят к выполнению функции безопасности по переводу УО (или его части) в безопасное состояние либо поддерживают безопасное состояние; б) увеличивается вероятность выполнения функции безопасности по переводу УО (или его части) в безопасное состояние либо поддержке безопасного состояния. 3.6.10 отказ с общей причиной (common cause failure): Отказ, который является результатов одного или нескольких событий, вызвавших одновременные отказы двух или более отдельных каналов в многоканальной системе, ведущих к отказу системы. 3.6.11 ошибка (error): Расхождение между вычисленным, наблюдаемым или измеренным значением или условием и правильным, заданным или теоретически верным значением или условием. Определения раздела 3.7 «Процессы жизненного цикла», как и сам жизненный цикл, являются темой отдельной публикации. Смотреть термины, относящиеся к процессам жизненного цикла3.7.1 жизненный цикл систем безопасности (safety lifecycle): Необходимые процессы, относящиеся к реализации систем, связанных с безопасностью, проходящие в течение периода времени, начиная со стадии разработки концепции проекта и заканчивая стадией, когда все Э/Э/ПЭ системы, связанные с безопасностью, и другие средства снижения риска уже не используются. В разделе 3.8 «Подтверждение мер по обеспечению безопасности» интерес представляют определения, даваемые для верификации и валидации. Сразу скажу, что обычно в жизненном цикле валидация и верификация (verification and validation, V&V) рассматривается как единый процесс. Непосредственно под валидацией понимаются испытания полностью интегрированной системы с физической симуляцией входных и выходных сигналов, а под верификацией – все остальные обзоры, анализы и тесты. Но из определений МЭК 61508 этого вовсе не следует. Смотреть термины, относящиеся к подтверждению мер по обеспечению безопасности3.8.1 верификация (verification): Подтверждение выполнения требований путем исследования и сбора объективных свидетельств. 3.8.2 подтверждение соответствия (validation): Подтверждение, путем испытаний и представления объективных свидетельств, выполнения конкретных требований к предусмотренному конкретному использованию. Выводы МЭК 61508 представляет собой достаточно пространный, сложный, порой запутанный и противоречивый стандарт, включающий в себя 7 частей. «Распутать» его можно, только применяя на практике. В основе МЭК 61508 лежит риск-ориентированный подход. Уровни риска для компьютерных систем управления назначаются в зависимости от влияния управляемого техногенного объекта на окружающую среду, а также на здоровье и жизнь людей. Для этого в МЭК 61508 введено понятие уровня полноты безопасности (Safety Integrity Level, SIL), которые установлены по возрастающей, от 1 до 4. Для соответствия тому или иному SIL необходимо реализовать меры по защите от случайных отказов аппаратных средств, а также от систематических отказов, вызванных ошибками проектирования. Поэтому, для каждого из SIL заданы требования к продукту в виде значений показателей безопасности и требования к «строгости» реализации процессов жизненного цикла. Терминология по функциональной безопасности изложена в четвертой части МЭК 61508 (МЭК 61508 4). Разобравшись с терминологией, в следующей части публикации мы сможем рассмотреть структуру и взаимосвязи для остальных частей МЭК 61508. Трактовать законы и стандарты можно по-разному, но, в любом случае, трактующий обязан осмысливать их содержание, чтобы своевременно отличить добро от зла. Кроме того, в планируемом цикле статей будут рассмотрены следующие основные аспекты функциональной безопасности: — Теория надежности и функциональная безопасность: основные термины и показатели; — Методы обеспечения функциональной безопасности компьютерных систем управления; — Жизненный цикл безопасности для системы управления; — Тестирование систем управления, важных для безопасности. Напомню, что в первой вводной части публикации: — обоснована важность оценивания и обеспечения функциональной безопасности для компьютерных систем управления; — рассмотрены архитектуры систем, для которых необходимо оценивать и обеспечивать функциональную безопасность; к таким системам относятся АСУ ТП (Industrial Control Systems) на базе программируемых логических контроллеров (ПЛК), встроенные системы (Embedded Systems) и уровень устройств (Device Layer) для интернета вещей; — кратко представлено множество стандартов, относящихся к функциональной безопасности в различных сферах применения.

Метки:  

На каких основаниях Alphabet претендует на звание самой дорогой ИТ-компании

Воскресенье, 28 Августа 2016 г. 02:21 + в цитатник
Alphabet возник чуть более года назад, в результате реструктуризации Google. Все акции Google были полностью конвертированы в акции Alphabet без каких-либо изменений их параметров. Холдинг Alphabet стал новым игроком на рынке, в состав которого на правах дочек вошли сама Google и все ее предыдущие проекты – в частности Calico, Fiber, Google Ventures, Google Capital, Google X, Life Sciences и Nest. Это, по мнению представителей компании, должно было обеспечить их большую самостоятельность и более четкую структуру руководства. В ведении Google останется поисковая система, а также карты, рекламный бизнес, сервис Google Play Store, видеохостинг YouTube и разработка операционной системы Android, а также Chrome, Google Apps и социальная сеть Google+. Пока большинство наиболее прибыльных подразделений всё ещё принадлежат Google. Далеко не все проекты, которыми теперь управляет Alphabet, показывают удовлетворительные результаты. Генеральным директором Alphabet был назначен уже бывший руководитель Google — Ларри Пейдж. Сооснователь поискового гиганта Сергей Брин занял должность президента холдинга. «Alphabet — странный холдинг. Лишь одна его часть приносит ему значительные доходы — это Google. От генерального директора холдинга практически ничего не слышно, но это не значит, что его вовсе не существует. Все руководители подразделений отчитываются перед ним о своей деятельности, он принимает основные решения. И хотя пресса его практически не видит, он до сих пор участвует в еженедельных совещаниях TGIF, на которых может присутствовать любой сотрудник корпорации — лично или по видеосвязи», рассуждает известный писатель, журналист Стивен Леви. По словам Леви, пока представителям ИТ-сообщества так до сих пор и не ясно, как сейчас устроена работа Alphabet: «Похоже, что холдинг до сих пор переживает потрясение — и недавний уход нескольких топ-менеджеров только усугубил ситуацию. Ларри Пейдж остаётся главой Alphabet, но не отвечает ни на какие вопросы. Это очень плохо, потому что проведенная реструктуризация до сих пор их вызывает». «После реорганизации в воздухе повис вопрос: как это всё будет работать. Многие, и я в том числе, не были уверены, что главы отдельных подразделений смогут поддерживать глобальное видение Ларри Пейджа и Сергея Брина, которое те вырабатывали в течение многих лет», — отмечает Леви. Результаты работы за год Стоимость акций за год значительно выросла: капитализация Alphabet в феврале 2016 года достигла $550 миллиардов. Но пока почти вся прибыль компании приходится на проекты Google. По одной из версий, Alphabet также создавался, чтобы «удержать» менеджеров высшего звена. Однако в начале июня 2016 года свой пост покинул руководитель подразделения Nest Тони Фаделл. В середине августа со своей должности ушёл глава Google Ventures Билл Марис. Более того, сотрудники отмечают внутреннюю напряженность в компании. Так, руководитель научного подразделения Verily, уволил нескольких своих прямых подчиненных. Проблемы возникли и в Google X — в процессе подготовки к выделению проекта самоуправляемого автомобиля в отдельную компанию Пейдж назначил подразделению нового генерального директора, ранее работавшего в автомобильной промышленности. Спустя несколько месяцев команду покинули несколько сильнейших инженеров, включая технического директора направления Криса Урмсона. Как полагает издание The New York Times, одной из причин конфликта между Урмсоном и Пейджем стала кандидатура нового главы подразделения. Основной доход Alphabet приносят технологии поиска и рекламная платформа. Леви называет эту компанию «машиной по производству денег», которая делает смелые ставки — и в ближайшее время, полагает Леви, многие из этих ставок могут окупиться. «Компания располагает мощными технологиями в области машинного обучения, петабайтами различных данных и километрами проложенного оптоволокна», приводит пример Леви. В последнем квартале Alphabet отчитался о выручке в размере $21 миллиарда. Google Fiber А пока проект, на который Alphabet возлагал большие надежды, не оправдал их. По плану, провайдер Google Fiber должен был к 2016 году набрать 5 миллионов подписчиков. В 2014 году у Google Fiber было 200 тысяч подписчиков. В связи с этим гендиректор Alphabet Ларри Пейдж принял решение сократить команду Google Fiber в два раза – до 500 человек. Провайдер Google Fiber приступил к реализации проекта в 2010 году. Компания потратила сотни миллионов долларов на прокладку волоконно-оптических линий связи в ряде городов, чтобы обеспечить скорость подключения к интернету примерно в 30 раз выше среднего показателя по США. Однако после шести лет развития сети было решено вместо кабелей использовать на «последней миле» беспроводные системы, писали «Ведомости» со ссылкой на The Wall Street Journal. Это коснется ряда подключаемых сейчас к проекту городов, в том числе Лос-Анджелеса, Далласа и Чикаго. В Сан-Хосе (Калифорния) и Портленде (Орегон) проект приостановлен. В Google Fiber также сообщили, что запуск их сервиса в Пало-Альто и окрестных городах откладывается по меньшей мере на полгода. Более тысячи городов подали заявку на подключение к Google Fiber, а в ноябре 2012 года этот сервис начал работать в Канзас-Сити. Гендиректор Google Эрик Шмидт заявлял, что Google Fiber – «не просто эксперимент, а реальный бизнес» и что компания решает, куда должна быть направлена его дальнейшая экспансия. За шесть лет сервис успел охватить лишь шесть крупных агломераций. Финансовые показатели проекта Fiber не разглашаются – они включаются в показатели группы подразделений, не относящихся к поиску и объединенных под названием «other bets». В данную группу помимо Fiber входят такие подразделения, как Nest и Verily. Совокупная выручка этих подразделений за последний квартал составила $185 миллионов, а операционные убытки достигли $859 миллионов. Квартальные капиталовложения по всей этой группе составили $280 миллионов, основная их часть пришлась на Fiber. Alphabet рассчитывает на то, что Fiber будет окупаться за счёт абонентской платы и, косвенно, роста бизнеса онлайн-рекламы. Провайдер продаёт доступ к интернету за $70 в месяц, ТВ-сервис — ещё за $60. В марте 2016 года Fiber обслуживал около 53 тысяч ТВ-зрителей — столько же, сколько и в конце 2015 года, подсчитали аналитики MoffettNathanson. Аналитики полагают, что подключение одного дома к Fiber обходится Alphabet более чем в $500, при этом не все квартиры в домах становятся абонентами. Проблема с Google Fiber не является единственной для Alphabet. В прошлом году компания прекратила продажу первой версии носимого интеллектуального устройства Glass, а недавно была расформирована команда, занимавшаяся разработкой роботов. Alphabet и «клуб четырех запятых» Тем не менее, у Alphabet есть серьезные амбиции, которые сводятся в конечном итоге к росту рыночной капитализации до $1 триллиона. Для этого у компании должны быть перспективы на растущем рынке. Кроме того, она должна доминировать в своем сегменте или быть одной из нескольких доминирующих компаний. Есть три компании, которые соответствуют условиям и находятся близко к оценке в триллион долларов: Alphabet, Amazon и Apple. Alphabet доминирует на рынке интернет-рекламы. Позиции компании и перспективы рынка способствуют росту стоимости акций Alphabet. По прогнозам аналитиков, прибыль компании будет расти до 2018 года. К этому времени капитализация Alphabet может составить $950 миллиардов. Если верить прогнозам, то компания имеет все шансы стать членом «клуба четырех запятых». По оценкам аналитиков, объем продаж Amazon к 2018 году превысит $28 триллионов, и лишь 5,5 процентов обеспечит электронная коммерция. Ставка сделана на AWS — облачный бизнес Amazon, у которого есть большой потенциал. Корпоративные расходы на инфраструктуру растут, растет рынок и будет расти рыночная капитализация Amazon. Аналитики считают, что компания может достичь оценки в триллион долларов в ближайшее десятилетие. Пока самой дорогой из этой тройки является компания Apple. Дела у Apple идут хорошо, но есть проблема, которая мешает Apple достигнуть заветного триллиона долларов. Корпорация Apple отчиталась о падении выручки второй квартал подряд. Главная причина — падение продаж iPhone, в основном на китайском рынке. Выручка за третий финансовый квартал упала на 14,6% по сравнению с аналогичным периодом 2015 года. Если в третьем квартале прошлого года этот показатель равнялся $49,6 млрд, то в 2016-м он опустился до $42,4. Пока рост компании замедлился. Крупные обновления iPhone будут выходить реже, автомобиль от Apple в ближайшее время ждать не приходится.

Метки:  

Аппроксимация числа Пи с помощью множества Мандельброта

Воскресенье, 07 Августа 2016 г. 12:26 + в цитатник
Я всегда говорил своему другу, что математика со своими изящными абстракциями обладают той магической силой, потенциал которой до сих пор полностью не раскрыт. Сегодня я хочу поговорить о том, как можно приблизить число Пи с помощью множества Мандельброта. Пару слов о множестве На самом деле на Хабре куча статей, описывающие множество Мандельброта (далее, множество М), рассматривающие его свойства, историю и удивительную красоту, подкрепляя всё это красочными картинками. Мне бы не хотелось останавливаться на его определении и прочих деталях, а сразу перейти к делу. Однако в силу того, что оно является центральным субъектом данной статьи, я все же освежу вашу память. Множество М — это множество всех комплексных чисел с, для которых функция при ее итерации с ограничена. Настолько просто. На практике мы применяем следующую теорему: если функция (вышеприведенная) в ходе итерации превосходит значение 2, то она 100% не ограничена. Поэтому, определить множество можно так: Я не буду затрагивать тему визуализации, туда мы сегодня копать не будем. Число Пи? Действительно, каким-таким образом? Все то, что покрыто черным на картинке принадлежит множеству М. Возьмем "координату соприкосновения двух частей" множества c = -0.75 + ix (где x ? ?). Проверим её принадлежность ко множеству М: начнем итерировать функцию n-раз от нуля и проверять, превосходит ли полученное значение 2. Если да, то функция разошлась, и значение с не принадлежит множеству при данном n. Иначе — принадлежит. x c n (кол-во итераций до расхода функции) 0.1 -0.75 + 0.1i 33 0.01 -0.75 + 0.01i 315 0.001 -0.75 + 0.001i 3143 0.0001 -0.75 + 0.0001i 31417 0.00001 -0.75 + 0.00001i 314160 Именно. Если поставить запятую на нужном месте, цифры напоминают число Пи. Наверное, совпадение Не будем заморачиваться с комплексной частью и возьмем число c = 0.25. Оно принадлежит множеству при бесконечно большом количестве итераций. Поэтому, будем "приближаться" к этой точке справа: возьмем c = 0.26, проверим его; c = 0.2501, проверим его, и т. д. c n (кол-во итераций до расхода функции) 0.26 30 0.2501 312 0.25001 991 0.250001 3140 0.2500001 9933 0.25000001 31414 Последовательность колеблется между двумя значениями, однако эхо числа Пи (поставив запятую в нужное место) никуда не исчезло. Немного истории Само множество М, названное в честь математика Бенуа Мандельброта — совсем недавное открытие. Бенуа даже выступал на TEDx, говоря в том числе и о нем. В 1991 Дейв Болл изучал, действительно ли "соприкосновение двух частей множества" М около c = -0.75 "бесконечно тонко". В ходе своего исследования он и обнаружил то, о чем мы сейчас говорим. И все-таки, наверное, совпадение Попытаемся понять, что происходит: действительно ли мы получаем число Пи или это какое-то иное трансцендентное число. Все это будем делать вокруг точки c = 0.25 (просто в силу отсутствия у него комплексной части — так легче). Рассмотрим рекурсивную функцию . При ее итерации от нуля заметим, что она очень медленно стремится к точке x = 0.5. Наглядно Чтобы не дать ей "застрять" на этом значении, мы подвинем данную функцию на ? единиц вверх (? бесконечно мало, не равно нулю). Тогда она примет вид . Данная функция медленно стремится к точке x = 0.5, а после того, как проходит её, быстро убегает в бесконечность. Будем копать дальше. Пусть x = y + 0.5. Наша задача — найти ноль. Делая замену в исходной функции, получим: Взяв в качестве ? любое малое значение, проитерируем функцию от нуля: y 0.001 ( = ?) 0.002001 0.0030050040010000004 0.004014034050046026 0.005030146519400955 0.006055448893407596 0.007092117354708267 0.00814241548328122 0.009208714413183598 0.010293514834327173 Видим, что она достаточно плавно и медленно возрастает возле нуля. Исходя из этого, мы в праве предположить, что разность (n+1)-го и n-го значений функции близка к её производной: . Учитывая это, наша исходная функция примет вид: , что является простейшим дифференциальным уравнением первого порядка. Решая его (например, методом разделения переменных), получим: Вспоминаем нашу цель — поиск нуля. Данное выражение равно нулю только в двух случаях: либо квадратный корень из ? равен нулю — невозможно по определению, либо тангенс равен нулю. Пренебрегая константой C: . Это подтверждает то, что мы сегодня увидели: ? nv? 0.01 3.0 0.0001 3.12 0.000001 3.140 0.00000001 3.1414 Видно, что множитель v? ставит ту самую запятую в нужное место. Заключение Построение числа Пи данным методом является, наверное, самым неэффективным способом: нужно проделать 314160 итераций для того, чтобы получить 3,14160. Кроме того, метод не обладает высокой точностью в силу больших погрешностей вычислений. Однако нам удалось соединить две, казалось бы, несоединимые точки: фрактал и отношение длины окружности к длине её диаметра.

Метки:  

[Перевод] Обзор физики в играх Sonic. Части 7 и 8: пружины и штуковины, суперскорости

Воскресенье, 31 Июля 2016 г. 16:36 + в цитатник
Продолжение цикла статей о физике в играх про Соника. В этом посте рассматриваются отталкивания персонажей от различных игровых объектов и их суперспособности. Ссылки на другие части серии: Часть 1: твердые тайлы Часть 2: бег Части 3 и 4: прыжки и вращение Части 5 и 6: потеря колец и нахождение под водой Часть 7: пружины и штуковины 1 Пружинные площадки 2 Воздушные шарики 3 Бамперы 4 Пушки 5 Крышки с пружинами 6 Вертушки 7 Лифты в небе 8 Грибы 9 Разрушение стен 10 Разрушаемые блоки и камни Пружинные площадки Красные пружинные площадки придают Сонику скорость 16, а жёлтые — скорость 10. В зависимости от направления площадки (вверх или вниз), значение отрицательное или положительное, и соответственно скорости по оси Y придается это значение. Если пружинная площадка направлена влево или вправо, значение скорости отрицательное или положительное, соответственно скорость по оси X приравнивается к этому значению. Вертикальные площадки не влияют на скорость X, как и горизонтальные площадки не влияют на скорость Y. Диагональные пружинные площадки В Sonic the Hedgehog (16-bit) нет диагональных пружинных площадок. Однако они есть в Sonic 2 (16-bit), 3, Knuckles и CD. В Sonic 2, 3 и Knuckles они работают одинаково, но в Sonic CD принцип отличается. в Sonic 2, 3 и Knuckles диагональная пружина устанавливает скоростям X и Y значение пружинной площадки с соответствующим знаком. Поэтому пружина, направленная вверх-вправо придает скорость Y, равную -16 и скорость X, равную 16. Проблема этого метода в том, что технически Соник отталкивается диагонально быстрее, чем горизонтально или вертикально. Это потому, что разработчики не позаботились учесть косинусы и синусы. В Sonic CD они исправились. Удобно, что абсолютные значения синуса и косинуса угла в 45 градусов одинаковы, поэтому требуется только одно значение. Скорость становится равной 11.3125 для красных пружин и 7.0703125 для жёлтых. Блокировка горизонтального управления Когда Соник отскакивает от горизонтальной пружины (красной или жёлтой), он не может тормозить или иным способом влиять на свою скорость X в течение 16 циклов. Движок достигает этого, устанавливая ту же блокировку горизонтального управления, что и при скатывании с крутых склонов (в S3 и Knuckles байты $32-33 являются таблицей состояний объекта игрока). Зачем блокировать горизонтальное управление? При столкновении с пружиной игрок скорее всего нажимает крестовину в направлении пружины, и это может привести к отталкиванию Соника в анимации торможения. Временное игнорирование ввода — это быстрое и элегантное решение. Анимация В случае пружинной площадки, направленной вверх, когда Соник теряет всю скорость, направленную вверх, он переходит в анимацию ходьбы. Кадры этой анимации сменяются каждые 8 циклов. В случае любой из диагональных пружинных площадок Соник вообще не переходит анимации ходьбы в воздухе. Он сохраняет анимацию «штопора» (трёхмерного вращения), кадры которой сменяются раз в 5,5 цикла. Воздушные шарики При столкновении Соника с воздушными шариками на уровнях Carnival Night Zone его скорость Y устанавливается равной -7, вне зависимости от угла столкновения. Скорость X не изменяется. Бамперы Бамперы в Spring Yard Zone придают Сонику скорость X, равную 7*cos(p), и скорость Y 7*-sin(p), где p — это угол между центрами бампера и Соника. Скорость устанавливается вне зависимости скорости Соника до столкновения с бампером. Пушки Пушки в Carnival Night Zone придают Сонику горизонтальную скорость 16*cos(p), и вертикальную скорость 16*-sin(p), где p — угол наклона пушки. Крышки с пружинами Красные крышки с пружинами, которые закрывают трубы в Chemical Plant Zone, работают как пружинные площадки, но немного сильнее, чем жёлтые площадки. При столкновении они придают Сонику скорость Y, равную -10.5. Вертушки Чёрные вертушки, которые разгоняют ежа вперёд в Chemical Plant Zone устанавливают скорость X равной 16. Однако они не замедляют его, если он уже движется быстрее. Лифты в небе Лифты в небе на уровнях Hill Top Zone перемещаются со скоростью X, равной 2, и скоростью Y, равной 1. Грибы Грибы в Mushroom Hill Zone работают как пружинные площадки, однако каждый последующий отскок становится выше предыдущего (до трёх отскоков). Первый отскок придаёт скорость Y -6.5, второй -7.5, а третий -8.5. Разрушение стен В Sonic 1, 2, 3 и Knuckles для пробивания разрушаемых стен при вращении абсолютная скорость X персонажа должна превышать 4.5 (за исключением персонажа Knuckles, который крошит стены при столкновении, при этом ему не обязательно вращаться). Столкновения с такими стенами не влияют на скорость X. Однако когда Knuckles разрушает стены в Sonic 3 и Knuckles, несмотря на то, что его скорость X не изменяется, он не двигается в кадре, в котором ударяет стену. То же самое справедливо для пробивания Соником стены при вращении в Sonic 3 и Knuckles. В Sonic CD, ограничение по скорости X убрано. Соник может пробивать разрушаемые стены, просто прыгая рядом с ними или вращаясь на любой скорости. Разрушаемые блоки и камни Когда Соник запрыгивает на разрушаемые объекты, такие как камни в Hill Top Zone, блоки в Marble Zone или крышки труб в Chemical Plant Zone, он отскакивает от них со скоростью Y, равной -3. Скорость X не изменяется. Часть 8: суперскорости 1 Супербыстрые ботинки 2 Супер/Гиперсоник 3 Супер Тейлс, Супер/Гипернаклз 4 Отбор колец 5 Примечания Супербыстрые ботинки Примечание переводчика: супербыстрые ботинки (Super Fast Shoes) — это бонус увеличения скорости, действующий 20 секунд и повышающий ускорение и максимальную скорость Соника. Выбивается из вот таких мониторов: Переменная Значение Ускорение 0.09375 Торможение 0.5 (не изменяется) Трение 0.09375 Максимальная скорость 12 Ускорение в воздухе 0.1875 Трение при вращении 0.046875 Торможение при вращении 0.125 (не изменяется) Примечание: если Соник падает в воду, все эффекты супербыстрых ботинок (Super Fast Shoes) обнуляются. «Подводные» переменные полностью их заменяют. Если вы выпрыгнете из воды, эффект супербыстрых ботинок не вернётся. Похоже, что это относится ко всем 5 играм. В Sonic 3 и Knuckles темп музыкальной композиции увеличивается в 1.25 раза. Супер/Гиперсоник Примечание переводчика: Суперсоник (Super Sonic) — это суперформа персонажа Sonic the Hedgehog. Такая форма Соника впервые была применена в игре Sonic the Hedgehog 2 и в различном объёме реализовалась затем в каждой основной игре про Соника. Превратиться в Суперсоника можно, собрав все семь Изумрудов Хаоса, найдя не менее 50 колец и потеряв всю защиту. Сделав двойной прыжок, Соник становится жёлтым Суперсоником, это более быстрая и почти неуязвимая форма Соника. Однако на поддержание этой формы тратятся кольца (см. ниже). В играх Sonic 3 и Knuckles, после сбора всех Изумрудов Хаоса на специальных уровнях можно собрать семь Суперизумрудов, после чего превратиться в Гиперформу персонажа. Она также тратит собранные кольца. В этом режиме персонаж может делать направленные двойные прыжки, уничтожать всех противников на экране и не способен утонуть, в отличие от суперформы. Переменные относятся к Суперсонику в Sonic 2 и к Супер- или Гиперсонику в Sonic 3 и Knuckles, за исключением отмеченной переменной. Переменная Значение Значение (под водой) Ускорение 0.1875 0.09375 Торможение 1 0.5 Трение 0.046875 (не изменяется) 0.046875 (не изменяется) Максимальная скорость 10 5 Ускорение в воздухе 0.375 0.1875 Начальная скорость прыжка 8 3.5 (не изменяется) Скорость прыжка при отпускании кнопки 4 (не изменяется) 2 (не изменяется) Трение при вращении 0.09375 (0.0234375 в Sonic 3 и Knuckles) 0.046875 (0.0234375 в Sonic 3 и Knuckles) Торможение при вращении 0.125 (не изменяется) 0.125 (не изменяется) Способность Hyper Blast (только у Гиперсоника) Когда игрок нажимает второй раз кнопку прыжка в воздухе, скорость Соника по оси X приравнивается 8, если он смотрит вправо, и к -8, если влево, а скорость по оси Y обнуляется. Если игрок удерживает «вверх» на крестовине при нажатии на кнопку, то скорость Соника по оси Y приравнивается к -8, а по оси X обнуляется. Супертейлз, Супер/Гипернаклз Переменная Значение Значение (под водой) Ускорение 0.09375 0.046875 Торможение 0.75 0.375 Трение 0.046875 (не изменяется) 0.046875 (не изменяется) Максимальная скорость 8 4 Ускорение в воздухе 0.1875 0.09375 Начальная скорость прыжка (не изменяется) (не изменяется) Скорость прыжка при отпускании кнопки (не изменяется) (не изменяется) Трение при вращении 0.0234375 0.0234375 Торможение при вращении 0.125 (не изменяется) 0.125 (не изменяется) Скорость взбирания (только для Наклза) 2 2 Начальная скорость скольжения (только для Наклза) 4 (не изменяется) 4 (не изменяется) Ускорение скольжения (только для Наклза) 0.046875 0.046875 Стенотрясение (Wall Quake) (только для Гипернаклза) Чтобы Наклз смог сотрясти экран и уничтожить всех врагов при контакте со стеной, он должен скользить со скоростью 4.5 пикселей за цикл или выше. Отбор колец Находясь в режиме Супер/Гипер, персонаж теряет по одному кольцу каждые 60 циклов, или раз в 1 секунду. Примечания Если Супер/Гиперперсонаж получает супербыстрые ботинки, разбив монитор, переменные супербыстрых ботинок заменяют переменные режима Супер/Гипер, на самом деле замедляя персонаж (однако максимальная скорость остаётся немного выше). Это может быть нежелательно в вашем собственном движке. Когда Супер/Гиперперсонаж падает в воду, он использует указанные выше переменные. Однако, если они становятся Супер/Гипер уже под водой, переменные режима Супер/Гипер становятся такими, как будто он не находится под водой. Это баг, и его следует избегать в своём движке. P.S. снова для внимательных и любопытных читателей. Здесь в первое зашифрованное слово заканчивается. Слова не относятся к вселенной Соника, однако для расшифровки требуется её знание (впрочем, гуглением вполне можно обойтись).

Метки:  

[Из песочницы] Lync SDK 2013. Опыт разработки собственного мессенджера на основе Lync (Skype for Business)

Суббота, 23 Июля 2016 г. 16:44 + в цитатник
О чем? В этой статье я расскажу о том, что предлагает нам компания Microsoft в своем Lync SDK для создания «красивых» интерфейсов и новых возможностей для Lync-клиента. Так же подробно остановлюсь на взаимодействии с Lync клиентом в UI Suppression mode, с которым нам очень плотно пришлось иметь дело в процессе разработки собственного корпоративного мессенджера на базе Skype for Business. И, самое главное, постараюсь подробно описать, с какими ограничениями нам пришлось столкнуться. С чего всё началось? Весной 2014-го года в нашей компании родилась идея создать корпоративный мессенджер на основе Lync (теперь уже Skype for Business). Вернее, сначала речь о мессенджере не шла, мы просто дорабатывали Lync под себя для более эффективной работы. По сути, мы использовали Lync-клиент в «штатном режиме», а наше приложение было просто дополнением для него, которое управляло контактами. Оно позволяло удобно разместить свои избранные контакты по всей ширине экрана, что было удобно для работы на десктопах, предполагало быстрый доступ к контактам и упорядочивало их по группам. Приложение назвали EasyLy (от «Easy Lync») и распространили среди «своих». Рисунок 1. Первая версия программы Постепенно в приложение добавлялись новые функции. Например, переписываться можно было как из Lync, так и из EasyLy, причем в последнем сохранялась история переписки. И в один эпохальный день было принято решение отказаться от интерфейса Lync и реализовать весь его функционал самим, чтобы след Lync остался только в диспетчере задач. То есть мы решили сделать свой собственный, более удобный мессенджер для десктопов на базе Lync. И вроде бы всё начиналось хорошо. Что мы хотели получить в итоге? В начале одно из основных неудобств Lync для нас состояло в отсутствии более или менее адекватного механизма сохранения и просмотра истории бесед. Lync, конечно, сохраняет (по истечении определённого времени) свою историю в Outlook, но этим крайне неудобно пользоваться. Помимо этого, история может вообще не сохраниться, если, например, закрыть окно с беседой до того, как произойдёт сохранение. Что касается usability, мы проповедовали концепцию «One click» для экономии времени пользователя и повышения эффективности его работы и пытались создать приложение максимально простое, понятное и удобное для офисного работника. Целевая группа, которую мы выделили для себя, – это не модные «мобильные сотрудники», бегающие со смартфоном по «полям», а настоящие офисные трудяги, работающие по 8 часов за большим монитором, где всё должно быть эргономично. Кроме появившейся ранее вкладки «Избранное», появились идеи создать вкладки «Группы», «Диалоги», а также журнал звонков с комментариями, окно проведения онлайн-собраний, возможность отправить сообщение офлайн-абоненту, интеграция с календарями, OneDrive и много других интересных функций. Мы планировали, не отбрасывая имеющийся функционал Lync (а затем и Skype for Business), создать дополнительную ценность для пользователя за счет UI под десктопы, быстрого доступа к имеющимся функциям и создания нового корпоративного функционала. Рисунок 2. Так выглядит EasyLy сейчас Разработка Первое, что было сделано – вкладка “Favorites”, где пользователь мог расположить все свои контакты, да еще и отсортировать их по группам. Мы приступили к работе и реализовали данную идею без особых проблем с помощью Lync SDK 2013. Все контакты мы сделали в виде карточек, на которых можно посмотреть список собраний и встреч данного пользователя, а также позвонить ему (аудио- и видеозвонки) или написать сообщение. При клике на эти кнопки вызывалось стандартное окно беседы Lync. Рисунок 3. Иконка контакта при наведении Это было достаточно просто. Воодушевленные успехом мы начали двигаться дальше и полностью отказались от Lync UI (перевели Lync-клиент в UI Suppression mode). Это дало нам возможность отказаться от стандартных окон бесед, звонков (да и вообще всех окон) и реализовать весь базовый функционал приложения самим. Не буду рассказывать про авторизацию пользователя, описание можно найти здесь. Расскажу про нашу вторую и самую главную вкладку «Dialogs», которую мы реализовывали почти год. Рисунок 4. Вкладка диалогов с включенным режимом мультичата Начали мы, как полагается, с текстовых бесед. Все шло хорошо, но не очень быстро, потому что, помимо простой отправки и приёма сообщений, нужно было реализовать typing, смайлы, поддержку rtf-форматирования и т.д. Реализацию Lync IM Conversation можно взять отсюда. Сохранение сообщений и записей о звонках мы реализовали на базе SQLite, которой пользователь может гибко управлять. Также мы внедрили поддержку одновременно нескольких открытых чатов (до 3-х) в одном окне, для еще более скоростного общения с сотрудниками. Потом мы добавили поддержку аудио-, видеозвонков, шаринга экрана и приложений. Добавление в беседу поддержки Application Sharing пришлось реализовывать достаточно долго. В обычном режиме Lync показ экрана происходит в самой беседе, а в UI Suppression mode нужно все возможности шаринга реализовывать самому с помощью «линковского» контрола ApplicationSharingView, служащего для отображения расшариваемого ресурса, которому для работы нужен handle родительского окна. Вот краткий список того, что мы сделали для поддержки шаринга: • Создали окно для просмотра шаринга, реализовали перерисовывание картинки при изменении размеров родительского окна. • Сделали вывод списка ресурсов (экран, приложения), которые можно шарить. • Сделали обводку рамками расшариваемых ресурсов. • Реализовали дополнительные возможности: например, передачу управления участнику конференции (чтобы он мог водить мышкой и кликать по экрану «шарящего» пользователя). Шаринг в Lync (в UI Suppression mode) – капризная вещь: любит часто отваливаться по неизвестным причинам, а при переходе на Skype for Business 2016 начал делать это почти постоянно. При просмотре шаринга часто появляется черный экран, и с этим ничего не сделать, так как воспроизведением занимается контрол ApplicationSharingView, про который написано выше. Также на удачный запуск шаринга сильно влияет скорость соединения. Далее мы перешли к созданию последней вкладки – «Groups», которая бы грузила списки групп из Lync и предоставляла пользователю возможность их полностью редактировать и сортировать в нужном порядке. Данная вкладка должна была перерасти в корпоративную вкладку, в которой бы размещались уже предварительно созданные в Active Directory группы для сотрудников (в Lync они именуются Distribution Groups): например, «Заказать пропуск», «Написать заявление» и т.д. Участниками данных групп являются сотрудники, занимающиеся определёнными вопросами в компании. При нажатии на данную группу открывается чат или аудио звонок с первым участником группы со статусом «онлайн». Редактированием этих групп должен заниматься администратор Lync-сервера. Конечно, в процессе реализации всех задуманных планов у нас возникали проблемы, которые мы периодически решали. Но была особая группа проблем, связанная с некорректной работой библиотеки Lync SDK в Lync Suppression mode. Мы отправляли их описание в Microsoft и думали, что сможем получить поддержку и найти способ решения. Проблемы Как неожиданно выяснилось, в UI Suppression mode пропадает интеграция с Outlook: • пропадают статусы контактов; • отсутствует возможность создать беседу из карточки контакта; • «отвалилась» кнопка «Создать собрание Skype». Полностью работающие карточки контактов в Outlook нам удалось вернуть, опираясь на вот эту статью (https://msdn.microsoft.com/ru-ru/library/office/jj...off15_IMIntegration_HowConnect). Также заработали статусы контактов. Теперь Outlook их получает не от Lync, а от нашего приложения, но обновляет он их каким-то магическим образом, и они постоянно «отваливаются» и перестают синхронизироваться. То есть реально человек уже появился онлайн и «зелёный», а в Outlook – всё ещё в жёлтом статусе «Отошёл». Мы писали в поддержку Microsoft, на что они нам прислали ссылку на эту же статью. Писали также в Yammer Microsoft, на форумах MSDN, Reddit и других площадках… К сожалению, эта проблема так и не решена. Проблема отвалившейся в Outlook кнопки «Создать собрание Skype» заключается в затирании в режиме UI Suppression mode ключей реестра по пути HCU/Software/Microsoft/Office/15.0/Lync/ConfAddin/мой sip/. Там представлены три ключа: Capabilities, InbandInfo, PublicMeeting. Когда Lync запущен в штатном режиме, при нажатии на кнопку «Создать собрание Skype» Outlook запрашивает у Lync информацию о конференциях, и уже Lync создаёт ключи реестра. В UI Suppresseion mode Lync этого делать не хочет. Средствами Lync SDK 2013 получить нужную информацию от Lync-сервера нельзя. Был найден выход: использовать другую SDK (https://msdn.microsoft.com/en-us/library/office/dn465943.aspx ) для работы непосредственно с сервером. Через UCMA мы смогли получить от сервера информацию о конференциях авторизированного пользователя. Наполнили ключи реестра – и вуаля: в Outlook вернулась возможность создавать собрания. Но в этом способе есть несколько ограничений: • библиотека UCMA работает только на 64-разрядных ОС, на 32-битных – решения нет; • компьютер пользователя и сервер должны находиться в одном домене, в противном случае нужно создавать сертификаты на сервере для доверенных приложений. Как это делать, описано тут, но нам данное решение не подходит, так как мы должны реализовывать функционал только на стороне клиента. Нашлись баги и в самом Lync SDK. Самый критичный: в видеобеседе p2p при добавлении 3-го участника падает сам Lync-клиент, стабильно. Майкрософт сам этот баг подтверждает, но сроков устранения не называет. Были попытки убивать беседу p2p и создавать сразу видеоконференцию на троих, но если 3-го участника добавляет клиент SFB, мы не можем этому помешать. Остановка и возобновление видеоканала тоже ни к чему не привели. Также проявилась проблема невозможности расшарить экран некоторым пользователям (тем, у кого установлена другая версия Lync-клиента). Проявляется данная проблема следующим образом. Первый клиент работает в нашем приложении (версия Lync – 2013), второй – в SFB 2016, и у него при открытии беседы с первым кнопка расшаривания экрана недоступна. Если первый клиент заходит в обычный Lync 2013 (не Suppression mode), то у второго кнопка шаринга становится активной. Если у второго установлен также Lync 2013 или наше приложение, шаринг доступен с обеих сторон. В Lync SDK отсутствует callback о доставке сообщения пользователю. Есть только callback, что сообщение ушло. Но иногда может сложиться ситуация, что мы отправляем сообщение человеку в онлайн, оно уходит без exception, но к моменту прихода собеседник уже офлайн. Следовательно, отправляющий думает, что сообщение пришло, а это не так. Часто возникает “ItemNotFoundException” при получении фото контактов, следовательно, приходится отображать наше стандартное изображение контакта. Эмпирическим путем мы нашли сколько раз (примерно 3) надо вызвать код получения фото, чтобы Lync его всё-таки вернул. Однако у некоторых контактов этот способ всё равно не срабатывает. Дополнительно мы ввели кэширование фото, чтобы при старте не сыпалась куча эксепшенов, если у пользователя добавлено много контактов. Есть проблема и с группами пользователя, в частности с «Favorites group». Проблема заключается в том, что у некоторых пользователей при вызове CanInvoke(DeleteGroup) Lync возвращает true, хотя эта стандартная группа Lync, и её нельзя удалить. Тип у этой группы такой же, как и у группы, созданной пользователем (CustomGroup), поэтому скрывание пункта «Удалить группу» из меню приходится делать еще и по дополнительной проверке на имя группы, что является жёстким костылём. Обнаружились ограничения Lync SDK 2013 • Недоступна одна из важных фич: возможность настройки переадресации вызовов, когда пользователь находится в офлайн. Мы реализовали переадресацию по истечении определённого времени, но только если пользователь не в офлайн. • При групповом видеозвонке (3 и более участников) поток, который транслирует видео участников, остаётся один (аналог мобильных конференций), то есть Lync сам меняет видеопотоки от разных участников в зависимости от того, кто сейчас говорит в микрофон. • Передача файлов недоступна в UI Suppression mode. Мы решили эту проблему 2 способами: -добавили передачу файлов через Outlook в виде аттача к письму; -внедрили сервис OneDrive для загрузки файлов в облако и автоматической отправки сообщения с URL файла. • Нельзя использовать контекстные данные беседы (как это делать, описано здесь https://msdn.microsoft.com/en-us/library/office/jj...px?f=255&MSPPError=-2147217396 ), когда беседа конвертировалась в конференцию и стала существовать на сервере, а не локально. Мы хотели использовать эту возможность для синхронизации различной информации между клиентами. • Отключена возможность записи в поле «Subject» в конференции (причём и в обычном Lync), зачем-то в Lync 2013 они закрыли эту возможность. Человек на MSDN жаловался, что у него в Lync 2010 около 30 сохраненных конференций, каждая со своим заголовком. С переходом на Lync 2013 у него остались только списки участников в каждой конференции. Теперь отличить одну беседу от другой практически невозможно. • Еще одна особенность Lync SDK 2013 – поддержка клиентов, начиная с Lync 2013 и новее. Lync 2010 не поддерживается. Однако Lync SDK 2010 работает и с Lync 2010, и с Lync 2013, и выше. Какой логикой руководствуется Microsoft, неизвестно. Заключение В процессе разработки мы поняли, что полностью реализовать полноценный аналог Lync, основываясь на Lync SDK + UCMA, не получится. Даже если не брать в расчёт ограничения данных технологий, обидно, что мы не смогли получить поддержку от Microsoft по исправлению ошибок Lync SDK. На сегодня мы вынуждены отказаться от UI Suppression mode, т.к. в нём невозможно реализовать весь нужный функционал, и ищем варианты обхода проявившихся проблем. Надеюсь, данная статья поможет начинающим разработчикам приложений на основе Lync/Skype for Business. И, возможно, кто-то из дочитавших до этого места захочет поделиться своими идеями. Пишите!

Метки:  

Использование механизма SRR в приложениях разработанных на Qt для QNX

Вторник, 19 Июля 2016 г. 20:31 + в цитатник
Фреймворк Qt один из самых популярных и применяемых при разработке кроссплатформенных настольных и мобильных приложений. Эта популярность не могла рано или поздно не привести к использованию Qt в системах специального и ответственного назначения. Достаточно давно существует возможность разработки на Qt для QNX Neutrino. Библиотека Qt поддерживает платформу QNX, а среда разработки Qt Creator обеспечивает взаимодействие с системами на QNX. Однако QNX, как система в том числе и для встраиваемых решений, имеет в своём составе технологии, которые не требуются, а потому и отсутствуют в системах общего назначения. Ключевая для ОСРВ QNX функциональность, на которой построена сама система и на которую нередко опираются пользовательские задачи это передача сообщений. Об особенностях применения механизма SRR (Send/Receive/Replay), как ещё называют передачу сообщений в QNX, и о разработке двух примеров Qt-приложений — клиента и сервера — я и хотел бы рассказать сегодня. В заметке не делается каких-то открытий, предлагается в общем-то известная информация. Тем не менее Qt это относительно новый фреймворк для разработчиков систем специального назначения, где исторически наблюдается некоторая инертность при внедрении новых технологий. Разработчики систем на QNX могут быть недостаточно знакомы с тонкостями Qt, а разработчики Qt-приложений зачастую могут не знать специфику QNX. Решение задачи использования в одном проекте и графических возможностей библиотеки Qt, и специфичных для QNX технологий может потребовать затраты усилий, особенно на первых этапах. Именно поэтому и появилась данная заметка, цель которой в одном месте собрать информацию, которая может понадобиться разработчикам при использовании Qt в QNX. Типовой пример использования SRR в QNX Поскольку о сообщениях QNX я уже писал раньше на Хабре, в том числе и о составных сообщениях, то будем считать, что теория в каком-то виде уже известна и можно переходить к практике. Поэтому привожу ниже исходный код приложения клиента: qnx_client.c//////////////////////////////////////////////////////////////////////////////// // qnx_client.c // // demonstrates using input/output vector (IOV) messaging // //////////////////////////////////////////////////////////////////////////////// #include <string.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include "../iov_server.h" int main(int argc, char* argv[]) { int coid; // Connection ID to server cksum_header_t hdr; // msg header will specify how many bytes of data will follow int incoming_checksum; // space for server's reply int status; // status return value iov_t siov[2]; // create a 2 part iov if ( 2 d\n"); exit(EXIT_FAILURE); } // locate the server coid = name_open(CKSUM_SERVER_NAME, 0); if ( -1 > Программа довольно тривиальная, я просто взял пример из курсов по QNX и немного его «причесал». Это консольное приложение, которое принимает на вход строку, пересылает её на сервер и выводит на экран ответ сервера — контрольную сумму переданной ранее строки. Обратите внимание, что в примере используются составные сообщения — макрос SETIOV() и функция MsgSendvs() вместо MsgSend() — что позволяет избежать лишнего копирования. Самое интересное здесь это использование функции name_open() для поиска сервера и установления соединения с ним. Теперь самое время посмотреть исходный код сервера: qnx_server.c//////////////////////////////////////////////////////////////////////////////// // qnx_server.c // // demonstrates using input/output vector (IOV) messaging // //////////////////////////////////////////////////////////////////////////////// #include <stdio.h> #include <stdlib.h> #include "../iov_server.h" typedef union { uint16_t msg_type; struct _pulse pulse; cksum_header_t cksum_hdr; } msg_buf_t; int calculate_checksum(char *text) { char *c; int cksum = 0; for ( c = text; *c; c++ ) cksum > Код сервера немного поинтереснее. Сервер принимает и обрабатывает сообщения от клиента. На самом деле в этом примере реализовано только одно сообщение — CKSUM_MSG_TYPE — подсчёт контрольной суммы переданных данных. Другое сообщение — _IO_CONNECT — посылается серверу, когда клиент вызывает функцию name_open(). Помимо сообщений сервер умеет обрабатывать служебные импульсы _PULSE_CODE_DISCONNECT и _PULSE_CODE_UNBLOCK. В этом простом примере обработка служебных сообщений в принципе не требуется. Алгоритм работы сервера достаточно прост. Сначала выполняется инициализация, в данном случае это объявление имени при помощи функции name_attach(), после чего клиенты могут найти сервер. Дальнейшая работа сервера представляет собой «вечный цикл». В самом начале цикла сервер блокируется на вызове MsgReceive() ожидая сообщений от клиента. По приходу сообщения или пульса ядро QNX разблокирует сервер, который начнёт обработку принятого сообщения. В примере используется объединение (union) msg_buf_t для получения сообщения. Это обычная практика для QNX, когда возможные типы сообщений (а сообщение обычно описываются структурой языка Си) объединяются в union. Наше полезное сообщение CKSUM_MSG_TYPE мы получаем при помощи MsgReceive() не целиком, принимается только заголовок, в котором указан размер данных. Данные дочитываются при помощи функции MsgRead(). Ответ клиенту отправляется при помощи функции MsgReply(), а в случае ошибки — MsgError(). Импульсы не требуют ответа. Для полноты картины привожу текст заголовочного файла. Этот заголовочный файл используется и сервером, и клиентом, и, как мы увидим дальше, Qt версии нашего сервера и клиента тоже используют этот файл. Он предназначен для подключения необходимых заголовочных файлов и объявления структуры заголовка сообщения CKSUM_MSG_TYPE. iov_server.h#ifndef _IOV_SERVER_H_ #define _IOV_SERVER_H_ #include <sys/dispatch.h> #include <sys/neutrino.h> #include <sys/iomsg.h> #include <errno.h> #define CKSUM_SERVER_NAME "cksum" #define CKSUM_MSG_TYPE (_IO_MAX + 2) typedef struct { uint16_t msg_type; unsigned data_size; } cksum_header_t; // checksum reply is an int #endif //_IOV_SERVER_H_ На скриншоте ниже представлен пример работы консольных версий сервера и клиента: Сначала запускается сервер, который ожидает сообщений от клиента. Потом запускается клиент, в качестве аргумента ему указывается строка «Hello, QNX!» Во время работы клиент и сервер выводят диагностические сообщения в консоль, по которым можно судить о работе программ. Программы работают как ожидалось, можно приступать к написанию графических вариантов на Qt. Сначала адаптируем клиентское приложение. Пример клиента на Qt Разрабатывать Qt приложения будем в Qt Creator. В этом случае сам процесс разработки приложений для QNX в общем не отличается от разработки приложений для других ОС. Ведь Qt это кроссплатформенный фреймворк. Требуется только создать комплект (Kit) для QNX в Qt Creator. Создаём новый проект приложения типа Qt Widgets Application. При этом Qt Creator подготовит все необходимые файлы, в том числе и форму для окна. Для клиента форму окна приводим к следующему виду: На форме размещены поле для ввода текста (text), который передаётся серверу, кнопки подключения (connect) и отключения (disconnect) от сервера, кнопка (calc) отправки сообщения серверу, поле ввода (cksum), которое используется для вывода контрольной суммы полученной от сервера, и область вывода диагностических сообщений (status). Осталось только написать код для работы с сервером и обработки логики графической формы. В результате получаем следующий класс MainWindow: mainwindow.h#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "../iov_server.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); public slots: void log(QString msg); void showCrc(QString crc); private slots: void qnxConnect(); void qnxDisconnect(); void calculate(); private: Ui::MainWindow *ui; int coid; // Connection ID to server }; #endif // MAINWINDOW_H mainwindow.cpp#include "mainwindow.h" #include "ui_mainwindow.h" #include <QDateTime> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); coid = -1; connect(ui->connect, SIGNAL(clicked()), this, SLOT(qnxConnect())); connect(ui->disconnect, SIGNAL(clicked()), this, SLOT(qnxDisconnect())); connect(ui->calc, SIGNAL(clicked()), this, SLOT(calculate())); } MainWindow::~MainWindow() { delete ui; } void MainWindow::qnxConnect() { // check if we already connected if ( coid t connect to server: ")).append(strerror(errno))); return; } log(tr("Connected to server")); ui->connect->setEnabled(false); ui->disconnect->setEnabled(true); ui->calc->setEnabled(true); } void MainWindow::qnxDisconnect() { // check if we already disconnected if ( coid < 0 ) return; // disconnect from the server int status = name_close(coid); if ( status < 0 ) { log(QString(tr("Can't disconnect from server: ")).append(strerror(errno))); return; } log(tr("Disconnected from server")); coid = -1; ui->calc->setEnabled(false); ui->disconnect->setEnabled(false); ui->connect->setEnabled(true); } void MainWindow::calculate() { ui->disconnect->setEnabled(false); ui->calc->setEnabled(false); // get the data QString data = ui->text->toPlainText(); log(QString(tr("Sending the following text to checksum server: %1")).arg(data)); // build the header cksum_header_t hdr; // msg header will specify how many bytes of data will follow hdr.msg_type = CKSUM_MSG_TYPE; hdr.data_size = data.length() + 1; // setup the message as a two part iov, first the header then the data iov_t siov[2]; // create a 2 part iov SETIOV(&siov[0], &hdr, sizeof(hdr)); SETIOV(&siov[1], data.toAscii().data(), hdr.data_size); // and send the message off to the server int incoming_checksum; // space for server's reply int status = MsgSendvs(coid, siov, 2, &incoming_checksum, sizeof(incoming_checksum)); if ( status < 0 ) { log(QString(tr("Can't send message to server: ")).append(strerror(errno))); return; } log(QString(tr("MsgSend return status: %1")).arg(status)); showCrc(QString::number(incoming_checksum)); } void MainWindow::showCrc(QString crc) { ui->cksum->setText(crc); ui->disconnect->setEnabled(true); ui->calc->setEnabled(true); } void MainWindow::log(QString msg) { ui->status->append(msg.prepend(QDateTime::currentDateTime().toString("hh:mm:ss "))); } Файл main.cpp остался таким, каким его создал Qt Creator, поэтому приводить его содержимое не стану. Итак, посмотрим, что же мы тут понаделали. Сначала, как и в прошлом примере, запускаем сервер. Затем запускаем Qt версию клиента. Нажимаем кнопку Connect, обращаем внимание, что сервер получает уведомление о подключении клиента в виде сообщения _IO_CONNECT. Затем пишем текст «Hello, QNX!» и нажимаем кнопку Calc, что приводит к отправке сообщения на на сервер. Событие отправки также отображается на экране. Полученная от сервера контрольная сумма отображается в окне клиента. Пример работает, сообщения отправляются и принимаются, проблем не замечено. Но… Но я то знаю, что всё не должно так замечательно работать. Дело в том, что после вызова MsgSendvs() клиент блокируется как минимум до вызова сервером функции MsgReceive() (моет быть больше, если в системе есть более высокоприоритетные процессы). Для иллюстрации этой особенности в коде функции calculate_checksum() сервера добавлена задержка в виде вызова sleep(10). С такой задержкой в сервере клиент блокируется на 10 секунд, что приводит к заметному «замерзанию» графического окна сервера. В некоторых случаях, особенно когда сервер сразу отвечает клиенту (т.е. информация всегда доступна серверу, а не приходит извне), блокировка не является проблемой. В остальных случаях, пользователь может начать нервничать, когда у него «замерзает» графический интерфейс. Я бы не стал рисковать и выпускать программы, которые могут нервировать заказчиков. С «замёрзшим» интерфейсом клиент не сможет продолжить работу с приложением после отправки сообщения до получения ответа от сервера, а ведь в реальной жизни приложение может взаимодействовать с несколькими серверами и предоставлять другие функции управления. Нет, текущий вариант клиентского приложения нас не может устроить. Поэтому давайте посмотрим на правильную реализацию клиента. Правильный пример клиента на Qt Как же можно решить проблему с блокировкой клиента? Клиент не может не блокироваться на MsgSendvs(). Однако вполне допустимо выделить работу с сообщениями в отдельный поток. В этом случае один поток обслуживает графический интерфейс, другой — реализует механизм SRR. Для работы с потоками в Qt будем использовать класс QThread. Реализацию SRR вынесем в отдельный класс Sender. Связь между классами Sender (работа с сообщениями) и MainWindow (графический интерфейс) организуем через сигналы и слоты Qt. Посмотрим, как изменился класс MainWindow с учётом вышесказанного. Для наглядности старый код также оставлен, и добавлен макрос SENDER_THREAD, при объявлении которого работа с сообщениями выполняется в отдельном потоке Qt. mainwindow.h#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "../iov_server.h" #define SENDER_THREAD #ifdef SENDER_THREAD #include <QThread> #endif namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); #ifdef SENDER_THREAD signals: void calcCrc(int coid, QString data); #endif public slots: void log(QString msg); void showCrc(QString crc); private slots: void qnxConnect(); void qnxDisconnect(); void calculate(); private: Ui::MainWindow *ui; int coid; // Connection ID to server #ifdef SENDER_THREAD QThread senderThread; #endif }; #endif // MAINWINDOW_H mainwindow.cpp#include "mainwindow.h" #include "ui_mainwindow.h" #ifdef SENDER_THREAD #include "sender.h" #endif #include <QDateTime> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); coid = -1; connect(ui->connect, SIGNAL(clicked()), this, SLOT(qnxConnect())); connect(ui->disconnect, SIGNAL(clicked()), this, SLOT(qnxDisconnect())); connect(ui->calc, SIGNAL(clicked()), this, SLOT(calculate())); #ifdef SENDER_THREAD Sender *sender = new Sender; sender->moveToThread(&senderThread); connect(&senderThread, SIGNAL(finished()), sender, SLOT(deleteLater())); connect(this, SIGNAL(calcCrc(int, QString)), sender, SLOT(send(int, QString))); connect(sender, SIGNAL(result(QString)), this, SLOT(showCrc(QString))); connect(sender, SIGNAL(log(QString)), this, SLOT(log(QString))); senderThread.start(); #endif } MainWindow::~MainWindow() { #ifdef SENDER_THREAD senderThread.quit(); senderThread.wait(); #endif delete ui; } void MainWindow::qnxConnect() { // check if we already connected if ( coid t connect to server: ")).append(strerror(errno))); return; } log(tr("Connected to server")); ui->connect->setEnabled(false); ui->disconnect->setEnabled(true); ui->calc->setEnabled(true); } void MainWindow::qnxDisconnect() { // check if we already disconnected if ( coid < 0 ) return; // disconnect from the server int status = name_close(coid); if ( status < 0 ) { log(QString(tr("Can't disconnect from server: ")).append(strerror(errno))); return; } log(tr("Disconnected from server")); coid = -1; ui->calc->setEnabled(false); ui->disconnect->setEnabled(false); ui->connect->setEnabled(true); } void MainWindow::calculate() { ui->disconnect->setEnabled(false); ui->calc->setEnabled(false); // get the data QString data = ui->text->toPlainText(); #ifdef SENDER_THREAD emit calcCrc(coid, data); #else log(QString(tr("Sending the following text to checksum server: %1")).arg(data)); // build the header cksum_header_t hdr; // msg header will specify how many bytes of data will follow hdr.msg_type = CKSUM_MSG_TYPE; hdr.data_size = data.length() + 1; // setup the message as a two part iov, first the header then the data iov_t siov[2]; // create a 2 part iov SETIOV(&siov[0], &hdr, sizeof(hdr)); SETIOV(&siov[1], data.toAscii().data(), hdr.data_size); // and send the message off to the server int incoming_checksum; // space for server's reply int status = MsgSendvs(coid, siov, 2, &incoming_checksum, sizeof(incoming_checksum)); if ( status < 0 ) { log(QString(tr("Can't send message to server: ")).append(strerror(errno))); return; } log(QString(tr("MsgSend return status: %1")).arg(status)); showCrc(QString::number(incoming_checksum)); #endif } void MainWindow::showCrc(QString crc) { ui->cksum->setText(crc); ui->disconnect->setEnabled(true); ui->calc->setEnabled(true); } void MainWindow::log(QString msg) { ui->status->append(msg.prepend(QDateTime::currentDateTime().toString("hh:mm:ss "))); } В объявлении класса MainWindow появился сигнал calcCrc(), при помощи которого сообщаемся экземпляру класса Sender кому и какое сообщение требуется отправить. Большие изменения претерпела реализация класса MainWindow. В конструкторе появился блок кода, в котором создаётся экземпляр класса Sender и при помощи метода moveToThread() выделяется в отдельный поток. В деструкторе ожидаем завершение потока (методы quit() и wait() класса QThread). Весь код метода calculate() перенесён в класс Sender и заменён на генерацию сигнала calcCrc(). После доработки MainWindow, можно перейти к классу Sender. sender.h#ifndef SENDER_H #define SENDER_H #include <QObject> #include "../iov_server.h" class Sender : public QObject { Q_OBJECT public: Sender() {} virtual ~Sender() {} signals: void result(QString data); void log(QString err); public slots: void send(int coid, QString data); }; #endif // SENDER_H sender.cpp#include "sender.h" void Sender::send(int coid, QString data) { emit log(QString(tr("Sending the following text to checksum server: %1")).arg(data)); // build the header cksum_header_t hdr; // msg header will specify how many bytes of data will follow hdr.msg_type = CKSUM_MSG_TYPE; hdr.data_size = data.length() + 1; // setup the message as a two part iov, first the header then the data iov_t siov[2]; // create a 2 part iov SETIOV(&siov[0], &hdr, sizeof(hdr)); SETIOV(&siov[1], data.toAscii().data(), hdr.data_size); // and send the message off to the server int incoming_checksum; // space for server's reply int status = MsgSendvs(coid, siov, 2, &incoming_checksum, sizeof(incoming_checksum)); if ( status < 0 ) { emit log(QString(tr("Can't send message to server: ")).append(strerror(errno))); return; } emit log(QString(tr("MsgSend return status: %1")).arg(status)); emit result(QString::number(incoming_checksum)); } По сути это код, который был раньше в методе calculate() класса MainWindow. Вывод ошибок и результата в графическое окно приложения клиента реализован при помощи сигналов log() и result(). С такими доработками графический интерфейс клиента не «замерзает», т.е. пока экземпляр класса Sender блокируется на 10 секунд в отдельном потоке, мы можем управлять графическим окном. Правда в представленном примере управлять особо нечем, но возможность то есть. Пример сервера на Qt Поэксперементировав с клиентом будем сразу разрабатывать сервер правильно. Поскольку вызов MsgReceive() приводит к блокировке, то вынесем функциональность сервера в класс Server, который будет работать в отдельном потоке. Принципы те же, что и в клиенте. Форму главного окна по-честному «скомуниздим» у клиента — скопируем mainwindow.ui, откроем в редакторе, удалим ненужные кнопки и преобразуем класс QPlainTextEdit (объект text) в QTextBrowser (редактор это позволяет). Объявление и реализация класса MainWindow сервера приведены ниже: mainwindow.h#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QThread> #include "../iov_server.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); signals: void startServer(name_attach_t* attach); public slots: void log(QString msg); void showCrc(QString crc); void showText(QString txt); void stopServer(void); private: Ui::MainWindow *ui; name_attach_t* attach; QThread serverThread; }; #endif // MAINWINDOW_H mainwindow.cpp#include "mainwindow.h" #include "ui_mainwindow.h" #include "server.h" #include <QDateTime> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); Server *server = new Server; server->moveToThread(&serverThread); connect(&serverThread, SIGNAL(finished()), server, SLOT(deleteLater())); connect(this, SIGNAL(startServer(name_attach_t*)), server, SLOT(process(name_attach_t*))); connect(server, SIGNAL(result(QString)), this, SLOT(showCrc(QString))); connect(server, SIGNAL(text(QString)), this, SLOT(showText(QString))); connect(server, SIGNAL(log(QString)), this, SLOT(log(QString))); attach = name_attach(NULL, CKSUM_SERVER_NAME, 0); if ( NULL t attach name: %1")).arg(strerror(errno))); } else { serverThread.start(); emit startServer(attach); } } MainWindow::~MainWindow() { stopServer(); serverThread.quit(); serverThread.wait(); delete ui; } void MainWindow::showText(QString txt) { ui->text->setText(txt); } void MainWindow::showCrc(QString crc) { ui->cksum->setText(crc); } void MainWindow::log(QString msg) { ui->status->append(msg.prepend(QDateTime::currentDateTime().toString("hh:mm:ss "))); } void MainWindow::stopServer() { if ( NULL > Для работы сервера создаём имя в MainWindow используя функцию name_attach(). При помощи сигнала передаём структуру attach в поток сервера, тем самым запуская его. Для остановки сервера удаляем имя — функция name_detach(). В остальном очень похоже на то, что было сделано в клиенте. Посмотрим на код: server.h#ifndef SERVER_H #define SERVER_H #include <QObject> #include "../iov_server.h" typedef union { uint16_t msg_type; struct _pulse pulse; cksum_header_t cksum_hdr; } msg_buf_t; class Server : public QObject { Q_OBJECT public: Server() {} virtual ~Server() {} signals: void result(QString data); void text(QString text); void log(QString err); public slots: void process(name_attach_t* attach); private: int calculate_checksum(char *text); }; #endif // SERVER_H server.cpp#include "server.h" int Server::calculate_checksum(char *text) { int cksum = 0; for ( char *c = text; *c; c++ ) cksum > Класс Server реализует две функции консольного сервера (qnx_server), изменился только вывод сообщений (при помощи сигналов/слотов Qt) и регистрация имени выполняется в классе MainWindow. Работа графических вариантов клиента и сервера представлена на следующем скриншоте: Сервер получился без элементов управления. Нет ни кнопок, ни полей ввода. Графическое окно сервера служит только для контроля за его работой. Заключение Вот и подошла к концу эта заметка. Был рассмотрен код нескольких примеров, стало понятно, как правильно использовать механизм сообщений QNX в приложениях на Qt. Для тех же, кто захочет воспроизвести примеры я опубликовал их на Bitbucket. Предвидя возможные замечания по коду, прошу учесть, что это только примеры, которые иллюстрируют работу SRR в Qt. Кое-что в рабочей системе я бы сделал иначе, но чтобы не перегружать примеры, их код был упрощён, и на некоторые моменты я закрыл глаза. Тем не менее, если у кого-то из читателей появятся конкретные предложения по улучшению кода примеров или исправлению ошибок, то я их по возможности учту. Прошу по этим вопросам обращаться в личные сообщения.
Сетевые технологии Интернета вещей

Метки:  

Azure DevTest Labs

Понедельник, 18 Июля 2016 г. 21:20 + в цитатник
Чуть больше месяца назад публичную доступность получил DevTest Labs — новый сервис Microsoft Azure для создания облачных окружений разработки и тестирования. Если вкратце, то DevTest Labs представляет собой лабораторию для создания наборов виртуальных машин на базе образов Windows и/или Lunux. Вы можете использовать как множество готовых образов (в том числе из галереи Azure Marketplace), так и загружать свои собственные из VHD файлов. Вы также можете расширять создаваемые виртуальные машины так называемыми артефактами. Артефакты представляют собой JSON файлы, в которых определенны некоторые кастомные действия выполняющиеся при создании виртуальной машины. Например, артефакт может выступать в роли скрипта для установки внешнего компонента, либо выполнять какое-то конфигурационное действие над виртиальной машиной. По умолчанию, вы получаете доступ к большому набору готовых артефактов из публичного репозитория сообщества DevTest Labs. Ознакомившись с готовыми примерами, вы сможете создать свой собственный репозиторий с артефактами и подключить его к вашей лаборатории DevTest Labs. В качестве репозитория можно использовать GitHub или VSTS. Инструмент Formula позволяет создавать реюзабельные конфигурации виртуальных машин, включающие: образ, размер, набор артефактов, параметры сети и тп. Данный подход удобен если вам потребуется частое создание окружения с общими конфигурациями. DevTest Labs содержит большой набор инструментов для контроля за ресурсами и стоимостью окружений. Кроме поддержки стандартного Azure Role-Based Control (RBAC), вам становятся доступен следующий набор функций: Функция автоматического включения/выключения виртуальных машин окружения, позволяет экономить ваши финансы, в периоды времени когда ваше окружение не используется. Вы можете устанавливать запреты на размеры и количество создаваемых виртуальных машин ограничения сверху стоимость окружения. Virtual Network settings позволяют устанавливать запреты на использования виртуальных сетей и подсетей Azure, а также контролировать создания публичных IP адресов. Диаграмма Cost thresholds является достаточно удобным инструментом для мониторинга за текущей и прогнозируемой стоимостью окружения в месяц. Вы также можете ограничивать список образов Azure Marketplace, которые могут быть использованы в лаборатории. Все ресурсы создаваемые в DevTest Labs (кастомые образы, артефакты, образы и тп) являются реюзабельными в пределах подписки, таким образом вы можете их переиспользовать и в ваших других лабораториях. DevTest Labs полностью поддерживается Azure Resource Manager. Благодаря этому вы можете создавать готовые окружения из ARM шаблонов. Ознакомиться с галереей готовых шаблонов вы можете здесь. Уже сейчас доступны готовые таски для управления окружениями DevTest Labs в Visual Studio Team Services. Эти таски позволяют создавать, останавливать и запускать окружение во время билда или процесса Release Management. Кроме этого, управление окружениями DevTest Labs доступно через: Azure PowerShell, REST APIs и .NET SDK. Таким образом, благодаря кастомизации вы сможете интегрировать DevTest Labs в ваши существующие процессы, вне зависимости от выбранной CI системы. DevTest Labs довольно интересный сервис. В первую очередь он может оказаться полезным командам, которые работают с различными конфигурациями виртуальных машин и заботятся о минимизации расходов на стоимость окружения. DevTest Labs постоянно развивается и обрастает новыми возможностями. Если у вас появятся идеи или пожелания по улучшению данного сервиса, то вы можете написать их в MSDN блог. Вопросы по использованию направляйте сюда.

Тренды интернет-рекламы: от видео к виртуальной реальности

Воскресенье, 17 Июля 2016 г. 14:47 + в цитатник
Изображение с сайта ixbt.com Самые смелые эксперты из сферы интернет-маркетинга пророчат баннерам скорую смерть: якобы их должна вытеснить видеореклама. Один из аргументов, которые они приводят, перефразируя известное высказывание, может звучать так: «Лучше один раз увидеть, чем сто раз прочесть». Многие продукты действительно выигрышно смотрятся на видео. Если говорить, например, о приложениях, то за короткое время вам продемонстрируют все его лучшие качества. Ну а с недостатками можно ознакомиться уже после покупки, либо прочитав отзывы. Безусловно, видео в большинстве случаев поможет потенциальному клиенту принять взвешенное решение и нажать кнопку «Установить», либо отказаться от покупки. В одном из постов на Geektimes уже рассказывалось о возможных вариантах продвижения приложений с использованием видеорекламы: видео в Google Play Store, видео в App Store (App Previews), альтернативные App Stores, видео на личном веб-сайте, YouTube, Facebook Video ads, Instagram video ads, Twitter video ads, TrueView (Google video ads). Популярность видеорекламы растет быстро, но еще быстрее растет популярность более современных технологий. Но о них – чуть позже. Прогнозы По прогнозу компании Strategy Analytics, к концу 2022-ого года число аудитория мобильного видео вырастет до 2 миллиардов человек. В попытке «завоевать мир», рекламодатели будут вкладывать еще больше средств в мобильную видеорекламу, стараясь охватить как можно больше пользователей смартфонов и планшетов. Вей Ши, аналитик Strategy Analytics, отмечает, что наибольший рост выручки ожидается в сегменте спонсируемого брендами контента. Бюджеты в данном сегменте будут расти на 28% в год на протяжении ближайших 5-ти лет. К 2021 года мировой объём доходов в секторе мобильного видео достигнет отметки в 25 миллиардов долларов (22,5 миллиарда евро). Как видно из графика, по темпам роста выручки индустрии мобильного видео выделяются Северная Америка и Западная Европа. В Азиатско-Тихоокеанском регионе динамика роста – более насыщенная. Посредниками в процессе рекламной монетизации все чаще выступают Facebook, Twitter, WeChat и остальные социальные сети. Ученые тем не менее отмечают, что пока тренд развивается настолько быстро, что не все рекламодатели смогут своевременно нарастить свои бюджеты на продвижение. Но, как мы увидим далее, в ближайшем будущем наберут популярность и другие способы продвижения, которые позволят расстаться со своими деньгами рекламодателям, которые еще не успели это сделать. Нюансы Оказывается, визуальный ряд для пользователей несравнимо важнее звука. По крайней мере, такой вывод делают исследователи. Ежедневно Facebook генерирует более 8 миллиардов просмотров. По данным сайтов LittleThings и Mic, каждый из которых генерирует по 150 миллионов просмотров на Facebook, для 30-секудных видеороликов 85% просмотров происходят без звука. Представители PopSugar аналогично подтверждают эту информацию, уточняя, что в их случае это значение находится в пределах 50-80%. Создатели видеорекламы и здесь нашли выход: они на всякий случай размещают на видео еще и текст объявления. Они верят, что пользователи выключают звук «по уважительной причине», а не потому, что реклама им мешает. Представители рекламных агентств отмечают, что по цене просмотров YouTube оказывается дешевле Facebook в 9 из 10 случаев. Тем не менее, иногда рекламодатели отдают предпочтение Facebook из-за наличия целевой аудитории. Они полагают, что будет проще продать таким пользователям услуги или товары через свои каналы. Но не все так благополучно, как хотели бы видеть рекламодатели. Число владельцев смартфонов, использующих ПО для блокировки рекламы, согласно последнему отчету PageFair выросло на 90% за последний год. В общей сложности, рекламу на смартфонах блокирует почти 420 миллионов пользователей по всему миру. По статистике — это каждое пятое мобильное устройство на планете. Активно блокируют рекламу жители азиатско-тихоокеанского региона — там блокировщики установлены на 36% устройств. В Индии и Индонезии adblock-приложения использует две трети всех владельцев смартфонов. В Китае блокировщики установлены на 159 миллионов устройств. Periscope и Facebook Live Еще один тренд, который нельзя игнорировать, – это сервисы с помощью Periscope, Facebook Live и так далее. Они позволяют проводить онлайн-трансляции. Они быстро стали популярны среди медиакомпаний и знаменитостей, а значит, представляют интерес для рекламодателей. «Популярность можно объяснить несколькими тенденциями, но главное — это проникновение смартфонов и скоростного мобильного интернета, чего не было пять-шесть лет назад. Лайвстриминг занимает свою нишу в коммуникациях, закрывая те сегменты, что до этого не доступны были фотографии», — сообщил в беседе с «Газетой.Ru» главный аналитик Российской ассоциации электронных коммуникаций (РАЭК) Карен Казарян. Сервис микроблогов Twitter купил Periscope в 2015 году. После этого для проведения онлайн-трансляций пользователю стало достаточно своего смартфона, подключенного к интернету, и аккаунта в Twitter. Новый тренд оперативно подхватила и социальная сеть Facebook, представившая в августе прошлого года функцию Facebook Live. Стараются не отставать и российские сервисы «ВКонтакте» и «Одноклассники». Сервис Periscope взяли на вооружение СМИ: трансляции с разных событий организовывали CNN, Bild, The Guardian, The Verge и другие. Но пока у Twitter нет четкого понимания, как зарабатывать на новом сервисе. Ставку на медиаконтент делает и сеть Facebook, обеспечившая приоритетное положение видео на пользовательских страницах и отправляющая уведомления подписанным пользователям о начале трансляции на той или иной странице. На текущий момент социальные сети запустили живое потоковое видео как механизм для увеличения количества пользователей и времени, которое они проводят в социальных сетях. Как свидетельствуют данные Syndacast, видео обеспечивает наиболее высокий показатель конверсии по сравнению с другими типами контента. Результаты опроса Internet Retailer демонстрируют, что 96% пользователей руководствуются просмотром рекламных роликов перед принятием решения о покупке. Пока в крупных интернет-компаниях только думают над приемлемыми формами монетизации, маркетологи уже нашли способы продвижения и заработка на основе новых возможностей соцсетей. Помогает в этом статистика, которую по завершении трансляций предоставляют Facebook Live и Periscope. В частности, наличие этой функции стало ключевым моментом в противоборстве с Meerkat, который запустился раньше своих конкурентов, но не смог предоставить полноценный фидбек по итогам живых эфиров. Негативно сказалось на приложении и отключение от Twitter. Наиболее очевидным способом заработка, предложенным в рунете, является реклама того или иного продукта непосредственно в самом Periscope-эфире. Для этого потребуется уже раскрученный аккаунт в соцсетях с немалой аудиторией. Предлагается получать прибыль и на проведении трансляций лекций или бизнес-тренингов в случае, если пользователь имеет интересные публике знания. В этом случае также понадобится уже популярный профиль в соцсетях. К тому же, он должен быть закрытым, а подписка на него — платной. VR-технологии VR-технологии и 360-градусные видео стали главным технологическим трендом в этом году. Пользователи готовы играть в специфические компьютерные игры, делать 3D-селфи для интернет-шопинга, ходить на виртуальные свидания, но этим применение данных технологий не ограничивается. Использование VR в рекламных целях переместило рекламу в другую плоскость – в прямом и в переносном смысле. А вместе с этим перевернулось и представление о рекламе у потребителя. Аналитики утверждают, что эффективность этого формата уже сейчас значительно превосходит обычные видеоролики. А это значит, что традиционное потребление рекламного видеоконтента в интернете (да и обычного видео) со временем уступит место виртуальной реальности. Именно покупка Oculus компанией Facebook в 2014 году стала основным показателем роста рынка VR. Facebook также разрабатывает контроллеры прикосновений, которые должны дополнить уже существующие VR-технологии, которые планируется использовать в шлеме виртуальной реальности. CEO Facebook Цукерберг описал разработку как «совершенно новый уровень погружения». В марте 2015 года крупнейший видеохостинг Youtube представил поддержку видео с обзором 360 градусов, которое позволит просматривать ролики под разными углами. Впоследствии аналогичную функцию в своей соцсети запустила и компания Цукерберга. Первыми в маркетинговых целях технологию VR стали использовать создатели развлекательного контента — кинофильмов и телешоу. 360-градусные видео в качестве промо блокбастеров стали массово создаваться сразу после успеха промо-ролика новых «Звездных войн», который был выложен в Facebook и Youtube еще в сентябре прошлого года. К настоящему времени это стало весьма распространенным явлением среди производителей развлекательного контента. Например, канал HBO анонсировал старт нового сезона самого популярного сериала «Игра престолов» с помощью 360-градусной заставки. Game of Thrones Opening Credits 360 VideoFrom King’s Landing to Dorne, explore the world of Westeros like never before in our immersive 360 experience.Опубликовано Game of Thrones 13 апреля 2016 г. Далее VR-технологиями заинтересовались и традиционные бренды: в этой формате выпустила новый каталог IKEA, а авиаперевозчик Etihad Airways снял рекламный фильм, в котором снялась голливудская звезда Николь Кидман. Видео «Reimagine», созданное The Barbarian Group, позволяет зрителям полностью погрузиться в уникальную атмосферу путешествия на борту Airbus A380. Технология VR рекламы идеально подходит для туристического бизнеса. The Teleporter — кабинка, похожая на традиционные британские телефонные будки, переносила жителей туманного Альбиона на теплые берега гавайских островов или в шумный Нью- Йорк. Имитация была создана с помощью очков Oculus Rift, термодатчика, подогревавшего воздух и вентилятора, имитирующего ветер. VR активно используется в рекламных целях менее года, однако аналитики уже просчитали эффект его использования для брендов. Аналитическая компания Newswhip выяснила, что популярность постов в соцсетях сегодня обеспечивает видеоконтент. Среди этого контента самые популярными являются именно 360-градусные ролики. NewsWhip проанализировал данные пабликов в Facebook 10 ведущих издателей за прошедший год. Эта группа включает в себя новые медиа — такие, как BuzzFeed и Huffington Post, а также более традиционные — The New York Times, Fox News, ВВС, Guardian и так далее. Согласно данным исследователей, 360-градусные видео просматриваются на 55% больше обычных, а расшариваются на 57% чаще. Сегодня VR и 360-градусные видео только входят в практику маркетологов, но аналитики отмечают, что развитие этого сегмента неизбежно приведет к замене обычных видео и полной смене модели потребления видеоконтента в интернете.

Метки:  

Проецируя Google Material Design на десктопную систему… (часть вторая)

Вторник, 05 Июля 2016 г. 21:14 + в цитатник
Краткое содержание первой части: контрактный клиент, редизайн их собственной CRM-ки, стиль Google Material, привычная среда обитания, аудитория — опытные айтишники. Кто не вдохновился первой частью и остальных тоже — приглашаю под кат… Вобщем, как вы помните, я выкатил клиенту вот такую картинку в качестве выполненного тествого задания и стал ждать ответа…. Прежде всего я хотел бы выразить благодарность скептикам из первой главы. Я и так два месяца откладывал описание этого проекта. Теперь же у меня появилась дополнительная мотивация продолжить: мне предстоит не только аргументировать свои решения, но и развеять ваши сомнения. Внимательный читатель безусловно заметил некоторые погрешности на скриншоте выше. И это замечательно! Не стоит забывать, что этот скрин — лишь результат тестового задания. Данный скрин — не целая система. Этот макет не решает проблемы пользователя или предлагает какой-то оптимальный сценарий. Это лишь “контрольная работа”, которая подается на стол потенциальному клиенту на проверку. Она основана на рестилизации одного случайно выбранного экрана старой системы. Как правило на этой стадии иногда бывает, что UI-дизайнер задаёт значение некоторым элементам/блокам/разделам, исходя из собственных догадок, а не задач клиента. Это допустимо и не критично. Дальше, как правило, дизайнер, подпитываемый верой или надеждой, ожидает feedback от клиента. Давайте теперь посмотрим на оригинал скриншота (внешний вид системы на тот момент). Именно этот раздел был выбран мной из 5 предложенных в качестве тестового задания: Что мне сразу бросилось в глаза тогда: дефолтный bootstrap, обилие форм ввода, вкладочность. Кстати, в последствии оказалось, то, что на моём тестовом задании блок “Уведомления” вообще трактован некорректно. У клиента в системе это на самом деле таски, связанные с данной задачей! Упс, я ведь оформил их совсем иначе… На самом деле на стадии выполнения тестового это моё недопонимание никого не волновало. Адекватный клиент понимает, что это еще не стадия работы “предлагать решения”. Это пока лишь “пре” стадия возможной будущей совместной работы под названием “показать подход”. Поэтому тех, кто спрашивал раньше, почему “уведомления” болтаются внизу, я успокою… Уведомлений вообще не будет :) Итак, упорядочу наблюдения: Дефолтный bootstrap. Это то, от чего клиент хочет уйти, потому как дефолтность не может обеспечить подстройки под личные нужды. Это то, про что обычно клиент говорит “Сейчас реализовано вот так, мы понимаем, что криво, но хочется немного иначе”. Обилие форм ввода. Для тех, кто в первой главе посчитал, что это “получилось очень нагромождено” скажу, что всё самое страшное еще впереди. Да, такова специфика системы Chronos: очень много параметров, которые сопровождают каждую сделку. Выкинуть нечего. Задача — не из визуально приятных, ведь к скроллам прибегать нельзя. Вкладочность. Это требование к системе. Так как сотрудникам Performance Lab зачастую одновременно приходится вести множество сделок и клиентов, то все они должны быть доступны за минимальное количество кликов. Любую вкладку можно закрыть, нажатие на любой раздел в меню слева порождало новую. Итак, скооперировавшись с аналитиком компании, который как оказалось тоже предпочитал Андроид, мы начали. Аналитик прекрасно знал требования пользователей, их поведенческие сценарии и их проблемы. Взаимодействовать с ним было сплошным удовольствием. Дизайнер интерфейсов должен проявлять колоссальное любопытство и внимание к пользователям и процесс движется эффективнее, когда у аналитика уже есть набор всех данных об их поведении. Сделки Раздел “Сделок” представляет из себя стандартный подход в виде воронки продаж. Для компании существует около 10 стадии ведения клиента. От “холода”, потом к “всё теплее” и в конечном итоге самая “жара” — это успешная продажа. Цель данного раздела в CRM “Chronos” — дать понимание количества сделок в каждой конкретной стадии, представить их денежный объем, показать задействованных сотрудников и, если надо, выделить просроченные. Я начал работу согласно всем текущим трендам: обилие отступов, наполненность воздухом и никакой тесноты для элементов: Попутно я предложил новую цветовую гамму для всех стадий продаж, основываясь на цветах, предлагаемых правилами Google Material (вот удобный ресурс для подбора цвета по этим правилам): Было Стало (от “холода” к продаже, в самом конце неприятное — красным, если сделка сорвалась, серым — если заморожена) Для отображения информации по всем сделкам в табличном виде был предложен следующий режим переключения вида (по клику): Каждая сделка была представлена в виде карточки: Последовательность подачи информации для каждой сделки выглядела следующим образом: сначала необходимо сделать акцент на сумме сделки, вторичнее по значимости идёт человек за неё ответственный, и только потом имеет значение название и описание сделки. За иконкой вертикального троеточия можно прятать любой дополнительный функционал (сохранить, экспортировать, поделиться, да мало ли чего еще потребуется). Нажимая на иконку “глаз” мы вызываем попап с параметрами отображения: можно выводить только определённые стадии сделок, или же выводить сделки только от определённых людей (заказчики, КАМы, пресейлы): Конечно, нельзя не упомянуть об отречённой и болтающейся одиноко floating button (ведь мы же следуем гайдам Гугла, если вы не забыли) в правом нижнем углу. Она пригодится для создания новой сделки … Первые проблемы По старой доброй традиции кое-какую важную информацию на старте клиент “подзабыл”. А именно… “Кстати, у нас же 80% пользователей системы бегают по офису с ноутами! И все они с разрешением 1366х768. А давайте-ка все макеты “запилим” в этот размер экранчика”. Лолштооо?! Когда разрешение 1300 было ходовым, мир не знал ни материального дизайна, ни солидных отступов, ни концепции “воздушности” в интерфейсах. Была поставлена задача любой ценой и жертвами уложить в это разрешение 6 стадий сделок. Да потеснить все элементы так, чтобы для каждой стадии было видно 4 карточки. Ну и ну! Получается, что во-первых: я должен урезать макет по высоте до реалистичной ноутбуковской высоты 768, а во-вторых: внедрить 4ый ряд карточек… Прощай “наполненность воздушностью” :( Но таковы требования к функционалу системы. Аналитик знает, что говорит, и мне приходится действовать в появившихся ограничениях. Первые решения Меня успокоили тем, что если и будет планироваться версия для мобильных устройств, то к ней будет индивидуальный подход. Сказано — сделано: Хорошей новостью оказалось то, что левое меню можно свернуть, тогда взору предстаёт более широкая картина: Раздел параметров отображения тоже пришлось потеснить и дополнить. Т.к. “внезапно” выяснилось, что будут сценарии, когда захочется фильтровать и выводить сделки за определенный период и находящиеся в определённом денежном диапазоне: (для визуального примера выполнена фильтрация еще и по людям: два заказчика, два пресейла, два КАМа) Наверное будет не лишним показать с чего всё начиналось… Разумеется этот скриншот сделан клиентом с экрана шириной 1920 пикселей, поэтому он способен отобразить больше информации: В следующем выпуске я расскажу о табличном виде и взаимодействии с формами внутри CRMки “Chronos”...
Введение в ReactiveUI: коллекции

Метки:  

Виртуальная реальность в проектировании дата центров

Воскресенье, 26 Июня 2016 г. 11:04 + в цитатник
В последнее время искусственная, или виртуальная, реальность (VR) все более распространяется в сфере потребительской электроники, а также в обрабатывающей промышленности, здравоохранении, образовании и т.д. Но в индустрии ЦОД данное направление практически не применяется, не взирая на то, что именно серверы отвечают за визуализацию контента, отображаемого большинством гарнитур виртуальной реальности. ЦОД характеризуется несколькими показателями и коэффициентами, значения которых и являются объектом изменения при его оптимизации. Обладая информацией о значениях данных и показателей, возможно запланировать меры, которые помогут повысить энергоэффективность дата-центра. Но подобные действия достаточно трудоемкие и опасные, ведь ошибки могут привести к сбою в работе ЦОД и даже к потере данных. Для того, чтобы поменять расположение серверных стоек также понадобится немало сил и времени. Но с помощью виртуальной реальности все эти манипуляции можно оптимизировать и сделать более надежным. Достаточно составить виртуальную модель, которая позволит определить правильность воздушных потоков и измерить необходимые показатели. Таким образом получится провести все вычислительные процессы, мониторинг и проектирование в полной безопасности по отношению к работоспособности ЦОД. У виртуальной реальности есть огромный потенциал — ее можно применять для проектирования и строительства серверных ферм. По мнению генерального директора колокейшн-провайдера Aegis Data Грега Маккалоха, именно дата-центры способны максимально эффективно использовать подобную технологию. И возможностей для этого предостаточно. В частности, VR особенно пригодится в проектировании и строительстве фактического помещения под ЦОД. Ведь с помощью виртуальной реальности получится визуализировать полезное внутреннее пространство и увидеть, как будет выглядеть само здание. Также и потенциальные клиенты смогут самостоятельно, удаленно «посещать» машзалы, в которых они собираются арендовать пространство. Это удобно, экономит время и деньги. Кроме того комплексное изучение визуализации модели ЦОД поможет принять более основательное решение в выборе площадки для хранения данных. И удаленные партнеры получат возможность просматривать систему физической безопасности дата-центра, включающую камеры видеонаблюдения, системы биометрической идентификации, тамбуры-шлюзы и многие другие элементы. Несмотря на то, что рассматриваемая технология пока еще находится на ранней стадии своего развития, Маккалох уверен, что VR-гаджеты уже являются достаточно полезными и эффективными инструментами для удовлетворения потребностей индустрии ЦОД. Они успешно используются при проектировании коммерческих зданий, поэтому ничто не мешает адаптировать их и для проектирования дата-центров. Ниже находится видеоролик от Google, который показывает использование виртуальной реальности для демонстрации ЦОД. Это — виртуальная экскурсия по дата-центру поискового гиганта в городе Даллас (штат Орегон, США). Данное видео представляет одно из самых безопасных мест на планете. С его помощью Google удалось показать свой дата-центр широкой аудитории, помогая потребителям понять, каким образом работают интернет-сервисы, вроде поисковиков и облачных хранилищ. Гаджеты виртуальной реальности могут стать весьма эффективными инструментами для продвижения коммерческих дата-центров, их проектирования и расширения инфраструктуры. Кроме того виртуальная реальность открывает новые возможности для обучения персонала серверных ферм или оптимизации взаимодействия между несколькими дата-центрами. Например, проведений совместных виртуальных конференций с участием операторов сразу нескольких ЦОД одной организации, расположенных в разных геолокациях. Но одновременно с получением выгоды, операторам ЦОД нужно осознать, что рынок виртуальной реальности будет неустанно расти. И по прогнозам, на 2016 год число проданных VR-гаджетов достигнет 9,6 млн штук. Подобная тенденция востребованности аудиовизуального медиа-контента для гаджетов виртуальной реальности рано или поздно приведет к новым вызовам для владельцев дата-центров. Они будут вынуждены наращивать число систем хранения данных и серверов, должным образом расширяя вспомогательную инфраструктуру своих корпоративных или коммерческих серверных ферм.

Метки:  

Отчет с Moscow Data Science Meetup 27 мая

Воскресенье, 26 Июня 2016 г. 09:14 + в цитатник
27 мая в офисе Mail.Ru Group прошёл очередной Moscow Data Science Meetup. На встрече собирались представители крупных российских компаний и научных организаций, а также энтузиасты в области машинного обучения, рекомендательных систем анализа социальных графов и смежных дисциплин. Гости делились друг с другом своим опытом решения практических задач анализа данных. Предлагаем вашему вниманию видеозаписи и презентации трёх докладов, представленных на встрече. Дмитрий Носов, Rambler&Co, H2O на Spark: как мы пили газировку и чуть не захлебнулись H2O — интересная и многообещающая платформа машинного обучения. Она может порадовать аналитика скоростью работы с большими объемами данных, набором алгоритмов, наличием API для нескольких языков программирования, и, конечно же, красивыми и подробными отчетами по построенным моделям. H2O написана на Java, поэтому работает вездеTM, в том числе на кластере Spark. В докладе спикер поделился своим опытом использования H2O на Spark и YARN, а также причинами отказа от использования H2O в production-окружении, несмотря на все ее положительные качества. Видеозапись выступления: it.mail.ru/video/724 Павел Филонов, «Лаборатория Касперского», Глубокое обучение и извлечение признаков в прогнозировании временных рядов Автоматическое выделение признаков, которые имеет место при построении глубоких сетей, видится перспективным инструментом, способным значительно сократить объём работ по подготовке данных. В докладе рассмотрена задача прогнозирования значений временного ряда и сравнены подходы к ее решениям как с использованием ручного выделения признаков, так и построенные на полностью автоматической обработке сырых данных. Видеозапись выступления: it.mail.ru/video/723 Александр Дьяконов, ВМК МГУ, Решение задачи Search Results Relevance (на платформе Kaggle) Разобрана задача по определению релевантности поисковой выдачи, которая решалась на прошлогоднем «Практическом семинаре по АД kaggle». Был описан очень простой алгоритм, который не использует сложных методов анализа текстов, словарей и ансамблей алгоритмов, и который, тем не менее, смог попасть в десятку сильнейших среди более чем 1300 участников. Видеозапись выступления: it.mail.ru/video/722
Опыт использования Liferay Portal в eСommerce

Метки:  

Dell Storage SC9000: интеллектуальная система хранения для эффективного дата-центра

Суббота, 25 Июня 2016 г. 17:52 + в цитатник
Рост требований к производительности СХД заставляет вендоров искать новые подходы к созданию оптимальной архитектуры систем хранения данных и наряду с традиционными дисками использовать флэш-память. Разработка серверов и систем хранения данных является одним из приоритетов Dell, куда компания инвестирует значительные средства. В настоящее время она предлагает новые системы резервного копирования и хранения данных для разных видов бизнеса. Рассмотрим подробнее систему хранения Dell SC9000. Аппаратная платформа Новый дисковый массив Dell SC9000 выпущен в октябре 2015 года и определенно заслуживает того, чтобы взглянуть на него внимательнее. Это флагманское решение уже можно увидеть в крупных дата-центрах мира. Но к системе стоит присмотреться и средним компаниям. Хранилище SC9000 с многопетабайтной емкостью и операционной системой Storage Center 7.0 предлагает новые возможности для ИТ-подразделений. Аппаратная платформа SC9000, старшая в линейке массивов серии SC, отличается самой высокой производительностью и масштабируемостью — до 960 накопителей SAS SSD и / или HDD на массив, причем массивы можно объединять в группы (федерация). Уже доказавшая свою надежность платформа оснащена новыми 8-ядерными процессорами Intel, вчетверо увеличена емкость системной памяти, а в качестве бэкенда используется интерфейс SAS 12 Гбит/с. Система поддерживает протоколы SAN (FC, iSCSI, FCoE), а также NAS через опциональное устройство FS8600. Производительность системы по сравнению с предыдущими продуктами SC выросла на 40 %. Внутренние тесты показали, что быстродействие массива SC9000 превышает 360 тыс. IOPS при задержке менее миллисекунды. Кроме того, вдвое выросла пропускная способность, а это означает отсутствие узких мест при росте нагрузки. В основе Dell SC9000 – новая серверная платформа Dell PowerEdge 13-го поколения с четырьмя 8-ядерными процессорами Intel Xeon с тактовой частотой 3,2 ГГц и оперативной памятью емкостью до 512 Гбайт. Систему можно конфигурировать как флэш-массив или гибридную СХД. Благодаря применению компонентов с возможностью резервирования и горячего подключения SC9000 является отказоустойчивым и простым в развертывании решением с высокой доступностью. Полки расширения SC400/420, SC200/220 или SC280 позволяют наращивать емкость. Система поддерживает унифицированное управление с массивами SC8000, SC4020, SCv2000. Емкость флэш-массива составляет до 46 Тбайт на 1U (без сжатия данных). Такой плотности удалось добиться благодаря применению в СХД трехуровневой памяти Samsung TLC 3D NAND. Система SC9000 предоставляет более 3 Пбайт чистой емкости, причем массивы можно объединять в группы, если рабочим нагрузкам требуются большие объемы хранения. Полки расширения SC280 (а это 96 HDD 3,5”) дают емкость более 100 Тбайт на 1U. Это можно использовать для медиаархивов или в приложениях, работающих с крупными файлами. Программные средства Несмотря на впечатляющие характеристики аппаратной платформы, многими своими качествами SC9000 обязана софту. Виртуализированная программная среда Storage Center с функциями автоматизации делает систему более экономичной и адекватной широкому спектру задач. Сравнение программных средств массивов серии SC. Программное обеспечение Dell Storage Center 7.0, оснащенное новыми функциями, обеспечивает улучшенную поддержку устройств Dell Storage серии SC в частных облачных средах и других критически важных приложениях. Посмотрим, что тут нового. Улучшенная оптимизация для работы с флэш-памятью Принимая во внимание, что высокая стоимость флэш-памяти является основным барьером для принятия этой технологии, Dell сфокусировалась на повышении эффективности использования накопителей, чтобы снизить их стоимость. Об оптимизации заявляют многие вендоры, но часто используется упрощенный подход с одним уровнем хранения, при котором все виды флэш-памяти ведут себя одинаково. Современные технологии виртуализации Dell позволяют использовать различные типы флэш-памяти в одном и том же массиве для запуска различных рабочих нагрузок и различных сценариев применения. Благодаря этому компания смогла выпустить серию высокоскоростных и экономичных массивов как полностью на базе флэш-памяти, так и в гибридном исполнении. В автоматическом тиринге Dell учитываются разные параметры цены/производительности SSD разного типа. То есть для достижения высокой производительности в IOPS не потребуется выложить запредельную сумму. Вот почему у флэш-массивов Dell стоимость хранения составляет всего 0,65 центов за гигабайт. Ну а в гибридных СХД этот показатель еще ниже. Глубокий тиринг, не ограниченный флэш-памятью Чтобы увеличить срок службы памяти 3D NAND, задействован механизм тиринга – перемещения данных между уровнями хранения. Первый уровень (Tier 1) представлен флэш-памятью SLC или eMLC, выдерживающей большое количество циклов перезаписи, второй (Tier 2) – памятью 3D NAND, в которую записываются относительно редко используемые данные, причем в сжатом виде. В некоторых моделях есть и третий уровень (Tier 3) – HDD. Конфигурацию системы (соотношение емкости разных видов флэш-памяти и жестких дисков) можно подбирать с учетом характера нагрузки: для этого есть соответствующая утилита. WI – для интенсивной записи, RI –- для интенсивного чтения Применяемые Dell методы тиринга – одни из самых полных в отрасли. Массивы SC позволяют создавать унифицированные пулы хранения данных SAN и/или NAS из разнородных систем, формировать тома из носителей разного типа (в том числе включать в них Tier 0 – кэш на стороне сервера), задавать гибкие конфигурации RAID. За счет автоматического размещения данных на соответствующем уровне хранения в реальном времени ускоряется «прогрев» данных и их «остывание». Но главное – упрощается управление, и удается выжать все возможное из накопителей с точки зрения производительности. Интеллектуальное размещение данных и оптимизация хранения на всех уровнях. Запатентованная технология автоматического многоуровневого размещения данных использует основные преимущества различных типов накопителей для оптимизации данных на протяжении всего жизненного цикла. Быстрое внедрение новых технологий Та же виртуализация, которая помогает массивам серии SC демонстрировать свои преимущества в соотношении цена/производительность, позволяет внедрять новые решения. Хороший пример – TLC 3D NAND. Выпустив прошлым летом накопители Mainstream Read-Intensive, Dell вдвое снизила стоимость флэш-памяти Tier 2 без уменьшения долговечности или быстродействия. Память TLC успешно применяется в ее массивах старшего класса, в то время как конкуренты все еще пытаются изменить архитектуру одноуровневых систем младшего класса. Быстрое вертикальное и горизонтальное масштабирование для удовлетворения потребностей в хранении данных и производительности. Одновременная вертикальная и горизонтальная масштабируемость делает массивы SC хорошо расширяемыми. Гибкая самооптимизирующаяся система SC9000 позволяет получить более 3 Пбайт чистой емкости и объединять массивы в группы, обеспечивая необходимой емкостью крупные рабочие нагрузки. Массив SC9000 обеспечивает быстрое модульное расширение благодаря поддержке сетей хранения данных (SAN) и сетевых систем хранения данных (NAS). Его также можно подключать к другим массивам серии SC в более крупных федеративных системах с единым управлением. Программное обеспечение SCOS включает в себя опциональный «гипервизор хранения», позволяющий легко перемещать данные по «федерации» массивов. И даже в случае наращивания одного дискового массива можно получить емкость и производительность крупной распределенной системы с унифицированным управлением. Dell Volume Advisor даст рекомендации по проактивному балансированию нагрузки на основе заданных правил. Он осуществляет мониторинг федерации массивов и советует, где лучше разместить данные. Эффективное использование емкости Массивы серии SC с программным обеспечением SCOS 7.0 поддерживают интеллектуальное сжатие данных на флэш-накопителях и HDD. Тем самым достигается значительная экономия емкости. Функция сжатия интегрирована с тирингом, поэтому сжатие не снижает производительности. При этом активны такие функции, как динамическое распределение емкости. Сжатие данных обеспечивает серьезную экономию емкости хранения, что особенно важно для флэш-памяти. За счет сжатия данных, достигающего 93 % в случае с базами данных Microsoft SQL, решение становится еще более экономичным: флэш-массив оказывается сопоставим по цене с дисковым массивом на базе HDD SAS 15k. Сжатие происходит, когда блоки данных перемещаются на нижние уровни, тем самым уменьшается влияние сжатия данных на производительность системы. При перемещении активных блоков на верхние уровни они остаются сжатыми. Постоянная доступность Новая функция SCOS 7.0 под названием Live Volume Auto-Failover предотвращает незапланированные простои. При отказе ПО Storage Center перенаправляет нагрузку на синхронизированные с основным резервные тома на другом массиве и запускает процедуру восстановления. Вмешательства администратора не требуется. Благодаря переназначению хостов можно вносить изменения в СХД, не влияя на работу пользователей и приложений. Прозрачное для сервера перемещение томов между массивами в федеративном кластере повышает эффективность использования кэша и емкости при растущих нагрузках. Еще одна примечательная технология SC9000 – функция автоматической замены сбойного массива Live Volume, позволяющая работать без простоев. Она дает возможность «растягивать» тома между площадками при помощи средств самого дискового массива. В результате создается недорогое катастрофоустойчивое решение, не требующее перестройки архитектуры хранения данных. Функция Live Volume с автоматическим переключением при отказе обеспечивает непрерывную работу системы при перебоях электропитания и автоматически восстанавливает среду высокой доступности при включении массива. Установка дополнительного оборудования или программного обеспечения не требуется. Функция Live Volume на массивах серии SC хорошо подходит для облачных сред. Она обеспечивает восстановление после сбоев и прозрачное автоматическое переключение на полностью синхронизируемые тома на другом массиве серии SC. Интеграция корпоративных приложений На уровне приложений поддерживаются снепшоты в среде Oracle, облачных средах на платформе Microsoft Azure, VMware Metro Stretch Clusters. Функция Azure Site Recovery обеспечивает резервное копирование данных в облачную инфраструктуру Microsoft. Предусмотрена также интегрированная защита сред Oracle, Microsoft и VMware. Набор программ Application Protection Manager обеспечивает целостность данных на сервере в средах баз данных Oracle, VMware и MS. Опциональные твердотельные накопители и жесткие диски с самошифрованием, сертифицированные по стандарту FIPS, защищают данные от кражи, утери или несанкционированного доступа. А встроенные расширенные возможности включают всесторонние «тонкие» методы управления ресурсами системы. В заключение сравним массив с конкурентами: Массив SC9000 — это подходящее решение для крупных систем хранения данных, серьезных нагрузок и распределенных корпоративных сред. Массив SC9000 не просто увеличивает производительность: его интеллектуальная виртуализированная архитектура автоматически оптимизирует финансовые расходы и использование емкости хранения, обеспечивая максимальную экономию. Массивы хранения Dell SC9000 призваны помочь компаниям с крупными центрами хранения и обработки данных увереннее и быстрее достигать важных целей, расходуя меньше средств и времени. Dell предоставляет заказчикам гибкие комплексные решения, способные быстро адаптироваться под меняющиеся потребности, предлагает решение с рекордно низкой стоимостью хранения гигабайта данных на базе твердотельных накопителей благодаря новому типу памяти TLC 3D.

Метки:  

Удаление Code Contracts c помощью Roslyn

Суббота, 25 Июня 2016 г. 14:44 + в цитатник
Что такое Code Contracts Code Contracts были созданы командой разработчиков из Microsoft Research в 2008 году. Задача Code Contracts — описывать предположения о состоянии в коде, которые в последующем используются для генерации документации и проверки кода на корректность. Предполагалось, что Code Contracts станут частью платформы .NET и получат поддержку в компиляторе, платформе и Visual Studio. К сожалению, поддержка появилась только на платформе в виде классов пространства имен System.Diagnostics.Contracts. Для остального требуются плагины и дополнительные утилиты. В данный момент проект поддерживает SergeyT и еще несколько участников. Поддержка Code Contracts в Mono Для проектов, которые разрабатываются на Windows, инфраструктура Code Contracts понятна и более развита. Есть Build Steps для MSBuild, можно переписывать/верифицировать сборки с помощью утилит, есть плагины для VS и Resharper. Но с Mono дела обстоят не так хорошо, есть самодельный ccrewrite, который ломается на сложном коде. Поддержки в xbuild и MonoDevelop нет, и простым способом собрать проект нельзя. Причины для удаления Code Contracts из проекта: — Внешняя зависимость проекта от утилит Code Contracts, без которых проект не собрать. — Скорость компиляции ниже из-за дополнительного шага в виде перезаписи сборки. — Отсутствие поддержки в Mono. — Неудобств стало больше, чем пользы. Удаление Code Contracts из исходного кода Благодаря проекту Roslyn от Microsoft анализ и обработка исходного кода на C#/VB.NET стали довольно тривиальной задачей. И я выбрал этот путь для удаления Code Contracts из исходного кода. Само решение простое и состоит из CSharpSyntaxRewriter, который пробегает по коду и заменяет проверки Code Contracts на их эквивалент вне Code Contracts. Сам удалитель Code Contract'ов оформлен в виде пакета Nuget, доступен как утилита и работает под Mono. Install-Package CodeContractsRemover И команда на перезапись всех исходников в директории проекта: # code_contracts_remover.exe <Convert|Remove> <directoryPath> > Если вы не хотите попрощаться с контрактами навсегда, то можете использовать данную утилиту как шаг сборки на вашем билд сервере. Ссылки Проект на GitHub Nuget пакет

Метки:  

[Из песочницы] Загрузчик для dsPIC33

Пятница, 24 Июня 2016 г. 19:58 + в цитатник
Загрузчик (bootloader) — очень удобный инструмент работы с микроконтроллерами (далее — МК). Это маленькая программа, которая позволяет МК «самопрограммироваться» (self-programming). Обычно, при подаче питания на МК, управление сначала получает загрузчик, которые проверят заранее заданные условия (определенное состояние на ножке МК, флаг в EEPROM, подходящий файл прошивки на SD-карте и т.д.). Если условия не выполняются, то управление передается основной программе. Если же условия выполняются, то загрузчик переключается в режим программирования, получая данные новой прошивки по предопределенному интерфейсу. Это позволяет обновить прошивку МК не прибегая к паяльнику, программатору или внутрисхемному программированию. Обычный алгоритм использования загрузчика для МК, только что вынутого из упаковки: с помощью программатора/отладчика прошивается загрузчик МК монтируется в плату используя загрузчик по заранее определенному интерфейсу загружается основная прошивка Это вполне приемлемо для опытных образцов изделий или для мелкосерийного производства. А что делать, если производство крупносерийное? Или сборка проводится автоматами (а может людьми с функционалом автоматов) — прошил, впаял? Тогда разумно убрать из алгоритма 3го пункт — объединить в одной прошивке и основную программу и загрузчик. В своей практике я столкнулся с довольно жутким методом получения такой прошивки — в HEX-файл основной прошивки просто дописывался HEX-файл с кодом загрузчика. Конечно. такой подход имеет право быть — как ни крути, но итоговые «прошивки имени др. Франкенштейна» работали как надо. Но чувство, что для решения этой задачи должны быть более корректные методы, меня не оставляло. Когда Я поискал решения в Интернете, то был неприятно удивлен, что простого и понятного описания решения нет. Собственно, именно это побудило меня написать публикацию, описывающую мое решение этой ситуации. Возможно мое видение решения этой проблемы отличается от максимально правильного, но оно гораздо более логичней, чем сшивание HEX-файлов. Прежде чем перейти к самой теме публикации, хочу привести список упрощений и инструментов, которые были использованы: MPLAB IDE v8.85 (да, весьма устаревшая IDE) Microchip C30 Toolsuite v3.12 объектные файлы в формате COFF (т.е. по умолчанию для этого toolchain-a) расположение загрузчика и основной программы статичны загрузчик располагается с адреса 0х0400 основная программа располагается с адреса 0х2000 память по адресам с 0х0200 по 0х0400 — неиспользуемая И самое главное — конкретных исходников загрузчика в это публикации не будет. Компоновка загрузчика в основной проект Просто скомпилировать… Начнем с самого простого случая. Добрый Дедушка Мороз прислал Вам на Новый Год готовый загрузчик. Причем он уже потрудился на славу и скомпилировал и скомпоновал его для Вас. Итак, у Вас в руках (на флешке/в сети/на жестком диске) есть файлик – UltraBoot3000.blob. Дальше алгоритм очень простой – просто добавь его к себе в проект. Касаемо MPLAB IDE его надо добавить в категорию «Object Files». К сожалению, по умолчанию в эту категорию можно добавить только файлы с расширением «o». Отмечу так же, что файлы с расширением «o» получаются так же в процессе компиляции Вашей программы. Чтобы нечаянно не перепутать и не забыть о файле загрузчика, рекомендую держать его с другим расширением, например blob – binary linked object. Чтобы IDE положило файл blob в категорию «Object Files», этой категории нужно скорректировать настройки фильтров. Жмем правой кнопкой мыши на этой категории и выбираем пункт «Filter…». В появившемся окне в поле через точку-с-запятой дописываем необходимый нам шаблон фильтра. В нашем случае в поле должно быть в итоге следующее описание фильтров: *.o;*.blob После настройки фильтров можно добавить файл загрузчика в проект. Запускаем процесс компи… НЕТ! СТОП! Чтобы корректно собрать прошивку с нашим загрузчиком, нужен правильный скрипт компоновщика. Конечно, если Дедушка Мороз был настолько добр, что и этот скрипт Вам прислал, то просто добавляем его себе в проект (MPLAB IDE поддерживает файлы с расширением «gld»), запускаем процесс сборки проекта и на выходе получаем корректный файл прошивки с уже встроенным кодом загрузчика. Но что делать, если Дедушка забыл про это скрипт или может быть именно Вы и являетесь тем, кто сделал этот загрузчик и Вам надо встроить его в свой/чужой проект? Читаем дальше… Подготовка скрипта компоновщика Собственно не стоит писать скрипт с нуля. Достаточно чуть-чуть переделать скрипт, который устанавливается в комплекте с компилятором. Лежит этот скрипт в папке «${ToolChainPath}\support\dsPIC33F\gld\». Примечание: здесь и далее ${ToolChainPath} – это путь, куда был установлен компилятор С30, по умолчанию это – «c:\Program Files\Microchip\MPLAB C30\». Скопируем оттуда скрипт по умолчанию для нашего устройства, например для МК dsPIC33FJ128GP802 это будет файл «p33FJ128GP802.gld». Первым делом надо вписать два символа, описывающих начало области загрузчика и основной программы. Например, так: _Booter = 0x000400; _mainFW = 0x002000; Далее в структуре MEMORY {…} в поле program указать начальную позицию (origin) и длину (length), соответствующие началу загрузчика и размеру flash-памяти минус начало загрузчика. Примерно так: program (xr) : ORIGIN = 0x400,LENGTH = (0x15800 - 0x400) Следующим шагом будет корректировка вектора сброса. В структуре SECTIONS {…} найдем описание «Reset Instruction». Необходимо чтобы она выглядела следующим образом: .reset : { SHORT(ABSOLUTE(_Booter)); SHORT(0x04); SHORT((ABSOLUTE(_Booter) >> 16) & 0x7F); SHORT(0); } >reset Осталось только добавить описание зоны загрузчика. Зона описывается в структуре SECTIONS {…}. Это описание необходимо вставить перед описанием зоны «.text». Описание следующее: .boot _Booter : { *(.booter); . = _mainFW - _Booter; } >program = 0xFFFF Итак, скрипт готов. Создание загрузчика Сделать загрузчик из программы Первое, что хотелось бы отметить: загрузчик не должен быть самостоятельной программой. Конечно, в процессе отладки загрузчика его можно реализовать как самостоятельную программу. Но как только Вы планируете его встроить в другую программу его необходимо специально подготовить. Итак, чего лишается программа, превращаясь в загрузчик: Описание конфигурационных бит Векторов прерываний Вектора сброса Кроме этого, невозможно корректно встроить константы загрузчика, хранимые во flash-памяти, в код основной программы. Поэтому от них тоже придется отказаться. Примечание: на самом деле способ есть, но он настолько нетривиален, что для массового использования проще отказать от констант в загрузчике. Доработка исходных текстов Доработка несложная. Убираем все макросы, описывающие конфигурационные биты. Исключаем использование глобальных констант. Настройка проекта Так же необходимо проверить и, при необходимости, скорректировать настройки проекта. Все изменения – во вкладке «MPLAB LINK30», категория «General». Установить чек-боксы: don’t pack data template; don’t create hanldes; don’t create default ISR; remove unused sections. Доработка скрипта компоновщика Так же как и для основной программы с загрузчиком скрипт будет отличным от скрипта по умолчанию. Итак, берем скрипт по умолчанию и вносим следующие изменения. Структуру MEMORY {…} уменьшаем до двух позиций: data и program. Причем начало и длина program соответствуют началу и длине области загрузчика: { data (a!xr) : ORIGIN = 0x800, LENGTH = 0x4000 program (xr) : ORIGIN = 0x400, LENGTH = 0x1C00 } Удаляем полностью описание «Reset Instruction» в структуре SECTIONS {…}. В этой же структуре удаляем описание «Configuration Words». Полностью удаляем структуру SECTIONS {…}, которая описывает вектора прерываний (метка «Section Map for Interrupt Vector Tables»). В структуре SECTIONS {…} дорабатываем описание зоны «.text», заменив название зоны на «.booter» и приведя ее к следующему виду: .booter 0x400 : { *(.init); *(.user_init); *(.handle); *(.libc) *(.libm) *(.libdsp); /* keep together in this order */ *(.lib*); *(.dinit); *(.text); } >program Естественно, полученный скрипт надо добавить в проект. Постобработка выходного файла После осуществления предыдущих действий можно запустить процесс компиляции. В выводе процесса сборки (для MPLAB IDE это будет в окне Output, вкладка Build) можно увидеть результат компоновки. Например, так: Program Memory [Origin = 0x400, Length = 0x1c00] section address length (PC units) length (bytes) (dec) ------- ------- ----------------- -------------------- .booter 0x400 0x7d0 0xbb8 (3000) Total program memory used (bytes): 0xbb8 (3000) 27% Data Memory [Origin = 0x800, Length = 0x4000] section address alignment gaps total length (dec) ------- ------- -------------- ------------------- .nbss 0x800 0 0xa2c (2604) bootdata 0x47c0 0 0x40 (64) Total data memory used (bytes): 0xa6c (2668) 16% Если в program memory больше одной секции – то скорей всего вы не до конца выполнили действия описанные выше. Если там именно одна секция с названием «.booter» — то все сделано правильно. Также надо обратить внимание на количество секций в data memory. Теперь надо выполнить постобработку выходного файла. Постобработка проводиться с файлом с расширением «cof». Открываем командную строку в папке с этим файлом. Допустим файл имеет имя ultraboot.cof, тогда выполним команду: "${ToolChainPath}\bin\pic30-strip.exe" -s > Не забываем ${ToolChainPath} заменять на реальный путь. Количество опций > Далее надо провести финальную проверку полученного бинарного файла с загрузчиком. Команда: "${ToolChainPath}\bin\pic30-objdump.exe" -ht ultraboot.blob Вывод будет примерно следующим: ultraboot.blob: file format coff-pic30 Sections: Idx Name Size VMA LMA File off Algn 0 .booter 000007d0 00000400 00000400 00000058 2**1 CONTENTS, ALLOC, LOAD, CODE SYMBOL TABLE: no symbols Если вы увидите, что секций ровно одна — с названием «.booter» и в символьной таблице нет символов, то можно считать, что все сделано корректно. И в конце ссылки на примеры файлов для линкера: для основного проекта с загрузчиком — drive.google.com/file/d/0B063O4zepkwsNDlCMkJ1S1ZxaE0/view?usp=sharing для загрузчика — drive.google.com/file/d/0B063O4zepkwsZU9Nck42cVoyWDA/view?usp=sharing

Введение в ReactiveUI: коллекции

Четверг, 23 Июня 2016 г. 19:35 + в цитатник
Привет, Хабр! Часть 1: Введение в ReactiveUI: прокачиваем свойства во ViewModel В предыдущей статье мы поговорили про свойства во ViewModel, и что мы можем с ними сделать, используя ReactiveUI. У нас получилось привести в порядок зависимости между свойствами и собрать в одном месте вьюмодели информацию о том, какие в ней есть зависимости между свойствами. В этот раз еще немного поговорим о свойствах, а затем перейдем к коллекциям. Попробуем понять, какие проблемы есть с обычными коллекциями, и зачем было создавать новые, с уведомлениями об изменениях. И, конечно, попробуем их использовать. Несколько слов о свойствах Прежде чем перейти к основной теме, скажу еще пару слов по поводу свойств. В прошлый раз мы пришли к следующему синтаксису: private string _firstName; public string FirstName { get { return _firstName; } set { this.RaiseAndSetIfChanged(ref _firstName, value); } } Тратить 6 строк кода на каждое свойство — довольно расточительно, особенно если таких свойств много и реализация всегда одинаковая. В языкe C# для решения этой проблемы в свое время добавили автосвойства, и жить стато легче. Что мы можем сделать в нашем случае? В комментариях был упомянут Fody — средство, которое может изменять IL-код после сборки проекта. Например, в реализацию автосвойства добавить уведомление об изменении. И для ReactiveUI даже есть соответствующее расширение: ReactiveUI.Fody. Попробуем использовать его. Кстати, для классической реализации тоже есть расширение: PropertyChanged, но нам оно не подходит, поскольку нужно вызывать именно RaiseAndSetIfChanged(). Установим из NuGet: > Install-Package ReactiveUI.Fody В проекте появится FodyWeavers.xml. Добавим в него установленное расширение: <?xml > И изменим наши свойства: [Reactive] public string FirstName { get; set; } С помощью данного инструмента можно также реализовать свойство FullName на базе ObservableAsPropertyHelper<>. Способ описан в документации на GitHub, здесь же опустим его. Я думаю, что две строки — вполне приемлимый вариант, и не очень хочу использовать вместо ToProperty() сторонний метод, позволяющий ReactiveUI.Fody реализовать это свойство правильно. Проверим, что ничего не сломалось. Как? Я проверяю юнит-тестами. ReactiveUI к ним дружелюбен, не зря он A MVVM framework <...> to create elegant, testable User Interfaces.... Чтобы проверить срабатывание эвента, необязательно подписываться на него руками, куда-то сохранять данные при срабатывании и потом обрабатывать их. Нам поможет Observable.FromEventPattern(), который превратит срабатывания эвента в IObservable<> со всей необходимой информацией. А чтобы превратить IObservable<> в список событий и проверить его на правильность, удобно использовать метод расширения .CreateCollection(). Он создает коллекцию, в которую то тех пор, пока источник не вызовет OnComplete() или мы не вызовем Dispose(), будут добавляться пришедшие через IObservable<> элементы, в нашем случае — информация о сработавших эвентах. Заметьте, что коллекция нам возвращается сразу, а элементы в нее добавляются уже потом, асинхронно. Это поведение отличается от, например, .ToList(), который не вернет управление и, следовательно, саму коллекцию до OnComplete(), что чревато вечным ожиданием в случае обычной подписки на эвент. [Test] public void FirstName_WhenChanged_RaisesPropertyChangedEventForFirstNameAndFullNameProperties() { var vm = new PersonViewModel("FirstName", "LastName"); var evendObservable = Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>( a => vm.PropertyChanged > Сам тестируемый сценарий (задание нового значения свойству) выполняется внутри using, а проверки — после. Это нужно для того, чтобы при проверке случайно не сработал какой-то эвент и не испортил нам коллекцию. Конечно, делать это зачастую необязательно, но иногда может быть важно. А теперь давайте проверим, что IObservable<> Changed вернет то же самое. [Test] public void FirstName_WhenChanged_PushesToPropertyChangedObservableForFirstNameAndFullNameProperties() { var vm = new PersonViewModel("FirstName", "LastName"); var notifications = vm.Changed.CreateCollection(); using (notifications) { vm.FirstName = "NewFirstName"; } Assert.That(vm.FullName, Is.EqualTo("NewFirstName LastName")); Assert.That(notifications, Has.Count.EqualTo(2)); Assert.That(notifications[0].Sender, Is.SameAs(vm)); Assert.That(notifications[0].PropertyName, Is.EqualTo(nameof(PersonViewModel.FirstName))); Assert.That(notifications[1].Sender, Is.SameAs(vm)); Assert.That(notifications[1].PropertyName, Is.EqualTo(nameof(PersonViewModel.FullName))); } И… Тест упал. Но мы же только поменяли источник информации об измении свойства! Попробуем понять, почему тест не прошел: vm.Changed.Subscribe(n => Console.WriteLine(n.PropertyName)); vm.FirstName = "OMG"; И получаем: FullName FirstName Вот так. Не похоже, что это ошибка фреймворка, скорее, деталь реализации. Это можно понять: оба свойсва уже изменились и порядок уведомления неважен. С другой стороны — он несогласован с порядком эвентов и не соответствует ожиданиям, что может быть чревато. Конечно, строить логику приложения, опираясь на порядок уведомлений — заведомо плохая идея. Но, например, при чтении лога приложения мы увидим, что зависимое свойство уведомило об измении ДО изменения его зависимости, что может сбить с толку. Так что обязательно запомним такую особенность. Итак, мы убедились, что ReactiveUI.Fody работает исправно и существенно уменьшает количество кода. Дальше будем использовать его. А теперь перейдем к коллекциям Интерфейс INotifyPropertyChanged, как мы знаем, используется при изменении свойств вьюмодели, например, для уведомления визуального элемента о том, что что-то изменилось и надо перерисовать интерфейс. Но что делать, когда во вьюмодели есть коллекция из множества элементов (например, лента новостей), и нам надо добавить свежие записи к уже показанным? Уведомлять о том, что свойство, в котором лежит коллекция, изменилось? Можно, но это приведет к перестроению всего списка в интерфейсе, а это может быть небыстрой операцией, особенно если речь идет о мобильных устройствах. Нет, так дело не пойдет. Нужно, чтобы коллекция сама сообщала, что в ней что-то поменялось. К счастью, есть замечательный интерфейс: public interface INotifyCollectionChanged { /// <summary>Occurs when the collection changes.</summary> event NotifyCollectionChangedEventHandler CollectionChanged; } Если коллекция его реализует, то при добавлении/удалении/замене и т.п. событиях срабатывает CollectionChanged. И теперь не надо перестраивать список новостей заново и вообще заглядывать в коллекцию записей, достаточно просто дополнить его новыми элементами, которые пришли через эвент. В .NET есть реализующие его коллекции, но мы говорим про ReactiveUI. Что есть в нем? Целый набор интерфейсов: IReactiveList<T>, IReadOnlyReactiveList<T>, IReadOnlyReactiveCollection<T>, IReactiveCollection<T>, IReactiveNotifyCollectionChanged<T>, IReactiveNotifyCollectionItemChanged<T>. Не буду приводить здесь описание каждого, думаю, по названиям должно быть ясно, что они из себя представляют. А вот на реализацию посмотрим подробнее. Знакомьтесь: ReactiveList<T>. Он реализует их всех и много чего другого. Так как нас интересует отслеживание изменений в коллекции, посмотрим на соответствующие свойства этого класса. Довольно много! Отслеживается добавление, удаление, перемещение элементов, количество элементов, пустота коллекции и необходимость сделать сброс. Рассмотрим это все подробнее. Конечно, реализованы также эвенты из INotifyCollectionChanged, INotifyPropertyChanged и парных им *Changind, но про них говорить не будем, они работают бок-о-бок с «наблюдаемыми» свойствами, показанными на картинке, и чего-то уникального там нет. Для начала простой пример. Подпишемся на некоторые источники уведомлений и немного поработаем с коллекцией: var list = new ReactiveList<string>(); list.BeforeItemsAdded.Subscribe(e => Console.WriteLine($"Before added: {e}")); list.ItemsAdded.Subscribe(e => Console.WriteLine($"Added: {e}")); list.BeforeItemsRemoved.Subscribe(e => Console.WriteLine($"Before removed: {e}")); list.ItemsRemoved.Subscribe(e => Console.WriteLine($"Removed: {e}")); list.CountChanging.Subscribe(e => Console.WriteLine($"Count changing: {e}")); list.CountChanged.Subscribe(e => Console.WriteLine($"Count changed: {e}")); list.IsEmptyChanged.Subscribe(e => Console.WriteLine($"IsEmpty changed: {e}")); Console.WriteLine("# Add 'first'"); list.Add("first"); Console.WriteLine("\n# Add 'second'"); list.Add("second"); Console.WriteLine("\n# Remove 'first'"); list.Remove("first"); Получаем результат: #Add 'first' Count changing: 0 Before added: first Count changed: 1 IsEmpty changed: False Added: first #Add 'second' Count changing: 1 Before added: second Count changed: 2 Added: second #Remove 'first' Count changing: 2 Before removed: first Count changed: 1 Removed: first Нас уведомляют о том, что добавлено или удалено, а также об изменении количества элементов и признака пустоты коллекции. Притом: — ItemsAdded/ItemsRemoved/BeforeItemsAdded/BeforeItemsRemoved возвращают сам добавленый/удаленный элемент — CountChanging/CountChanged возвращают количество элементов до и после изменения — IsEmptyChanged возвращает новое значение признака пустоты коллекции Есть одна тонкость Пока все предсказуемо. Теперь представим, что мы хотим только на основе уведомлений о добавлении и удалении считать количество записей в коллекции. Что может быть проще? var count = 0; var list = new ReactiveList<int>(); list.ItemsAdded.Subscribe(e => count++); list.ItemsRemoved.Subscribe(e => count--); for (int i = 0; i < 100; i++) { list.Add(i); } for (int i = 0; i < 100; > Тест прошел успешно. Изменим принцип заполнения коллекции, добавим сразу много элементов: list.AddRange(Enumerable.Range(0, 10)); list.RemoveAll(Enumerable.Range(0, 5).Select(i => i * 2)); Успешно. Кажется, подвохов нет. Хотя стойте… list.AddRange(Enumerable.Range(0, 100)); list.RemoveAll(Enumerable.Range(0, 50).Select(i => i * 2)); Ой! Тест не прошел и count > Все дело в том, что ReactiveList<T> реализован не так примитивно, как может показаться. Когда коллекция меняется существенно, он отключает уведомления, делает все изменения, включает уведомления обратно и посылает сигнал сброса: list.ShouldReset.Subscribe(_ => Console.WriteLine("ShouldReset")); Зачем так сделано? Иногда коллекция меняется существенно: например, в пустую коллекцию добавляется 100 элементов, из большой коллекции удаляется половина элементов или происходит ее полная очистка. В таком случае реагировать на каждое мелкое изменение нет смысла — это будет затратнее, чем дождаться конца серии изменений и отреагировать так, будто коллекция полностью новая. В последнем примере так и происходит. ShouldReset имеет тип IObservable<Unit>. Unit — это по сути void, только в форме объекта. Он используется в ситуациях, когда нужно уведомить подписчика о неком событии, и важно только то, что оно произошло, передавать какие-то дополнительные данные не требуется. Как раз наш случай. Если бы мы на него подписались, то увидели бы, что после операций вставки и удаления нам пришел сигнал сброса. Соответственно, чтобы обновлять счетчик правильно, надо чуть-чуть изменить наш пример: list.ItemsAdded.Subscribe(e => count++); list.ItemsRemoved.Subscribe(e => count--); list.ShouldReset.Subscribe(_ => count = list.Count); Теперь тест проходит и все снова замечательно. Просто не нужно забывать о том, что некоторые уведомления могут и не придти, и обрабатывать эти ситуации. И, конечно, не забывать тестировать такие вот ситуации, когда коллекции сильно меняются. Правила подавления уведомлений об изменениях Мы увидели, что при сильном изменении коллекции возникает сигнал сброса. Как можно контролировать этот процесс? В конструкторе ReactiveList<T> есть один необязательный аргумент: double resetChangeThreshold = 0.3. И уже после создания списка его можно изменить через свойство ResetChangeThreshold. Как он используется? Уведомления об изменениях будут подавлены, если результат деления количества добавляемых/удаляемых элементов на количество элементов в самой коллекции больше этого значения, и если при этом количество добавляемых/удаляемых элементов строго больше 10. Это видно по исходному коду и никто не гарантирует, что эти правила не поменяются в будущем. В нашем примере 100/0 > 0.3 и 50/100 > 0.3, поэтому уведомления были подавлены оба раза. Естественно, можно варьировать ResetChangeThreshold и подставивать коллекцию под конкретное место использования. Как нам самим подавить уведомления? В первом примере со счетчиком мы видели такой код: for (int i = 0; i < 100; i++) { list.Add(i); } Здесь элементы добавляются по-одному, поэтому уведомления об изменении всегда отправляются. Но мы добавляем много элементов и хотим на время подавить уведомления. Как? Использовав SuppressChangeNotifications(). Все, что находится внутри using, не будет вызывать уведомлений об изменении: using (list.SuppressChangeNotifications()) { for (int i = 0; i < 100; i++) { list.Add(i); } } А что насчет изменений самих элементов коллекции? Мы видели, что в ReactiveList<T> есть источники уведомлений ItemChanged и ItemChanging — изменения самих элементов. Попробуем их использовать: var list = new ReactiveList<PersonViewModel>(); list.ItemChanged.Subscribe(e => Console.WriteLine(e.PropertyName)); var vm = new PersonViewModel("Name", "Surname"); list.Add(vm); vm.FirstName = "NewName"; Ничего не произошло. Нас обманули, и ReactiveList на самом деле не следит за изменением элементов? Да, но только по-умолчанию. Чтобы он отслеживал изменения внутри своих элементов, надо просто включить эту фичу: var list = new ReactiveList<PersonViewModel>() { ChangeTrackingEnabled = true }; Теперь все работает: FullName FirstName Кроме того, ее можно включать и выключать по ходу работы. При выключении существующие внутренние подписки на элементы удалятся, при включении — создадутся. Естественно, при добавлении/удалении элементов подписки тоже удаляются и добавляются. Наследуемые коллекции Как часто возникают ситуации, когда нужно из существующей коллекции выбрать только часть элементов, или отсортировать их, или преобразовать? И при изменении исходной коллекции поменять зависимую. Такие ситуации нередки, и в ReactiveUI есть средство, которое позволяет это легко сделать. Имя ему — DerivedCollection. Они наследуются от ReactiveList и, следовательно, возможности имеют те же самые, за исключением того, что при попытках изменить такую коллекцию будет выбрасываться исключение. Коллекция может поменяться только тогда, когда меняется ее базовая коллекция. Не будем снова рассматривать уведомления об изменениях, там все как и было. Посмотрим, какие преобразования можно применить к базовой коллекции. var list = new ReactiveList<int>(); list.AddRange(Enumerable.Range(1, 5)); var derived = list.CreateDerivedCollection( selector: i => i*2, filter: i => i % 2 > Видим, что можно преобразовать значение, отфильтровать исходные элементы (до преобразования!) и передать компаратор для преобразованных элементов. Притом обязателен только селектор, остальное — по желанию. Также есть перегрузки метода, которые позволяют использовать в качестве базовой коллекции не только INotifyCollectionChanged, но и даже IEnumerable<>. Но тогда надо предоставить наследуемой коллекции способ получить сигнал сброса. Здесь наследуемая коллекция берет из исходной нечетные элементы, удваивает их значение и сортирует от большего к меньшему. В консоли будет: 1, 2, 3, 4, 5 10, 6, 2 1, 2, 3, 4, 5, 2, 3, 4 10, 6, 6, 2 Stay tuned В этот раз мы обсудили некоторые подробности работы со свойствами, не описанные в прошлой части. Добились того, чтобы реализация свойства занимала одну строку, и выяснили, что нельзя верить порядку уведомлений об их изменении. Основной же темой были коллекции. Мы разобрались, какие уведомления можно получить от ReactiveList при его изменении. Выяснили, зачем и при каких условиях уведомления подавляются автоматически, а также как подавить их собственными руками. Наконец, мы попробовали использовать наследуемые коллекции и убедились, что они умеют фильтровать, преобразовывать и сортировать данные базовой коллекции, реагируя на ее изменения. В следующей части поговорим про команды и рассмотрим вопрос тестирования вьюмодели. Выясним, какие проблемы с этим связаны и как они решаются. А потом перейдем к связке View + ViewModel и попробуем реализовать небольшое приложение с GUI, использующее уже описанные средства. До встречи!

Метки:  

Поиск сообщений в predefglas
Страницы: [2] 1 Календарь