Як Windows 10 збирає дані про користувачів

Інформація про те, що Windows 10 збирає дані про користувачів, не нова. Ще в 2014 році компанія Microsoft опублікувала заяву про конфіденційність, з якої випливає, що на її сервери може передаватись інформація про використання програм, пристроїв та мережі, в яких вони працюють. Ці дані можуть закріплюватись за певним ідентифікатором користувача (обліковий запис Microsoft), а також до цих даних додається інфо про адресу електронної пошти, переваги, інтереси, місцезнаходження, і багато іншого.

Чеське видання Aeronet.cz опублікувало розслідування невідомого ІТ-фахівця, який вирішив відстежити активність Windows 10 по збору даних. У ході дослідження використовувалися такі інструменти: програма Destroy Windows 10 Spying, що блокує передачу даних на сервери Microsoft, PRTG Network Monitor, Windows Resource Monitor и Wireshark. На думку дослідника, Windows 10 – більше схожа на термінал по збору даних, ніж на класичну операційну систему.

Cortana хоче знати про користувача все

Найбільш активним «збирачем» даних в новій ОС є голосовий помічник Cortana. Експеримент чеського дослідника показав, що всі голосові запити, передані в динамік пристрою, Windows 10 відправляє на такі сервери:
vortex.data.microsoft.com
vortex-win.data.microsoft.com
telecommand.telemetry.microsoft.com
telecommand.telemetry.microsoft.com.nsatc.net
oca.telemetry.microsoft.com
oca.telemetry.microsoft.com.nsatc.net
sqm.telemetry.microsoft.com
sqm.telemetry.microsoft.com.nsatc.net
watson.telemetry.microsoft.com
watson.telemetry.microsoft.com.nsatc.net
redir.metaservices.microsoft.com
choice.microsoft.com
choice.microsoft.com.nsatc.net
df.telemetry.microsoft.com
reports.wes.df.telemetry.microsoft.com
wes.df.telemetry.microsoft.com
services.wes.df.telemetry.microsoft.com
sqm.df.telemetry.microsoft.com
telemetry.microsoft.com
watson.ppe.telemetry.microsoft.com
telemetry.appex.bing.net
telemetry.urs.microsoft.com
telemetry.appex.bing.net:443
settings-sandbox.data.microsoft.com
vortex-sandbox.data.microsoft.com
survey.watson.microsoft.com
watson.live.com
watson.microsoft.com
statsfe2.ws.microsoft.com
corpext.msitadfs.glbdns2.microsoft.com
compatexchange.cloudapp.net
cs1.wpc.v0cdn.net
a-0001.a-msedge.net
statsfe2.update.microsoft.com.akadns.net
sls.update.microsoft.com.akadns.net
fe2.update.microsoft.com.akadns.net
diagnostics.support.microsoft.com
corp.sts.microsoft.com
statsfe1.ws.microsoft.com
pre.footprintpredict.com
i1.services.social.microsoft.com
i1.services.social.microsoft.com.nsatc.net
feedback.windows.com
feedback.microsoft-hohm.com
feedback.search.microsoft.com
rad.msn.com
preview.msn.com
ad.doubleclick.net
ads.msn.com
ads1.msads.net
ads1.msn.com
a.ads1.msn.com
a.ads2.msn.com
adnexus.net
adnxs.com
az361816.vo.msecnd.net
az512334.vo.msecnd.net

При цьому, дослідник зауважив, що інформація відправляється на сервери один раз в 15 хвилин (порціями приблизно по 80 мегабайт). Це занадто багато для метаданих, тому він припустив, що спочатку Cortana перетворює голосові записи в текст, а вже потім відправляє на сервери Microsoft ще й WAV-файли з голосом (включаючи записи розмов через SIP). Зібрана текстова інформація зберігається всередині вбудованого в Cortana блокноту.

Якщо заборонити комунікацію з серверами з вищевказаного списку через файл хостів, то надалі програма буде видавати помилки.

Крім того, деякі користувачі вже встигли поскаржитися на те, що Cortana продовжує працювати у фоновому режимі, навіть якщо її відключити в налаштуваннях.

Крім того, як з’ясували журналісти видання Ars Technica, якщо користувач відключить функцію пошуку в інтернеті з меню «Пуск», здійснення такого пошуку все одно призведе до відправки запиту на сервер Bing, який поверне файл threshold.appcache, в якому також міститься певна інформація Cortana, включаючи ID-пристроїв, що зберігається при перезавантаженні.

На даний момент віртуальний помічник розуміє тільки англійську мову, а Microsoft запевняє, що вся зібрана ним інформація надійно захищена. Однак компанія з Редмонда також заявляє, що за запитом відповідних державних органів, дані можуть бути передані їм.

Для того, щоб передавати менше персональних даних, користувач може не пов’язувати Windows 10 з обліковим записом Microsoft. У такому випадку Cortana не працюватиме, але пошук буде функціонувати.

Навіть чати з шифруванням не захищають текст

Також ОС відстежує пошукові запити користувача, аналізує поштове листування, щоб дізнатися переваги і розклад власника комп’ютера. Крім того, дані також передаються і пошуковій системі Bing.

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

oca.telemetry.microsoft.com.nsatc.net
pre.footprintpredict.com
reports.wes.df.telemetry.microsoft.com

Сервер телеметрії збирає інформацію про географічне положення, IP-адресу, Footprintpredict далі передає дані пошуковій системі Bing. При цьому використовується не тільки інформація, введена безпосередньо в браузері, але і, наприклад, взята з чатів – Windows 10 може «перехоплювати» введення даних з будь-якого встановленого додатка. Таким чином, якщо користувач в розмові в месенджері згадає про те, що збирається у відпустку, після в браузері Edge йому буде показуватися відповідна реклама. Оскільки перехоплюється введення з клавіатури, то навіть при спілкуванні через захищені месенджери, ОС може бачити, що вводить користувач (але не бачить, що йому прислали у відповідь).

За заявою дослідника, йому вдалося виявити ще одну цікаву особливість Windows 10 – якщо де-небудь в ОС надрукувати назву відомого американського фільму, то система здійснює відповідний пошук на жорсткому диску і індексує мультимедійні дані. Індексний файл потім відправляється на сервери Microsoft:

df.telemetry.microsoft.com
reports.wes.df.telemetry.microsoft.com
cs1.wpc.v0cdn.net
vortex-sandbox.data.microsoft.com
pre.footprintpredict.com

При цьому, назви іноземних фільмів (наприклад, чеських) не приводили до подібної активності ОС, також система не вивчає вміст файлів, тому якщо назвати файл з фільмом будь-яким іншим словом, то він не буде проіндексований. Дослідник у своїй статті припустив, що ця функціональність в майбутньому може бути використана для пошуку контрафактного контенту або створення націлених рекламних оголошень про покупку фільмів.

Веб-камера теж передає дані

Після активації ОС Windows 10 і після першого запуску веб-камери вона відправляє близько 35 мегабайт даних на такі сервери:

ca.telemetry.microsoft.com
oca.telemetry.microsoft.com.nsatc.net
vortex-sandbox.data.microsoft.com
i1.services.social.microsoft.com
i1.services.social.microsoft.com.nsatc.net

Дослідник помітив тільки один випадок відправки даних веб-камерою, але припускає, що можливо вона відправляє інформацію з довгим інтервалом (дні або тижні). У своєму матеріалі він заявляє про те, що не знає, для чого конкретно може використовуватись інформація з веб-камери, але враховуючи, що ОС Windows – це система, що застосовується в багатьох навіть найбільших міжнародних компаніях, подібна функціональність потенційно може призводити до витоку важливих даних.

Усі дані, що передаються на сервери Microsoft, зашифровані, тому зрозуміти, що конкретно відправляє система без взлому шифрування, просто неможливо.

Журналісти Ars Technica відключили передачу телеметрії за допомогою групових політик, але система все одно періодично посилала інформацію на сервер ssw.live.com

Представники Windows заявили виданню, що Windows 10 збирає тільки інформацію, яка допоможе в майбутньому поліпшити надані користувачам сервіси. Тим не менше, не всі користувачі раді тому, що система продовжує щось відправляти на сервери Microsoft, навіть якщо їй заборонити це робити, і намагаються вирішити цю проблему самостійно, створивши відповідні інструменти. Так на GitHub викладений код програмиDisableWinTracking, яка «використовує деякі відомі способи відключення стеження в Windows 10».

Налагоджуємо комунікацію між клієнтом і UX: як уникнути зіпсованого телефону

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

  • Бізнес — завжди думає про досягнення своїх KPI, але рідко розуміє складність розроблюваної системи і зручність для користувачів.
  • UX-проектувальник — завжди думає про користувача, іноді на шкоду бізнесу. Не завжди явно розуміє мету бізнесу і намагається нав’язувати свої ідеї.
  • Розробник — думає, як зробити все класно з точки зору архітектури системи і програмного коду. Намагається приміряти користувальницькі сценарії на себе, але є технічно підкованим людиною, що не властиво для більшості користувачів.

Якщо про передачу вимог від рівня бізнесу до системного рівня сказано чимало і виробився певний інструментарій, то ось які артефакти використовувати для взаємодії і передачі знань між бізнесом, аналітиком та UX-проектуванням — питання відкрите. Цією темою я продовжую цикл статей з бізнес-аналізу в розробці мобільного.

У нас успіхом проекту вважається не тільки добре написане додаток, який містить в собі 0 критичних дефектів і реалізує все, що потрібно бізнесу, але й добре продумана логіка взаємодії користувача з додатком, якість підготовленої дизайн-концепції, яка буде залучати клієнтів. Роль бізнес-аналітика в компанії з’явилася відносно недавно, якщо брати до уваги інші напрямки (такі як розробка дизайн). Процес притирання був хворобливим, зі сльозами і соплями.

Часто виникали проблеми такого характеру:

  • Вимоги дуже детальні і не дають простору, щоб розвернутися. В результаті ми часто отримували дизайн, який відрізнявся від затверджених замовником вимог. Іноді замовник був цьому радий. Адже красиві дизайн-концепції, оформлені відповідним чином, набагато більш наочні і зрозуміліше, ніж набір хитромудрих бізнес-процесів, які транслюються в сценарії.
  • Вимог недостатньо, щоб підготувати дизайн. В результаті ми отримували затримки по термінах, зрушування віх за проектами, постійний сварки між бізнес-аналітиком і дизайнером, які відстоювали різні точки зору бізнесу і користувачів. Ми повинні розуміти, що у всьому має бути компроміс. Бізнес-цілі досягаються за рахунок реалізації користувацьких цілей. Якщо користувачеві додаток цікаво, то він буде сприяти нам у досягненні цілей бізнесу.

Для того, щоб взаимодейтсвие між BA, UX-проектуванням і кінцевим клієнтом проходилло гладко й ефективно, ми використовуємо набір артефактів.

Установча зустріч між дизайнерами, аналітиками, PM-ами

На самому початку наше завдання зрозуміти, як ми будемо рухатися, і що на думку команди може викликати найбільші проблеми на етапі підготовки дизайну. Як правило, стартуємо ми одночасно, але попередньо визначаємо фронт робіт. Весь продукт можна розділити на три частини:

  • Опції особливі, зі складною бізнес-логікою. У замовника є уявлення як це повинно працювати і ці знання потрібно отримати. Аналітик в першу чергу починає роботу за завданнями такого типу. Невизначеності потрібно зняти в першу чергу, якщо цього не зробити, то про подальших роботах і мови бути не може.
  • Функції, які повинні бути зручні для користувача. Замовник має своє уявлення, але чекає від нас експертизу як зробити краще. Такі завдання віддаються UX — проектувальника, який готує концепції TO BE.
  • Функції, які повторюються з додатка до додатка. Як правило вони вже описані у вигляді вимог, є уявлення, яким буде дизайн, готовий код для реиспользования. Такі речі відкладаються на останні етапи проекту і можуть виконуватися дизайнером і аналітиком практично паралельно з періодичної синхронізації.

У випадку з функціями першого типу для передачі знань між учасниками команди ми використовуємо ряд артефактів.

Діаграма бізнес-процесів

Ми застосовуємо BPMN діаграма для опису бізнес-процесів замовника. Їх перевага полягає в тому, що вони прості для читання і чітко фіксують послідовність основних кроків, які повинні бути дотримані. Вони легко сприймаються замовником (у деяких компаніях є стандартом) і зрозумілі дизайнерам.
Кожна діаграма обов’язково забезпечується текстом. Текстовий супровід описує всі кроки більш детально і фіксує вимоги бізнесу, які неможливо відобразити графічно, а також дані, які задіяні в тій чи іншій процедурі бізнес-процесу.

Приклади даних і логічна модель даних

Важливим для дизайнерів є не тільки дотримання бізнес логіки, але й розуміння з якими даними доведеться мати справу. Буде зручно переглядати список з 3 найменувань. Думаю, що так. А якщо цих найменувань 1000, підійде все той же простий список? Для передачі даних у нас прийнято використовувати такі артефакти:

  • Логічну модель даних
  • Приклади даних

Логічна модель допомагає зрозуміти, які основні сутності будуть задіяні в програмі, з чим доведеться працювати користувачу. Які атрибути даних сутностей, що важливо підкреслити, а що навпаки користувачеві нецікаво і показувати не будемо. Як було доведено практикою, однієї логічної моделі недостатньо. Важливо ще розуміти сам контент — як він виглядає і яку інформацію несе для користувача. Саме тому кожна модель даних забезпечується плоскими таблицями, які пояснюють, що це за сутність, скільки їх може бути у користувача, дають текстовий опис атрибутів сутності і приклад того, «як це реально виглядає».

NB! Важливо пам’ятати один момент. Аналітик повинен вчасно виявляти та сигналізувати про майбутні зміни у вимогах PM-у проекту. Передати знання у вигляді діаграм бізнес-процесів і логічної моделі з прикладами даних недостатньо. Важливо розуміти, що отримана інформація адекватно сприймається учасниками команди.

Інтелект-карта

У нас виробилася така практика: після того, як UX-проектувальник вивчив всі отримані матеріали і задав необхідні запитання аналітику, він готує інтелект-карту з набором функцій і можливостей, які ляжуть в основу майбутнього дизайну. Після підготовки інтелект-карта обговорюється спільно з аналітиком. На цьому етапі потрібно переконатися, що всі все розуміють однаково, і немає ніяких різночитань.

Інтелект-карта майбутнього набору функцій, які UX-проектувальник хоче включити в дизайн

Фінальний набір екранів і валідація

Перед показів дизайн замовнику ми в обов’язковому порядку проводимо валідацію командою. Розробники перевіряють майбутнє додаток на реалізацію, аналітики — на відповідність бізнес-логікою та очікуванням замовника. І тільки після затвердження всіма учасниками процесу дизайн відправляється на затвердження з замовником.

Підсумуємо

Описаний набір артефактів і взаємодій допомагає аналітику полегшити обмін інформацією між бізнесом та UX-проектуванням і робить комунікацію гранично ефективною. Установчі зустрічі і побудова інтелект-карти дозволяють команді синхронізуватися всередині себе і зводять до мінімуму виникнення різночитань і непорозуміння між учасниками процесу. А це — одна з головних складових успіху всього проекту в цілому.

Інтервали в С++, частина 3: представляємо інкрементори (Iterable)

У попередніх постах я описав проблеми, з якими зіткнувся при створенні бібліотеки для роботи з інтервалами. Зараз я опишу вам моє рішення: покращення концепції інтервалів, які дозволяють створювати інтервали з обмежувачами і нескінченні інтервали, що чудово вписуються в ієрархію стандартної бібліотеки без втрати продуктивності.

У кінці попереднього поста я підсумував недоліки існуючих інтервалів:

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


Концепція інтервалів
Для початку, давайте суворо визначимо поняття інтервалу. У стандарті C++ це слово використовується всюди, але ніде не визначається. Можна зрозуміти, що інтервал – це щось, з чого можна отримати begin і end, пару ітераторів, які влаштовані так, що до end можна дістатися, почавши з begin. У термінах моєї пропозиції формалізувати цю концепцію можна так:

using std::begin;
using std::end;

template < typename T>
using Iterator_type =
decltype(begin(std::declval<T>()));

template < typename T>
concept bool Range =
requires(T range) {
{ begin(range) } -> Iterator_type<T>;
{ end(range) } -> Iterator_type<T>;
requires Iterator<Iterator_type<T>>;
};

 

Також є поліпшення концепції інтервалу Range, які називаються InputRange, ForwardRange, і т. д. На ділі вони просто більше вимагають від своїх ітераторів. Нижче показана вся ця ієрархія.

Ці концепції є основою для бібліотек Boost.Range (http://www.boost.org/libs/range)

Проблема 1: Генерація поганого коду
Якщо пам’ятаєте, для реалізації інтервалів як з обмежувачем, так і нескінченних, у вигляді пари ітераторів, ітератор end повинен бути особливим. І такий ітератор являє собою більше концепцію, ніж фізичне положення елемента в послідовності. Можна представляти його, як елемент з позицією «останній + 1» – різниця лише в тому, що ви не дізнаєтеся, де його позиція, поки не досягнете її. Оскільки тип сигнального ітератора такою ж, як у звичайного, потрібна перевірка на етапі виконання програми, щоб визначити, чи є даний ітератор сигнальним. Це призводить до повільного порівнянні ітераторів і незручним реалізаціями методів.

Концепція инкременторов(Iterable)
Для чого потрібні ітератори? Ми збільшуємо їх, разыменовываем і порівнюємо, так адже? А що можна зробити з сигнальним ітератором? Не особливо багато чого. Його позиція не змінюється, його можна разыменовать, оскільки його позиція завжди «останній + 1». Але його порівняти з ітератором. Виходить, що сигнальний ітератор – слабкий ітератор.

Проблема з інтервалами в тому, що ми намагаємося перетворити сигнальний ітератор в звичайний. Але він ним не є. Так і не будемо це робити – нехай вони будуть іншого типу.

Концепція Range вимагає, щоб begin і end були одного типу. Якщо можна їх зробити різними, це вже буде більш слабка концепція – концепція Iterable. Инкременторы – вони як ітератори, тільки у begin і end різні типи. Концепція:

template<typename T>
using Sentinel_type =
decltype(end(std::declval<T>()));

template < typename T>
concept bool Iterable =
requires(T range) {
{ begin(range) } -> Iterator_type<T>;
{ end(range) } -> Sentinel_type<T>;
requires Iterator<Iterator_type<T>>;
requires EqualityComparable<
Iterator_type<T>, Sentinel_type<T>>;
};

template < typename T>
concept bool Range =
Iteratable<T> &&
Same<Iterator_type<T>, Sentinel_type<T>>;

Природно, концепція Range входить в концепцію Iterable. Вона просто уточнює її, додаючи обмеження на рівність типів begin і end.

Так виглядає ієрархія, якщо ми розглядаємо інтервали, инкременторы і ітератори, але зовсім не обов’язково саме так визначати їх у програмі. Зауважте, що «интервальность» – тобто, схожість типів begin і end, ортогональна силі ітератора begin. Коли нам треба включати в код моделювання RandomAccessRange, ми можемо сказати requires RandomAccessIterable && Range і просто змінити всю концепцію.

Різниця між, наприклад, BidirectionalIterable і ForwardIterable в концепції, моделюється ітератором begin з Iterable.

Iterable і алгоритми STL
Але постійте – адже алгоритми STL не будуть працювати з инкременторами, тому що їм потрібно, щоб у begin і end було один тип. Так і є. Тому я прошерстил весь STL, щоб перевірити, що можна переписати. Наприклад, std::find

template<class InputIterator, class Value>
InputIterator
find(InputIterator first, InputIterator last,
Value const & value)
{
for (; first != last; ++first)
if (*first == value)
break;
return first;
}

Зараз std::find використовує Ranges. Але зауважте, що алгоритм не намагається поміняти позицію ітератора end. Алгоритм пошуку можна легко змінити так, щоб він працював з Iterables замість Ranges:

template<class InputIterator, class Sentinel, class Value>
InputIterator
find(InputIterator first, Sentinel last,
Value const & value)
{
for (; first != last; ++first)
if (*first == value)
break;
return first;
}

Ось і все – зміна настільки мале, що його навіть важко помітити.

Так які алгоритми C++98 можна пристосувати до роботи з Iterables замість Ranges? Виявляється, майже всі. Легше перерахувати ті, які не піддаються. Це:

  • copy_backward
  • алгоритми роботи з множинами і пірамідами (push_heap, pop_heap, make_heap, sort_heap)
  • inplace_merge
  • nth_element
  • partial_sort і partial_sort_copy
  • next_permutation і prev_permutation
  • random_shuffle
  • reverse і reverse_copy
  • sort і stable_sort
  • stable_partition

Інші півсотні вимагають чисто механічного зміни в коді. Визначивши концепцію Iterable так, як вона визначається в Range, ми даємо будь-якого алгоритму, що працює з Iterable, можливість точно так само працювати і з Ranges. Це корисно і важливо – для ітераторів написано дуже багато коду, щоб робити для них якусь несумісну абстракцію.

Доказ у Perf

І що ми отримаємо? Повернемося до наших З-рядками. Я описав клас c_string_range і знайшов, що перебір символів генерує поганий код. Почнемо знову, тільки за допомогою range_facade, щоб побудувати Iterable замість Range.

using namespace ranges;
struct c_string_iterable
: range_facade<c_string_iterable>
{
private:
friend range_core_access;
const char *sz_;
const char & current() const { return *sz_; }
void next() { ++sz_; }
bool done() const { return *sz_ == 0; }
bool equal(c_string_iterable const &that) const
{ return sz_ == that.sz_; }
public:
c_string_iterable(const char *s)
: sz_(sz) {}
};

Код вийшов набагато простіше, ніж старий. Всю роботу робить range_facade. Ітератор і сигнальний ітератор реалізовані у вигляді примітивів. Щоб перевірити його, я згенерувати оптимізований машинний код для наступних функцій, одна з яких використовує старий клас c_string_range, а інша – новий c_string_iterable:

// Range-based
int range_strlen(
c_string_range::iterator begin,
c_string_range::iterator end)
{
int i = 0;
for(; begin != end; ++begin)
++i;
return i;
}

// Iterable-based
int iterable_strlen(
range_iterator_t<c_string_iterable> begin,
range_sentinel_t<c_string_iterable> end)
{
int i = 0;
for(; begin != end; ++begin)
++i;
return i;
}

Навіть не знаючи асемблера, можна зрозуміти різницю.

;Range-based strlen
pushl %ebp
movl %esp, %ebp
pushl %esi
leal 8(%ebp), %ecx
movl 12(%ebp), %esi
xorl %eax, %eax
testl %esi, %esi
movl 8(%ebp), %edx
jne LBB2_4
jmp LBB2_1
.align 16, 0x90
LBB2_8:
incl %eax
incl %edx
movl %edx, (%ecx)
LBB2_4:
testl %edx, %edx
jne LBB2_5
cmpb $0, (%esi)
jne LBB2_8
jmp LBB2_6
.align 16, 0x90
LBB2_5:
cmpl %edx, %esi
jne LBB2_8
jmp LBB2_6
.align 16, 0x90
LBB2_3:
leal 1(%edx,%eax), %esi
incl %eax
movl %esi, (%ecx)
LBB2_1:
movl %edx, %esi
addl %eax, %esi
je LBB2_6
cmpb $0, (%esi)
jne LBB2_3
LBB2_6:
popl %esi
popl %ebp
ret
;Iterable-based strlen
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %ecx
xorl %eax, %eax
cmpb $0, (%ecx)
je LBB1_4
leal 8(%ebp), %edx
.align 16, 0x90
LBB1_2:
cmpb $0, 1(%ecx,%eax)
leal 1(%eax), %eax
jne LBB1_2
addl %eax, %ecx
movl %ecx, (%edx)
LBB1_4:
popl %ebp
ret

Код з инкременторами набагато крутіше. І він практично ідентичний з ассемблером, отриманим ітераторів «голого».

Ітератори, сигнальні ітератори і паритетність

Але що означає порівняння двох об’єктів різних типів на еквівалентність?

Трохи для непосвячених: N3351 визначає, в яких випадках припустимі порівняння різних типів. Недостатньо, щоб синтаксис «x==y» був припустимо і видавав булевское значення. Якщо у х і в будуть різні типи, то ці типи повинні бути самі по собі EqualityComparable, і у них має бутизагальний тип, до якого їх можна перетворити, і він також повинен бути EqualityComparable. Припустимо, ми порівнюємо char і short. Це можливо, оскільки вони EqualityComparable, і їх можна перетворити в int, який теж EqualityComparable.

Ітератори можна порівнювати, а сигнальні ітератори порівнюються тривіальним чином. Складність в тому, щоб знайти для них загальний тип. Взагалі, у кожного ітератора і сигнального є загальний тип, який можна створити так: припустимо існування нового типу ітератора I, який представляє собою тип-суму, і містить або ітератор, або сигнальний ітератор. Коли їх порівнюють, він веде себе семантично так, ніби їх обох спочатку перетворили в два об’єкти типу I, назвемо їх lhs і rhs, і потім порівняли по наступній табличці:

lhs сигнальный итератор? rhs сигнальный итератор? lhs == rhs?
true true true
true false done(rhs.iter)
false true done(lhs.iter)
false false lhs.iter == rhs.iter

Ця табличка нагадує ту, яка вийшла при аналізі поведінки оператора порівняння c_string_range::iterator. Це не випадково – то був особливий випадок цієї, більш загальної, схеми. Вона підтверджує інтуїтивне висновок, який ви вже можете помітити, переглянувши два моїх класу, c_string_range і c_string_iterable. Один – пара ітераторів, інший – пара ітератор/сигнальний, але їх схема роботи схожі. Ми відчуваємо, що можливо побудувати еквівалентний Range будь Iterable, якщо пожертвувати дещицею швидкодії. І тепер ми знайшли підтвердження цьому.

Можливість порівнювати ітератори і сигнальні ітератори безпосередньо дозволяє нам використовувати систему типів C++ для оптимізації великий категорії ітерацій, прибираючи розгалуження в операторі порівняння паритетності.

Заперечення

Ідея дати різні типи begin і end не нова, і придумав її не я. Я дізнався про неї від Дейва Абрахамса (Dave Abrahams) багато років тому. Нещодавно подібну ідею подав Дітмар Кюэль (Dietmar Kuehl) у списку розсилки Ranges, а у відповідь на його лист Шон Пэрент (Sean Parent) висловив наступне заперечення:

Мені здається, ми покладаємо на ітератори занадто багато. Алгоритми, що працюють з закінченням на підставі перевірки сигнального ітератора або на підставі підрахунку – це різні сутності. См. copy_n() і copy_sentinel()

stlab.adobe.com/copy_8hpp.html

Щодо інтервалів – я впевнений, що можна побудувати його за допомогою:

  1. пари ітераторів
  2. ітератора і кількість
  3. ітератора і сигналу

І в цьому випадку copy(r, out) може видати потрібний алгоритм.

Якщо я правильно його зрозумів, він говорить про існування трьох паралельних концепцій інтервалів: IteratorRange, CountedRange і SentinelRange. І ці ієрархії не потрібно намагатися зв’язати між собою. Алгоритм копіювання повинен містити три різні реалізації, по одній на кожну концепцію. Тоді доведеться потроїти близько 50 алгоритмів – і це надто багато повторення в коді.

Гірше того, деякі алгоритми засновані на уточнених концепціях. Наприклад, libc++ алгоритм rotate обирає одну з трьох реалізацій, в залежності від того, ви передаєте йому прямі, двосторонні або ітератори довільного доступу. А для включення трьох різних реалізацій Iterator, Counted і SentinelRanges знадобилося б 9 алгоритмів rotate! При всій повазі, це божевілля.

Підсумки

На початку посту я навів список проблем, пов’язаних з інтервалами з парними итераторами. Я показав нову концепцію, Iterable, яка займається питаннями швидкодії і порушив питання складнощів реалізації інтервалів. Поки я не описав, як ця концепція працює з нескінченними інтервалами, про що ми поговоримо в четвертому, фінальному пості.

Весь код можна знайти у сховищі на github.

 

Техніки створення інтерактивних email-повідомлень за допомогою CSS

У нашому блозі ми вже розповідали про те, як реалізувати у листі пагінацію, проте це далеко не єдиний варіант інтерактивності email-розсилки. У деяких випадках привабливі листи можна створити з допомогою hover-ефекту, коли контент змінюється при наведенні на нього курсору.

Сьогодні ми представляємо вашій увазі витяги з статей блогу FreshInbox про те, як створити інтерактивне email-лист.

Перший спосіб включає три простих кроки.

1 крок: таблиця і фонове зображення

Спочатку потрібно створити таблицю, яка буде містити одну комірку із зображенням в якості фону:

<table cellpadding=0 cellspacing=0 border=0><tr>
<td width=240 background="http://.../alternate-image.jpg">
td>tr>table>

 

2 крок: посилання і зображення

Для hover-ефекту потрібно два зображення — одне показується спочатку, а інше з’являється при наведенні. На другому кроці потрібно вибрати головне зображення, яке буде «обгорнуте» посиланням. Також до ссылке додається клас «img-swap», а до зображення застосовується властивість

display:block

.<table cellpadding=0 cellspacing=0 border=0><tr>

<td width=240 background="http://../alternate-image.jpg">
<a class="img-swap" href="http://../link"><img src="http://../primary-image.jpg" width="240" height="170" border="0" style="display:block;" alt="the product">a>
td>tr>table>

 

3 крок: стиль і ховер

Завершальним етапом є додавання до ссылке стилів і налаштування для неї псевдокласу

:hover

, «націленого на зображення. Встановивши висоту зображення на 0px в тому випадку, коли курсор знаходиться на посилання, можна приховати зображення, що «фонове зображення з осередку. Стиль display встановлений в

:block

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

<style>
.img-swap {
display: block;
width: 240px;
height: 170px;
}

.img-swap:hover img {
height: 0px;
}
style>

Даний спосіб підтримується в Yahoo! Mail, Outlook.com (і Outlook 2003). Існує і модифікація для Gmail, яку ми докладно розглядали в одній з минулих статей.

Натисни і побачиш сюрприз

Ще одна техніка дозволяє створювати інтерактивні листи з допомогою hover-ефекту, а для мобільних користувачів показувати «сюрприз» після кліка на картинці.

Цей спосіб схожий на описаний вище, однак він відрізняється тим, що спочатку для непідтримуваних клієнтів показується не первісне зображення, а з’являється картинка. Це дозволить користувачам з непідтримуваними поштовими програмами не упустити сам зміст листа (хоча і вся інтерактивність їм буде недоступна).

Підтримувані клієнти: iOS Mail, Android 4.x Mail, Yahoo! Mail, Outlook.com і Gmail.com (з описаним за посиланням вище хаком з селекторами атрибутів).

Непідтримувані клієнти: десктопний Outlook, мобільні додатки Gmail і Gmail for business

У чому відмінність від попереднього методу

Щоб зробити можливим відображення відкривається зображення, потрібно здійснити невеликі зміни в порівнянні з попередньою версією техніки. Замість використання зображення обкладинки в якості оверлея, а відкривається зображення в якості фону, потрібно зробити все навпаки:

<table border=1 cellpadding=0 cellspacing=0 background="http://freshinbox.com/examples/rollover-reveal-simple/images/reveal-close-l.jpg">
<tr><td>
<a class="reveal" lang="x-reveal" style="display:block;width:500px;height:400px;" 
href="#">
<img src="http://freshinbox.com/examples/rollover-reveal-simple/images/reveal-open-l.jpg" 
style="display:block;" height=400 width=500 alt="A surprise!" border=0>
a>
td>tr>table>

Відкривається зображення буде основним, а первісна «обкладинка» стане фоном. Потім на підтримуваних поштових клієнтів ми сховаємо оверлей, показуючи тільки обкладинку (тобто фон). Коли користувач наведе курсор на зображення, йому вже буде показано приховане зображення.
Тому, замість:

rollover:hover img{
max-height: 0px;
height:0px;
}

Код буде виглядати так:

.reveal img{
max-height: 0px;
height:0px;
}
.reveal:hover img{
max-height: none;
height: auto;
}

Таким чином, якщо поштова програма не підтримує інтерактивність, користувач побачить те зображення, яке в результаті відкривається за ховеру. В цьому випадку втрачається wow-ефект, але зберігається сенс послання.

Крім того, зображення загорнуте в «мертву посилання» — це потрібно для того, щоб спрацьовував ефект по тапу на iOS і Android. Посилання може бути активною, але тоді в Android користувачі будуть перенаправлятися на неї. В принципі, інтерактивність на мобільних пристроях можна взагалі відключити за допомогою спеціального медиазапроса:

@media screen and (max-device-width: 1024px){
.reveal img{
max-height: none !important;
height: auto !important;
} 
} 

Під спойлером представлений повний код прикладу (попрацювати з ним також можна Codepen):

Код прикладу


<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=EDGE" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Rollover to Revealtitle>

<style>

/* wrapping in media query prevents styles from activating in OWA */
.yfix{}

@media screen and (max-width:9999px) {
.reveal img{
max-height: 0px;
height:0px;
}
.reveal:hover img{
max-height: none;
height: auto;
} 

* [lang=x-reveal] img{
max-height: 0px;
height:0px;
}
* [lang=x-reveal]:hover img{
max-height: none;
height: auto;
}
}

style>
head>
<body style="margin:0px; padding:0px;">

< table border=1 cellpadding=0 cellspacing=0 background="http://freshinbox.com/examples/rollover-reveal-simple/images/reveal-close-l.jpg"><tr>
<td><a class="reveal" lang="x-reveal" style="display:block;width:500px;height:400px;" href="#"><img src="http://freshinbox.com/examples/rollover-reveal-simple/images/reveal-open-l.jpg" style="display:block;" height=400 width=500 alt="A surprise!" border=0>a>td>
tr>table>

body>

Dojo 2

Dojo 2 уточнює і розширює оригінальні інтерфейси Dojo, видаляючи застарілі функції та узгоджуючи термінологію згідно з доповненнями, внесеними ECMAScript з моменту первинного випуску Dojo в 2004 році. Мета Dojo 2 це підтримка тільки ECMAScript 5+. Так, особливості, які були в Dojo 1 і які стали частиною специфікації ECMAScript, були видалені з фреймворка.

Dojo 2 написаний на TypeScript. Це дозволяє користувачам Dojo скористатися перевагами додаткової статичної типізації і дозволяє Dojo бути опублікованими в AMD, CommonJS і ES6 форматі модулів для використання з нативними модульними системами в будь-якому сучасному оточенні.

Загальний підхід Dojo 2Dojo Toolkit почав створюватися в 2004 році групою однодумців розробляють JavaScript, які втомилися винаходити колесо і створювати милиці навколо невідповідності браузерів.

Місія Dojo Toolkit в тому, щоб забезпечити цілісність і простоту у використанні функцій API, які дозволяють розробникам створювати простіше підтримувані веб-додатки і не турбується про невідповідності і примхи кожного браузера.

Ми випустили Dojo 1.0 в 2007 році і продовжували його безперервно розвивати, вводячи поняття, які в даний час стали основними у розвитку JavaScript. В той час, використання модулів JavaScript, promises/deferreds, MVC, CSS препроцесора і системи збирання було сприйнято багатьма як складне і непотрібне. Як ми знаємо, ці речі стали частиною розвитку JavaScript сьогодні, і ми дуже раді, що більшість розробників JavaScript в даний час прагне до розвитку в цьому напрямку.

Основні принципи

Ми витратили багато часу, думаючи про те, що повинен вміти JavaScript фреймворк наступного покоління. Недостатньо просто додати нові функції, збільшити номер версії і назвати його «Dojo 2». У ньому повинен бути набір основних принципів, що визначають майбутній розвиток. Світ JavaScript значно змінився з часів народження Dojo. Місія фреймворку залишається такою ж, але те, як це зроблено, буде сильно відрізнятися.

Модульність

В даний час (принаймні на цьому тижні) у світі JavaScript вважають, що все, що може бути розділене на окремі пакети, має бути розділене. Наприклад, якщо все що вам потрібно це основні маніпуляції DOM і обробка подій, то ви можете взяти пакет, який робить тільки це.

Це здорово працює для невеликих проектів, але, коли вимоги ростуть і складність зростає, все більше пакетів з декількох джерел додаються до проекту. Ідея, що ви можете просто змінити пакет на інший пізніше — утопія. При створенні програмного забезпечення для великих корпорацій, часто неможливо працювати таким чином, т. к. їх юридичні відділи вимагають чистої інтелектуальної власності — код розглядається і юридично приймається перед використанням.

Наш підхід з Dojo 2 полягає в золотій середині між окремими пакетами і єдиним Dojo Toolkit. Ми будемо розробляти, збирати і випускати функціональність ядра Dojo разом з такими пакетами, як dgrid, dstore і Intern. Розробники будуть вільно використовувати і самостійно модернізувати частини, які їм потрібні, або використовувати зібраний випуск Dojo Toolkit. Поділ Dojo дозволить іншим внести свій вклад більш легко і випуски будуть відбуватися набагато швидше і менш болісно.

Використання існуючої екосистеми

Dojo, можливо, у багатьох напрямках був першим, але, враховуючи поширення JavaScript мікро-бібліотек і інструментів, у нас часто немає підстав, щоб підтримувати власне рішення тільки тому, що воно наше. Там, де є порівнянна або найкраща реалізація, ми будемо думати над тим, щоб використовувати її. Наприклад, ми будемо документувати наш код з допомогою JSDoc, а не DojoDoc як ми робили в часи розробки Dojo 1.x.

Покращена документація

До речі про документації: ми старанно працювали над поліпшенням документації для Dojo 1.х, але наші вимоги до документації Dojo2 ще вище. Багато в чому проблеми з документацією були викликані відсутністю інструментів. Використовуючи сучасні рішення, такі як JSDoc, Markdown і GitHub, ми можемо збільшити якість документації і швидкість додавання та оновлення документів.

Продовження просування JavaScript

По-перше, Dojo 2 буде написаний на TypeScript. В той час, як ES6 / ES2015 приніс багато необхідних поліпшень, є багато незакінчених речей. Такі мови, як TypeScript, дозволяють додавати поліпшення перш, ніж вони будуть додані до мови. Тоді ми можемо легко скласти транспайлер в AMD, CJS або ES6 модулі. Це дозволяє поліпшити сама мова, але що ще більш важливо, полегшити життя розробникам.

Сучасні оточення

На додаток до десктопних браузерам, метою Dojo 2 є підтримка максимально можливого кількості сучасних JavaScript оточень. Це означає підтримку мобільних телефонів, планшетів, Node.js / io.js, VR гарнітури і багато іншого.

Віджети

Віджети були однією з основних особливостей Dojo 1.x, але багато чого змінилося після того, як ми представили Dijit. Ми все ще думаємо який підхід обрати Dojo 2 — Dijit, нативні віджети, веб-компоненти або щось зовсім нове. Наш початковий акцент робиться на визначенні основної функціональності для Dojo 2, після цього ми почнемо визначати загальний підхід для віджетів.

План

Ми працюємо над кожною частиною Dojo 2 в кілька кроків.
Дизайн. Визначити основну функціональність і API, щоб створити високий рівень «специфікації» для кожного Dojo 2 пакета.
Розробка. Використовуючи специфікацію створену на першому кроці, розробити і задокументувати функціональність. Після чого використовувати Intern щоб перевірити, що це працює.
Випуск. Dojo 2 буде упакований як набір різних модулів. Із завершенням кожного модуля ми ближче до Dojo версії 2.0.

1 2 3 ... 124 125 126 127 128 129 130 131 132 133 134 ... 901 902 903