diff --git a/1-js/10-es-modern/3-promise/1-promise-settimeout/solution.md b/1-js/10-es-modern/3-promise/1-promise-settimeout/solution.md
new file mode 100644
index 00000000..791fe90e
--- /dev/null
+++ b/1-js/10-es-modern/3-promise/1-promise-settimeout/solution.md
@@ -0,0 +1,8 @@
+
+```js
+function delay(ms) {
+ return new Promise((resolve, reject) => {
+ setTimeout(resolve, ms);
+ });
+}
+```
\ No newline at end of file
diff --git a/1-js/10-es-modern/3-promise/1-promise-settimeout/task.md b/1-js/10-es-modern/3-promise/1-promise-settimeout/task.md
new file mode 100644
index 00000000..0dd9edc4
--- /dev/null
+++ b/1-js/10-es-modern/3-promise/1-promise-settimeout/task.md
@@ -0,0 +1,27 @@
+
+# Промисифицировать setTimeout
+
+Напишите функцию `delay(ms)`, которая возвращает промис, переходящий в состояние `"resolved"` через `ms` миллисекунд.
+
+Пример использования:
+```js
+delay(1000)
+ .then(() => alert("Hello!"))
+````
+
+Такая полезна для использования в других промис-цепочках.
+
+Вот такой вызов:
+```js
+return new Promise((resolve, reject) => {
+ setTimeout(() => {
+ doSomeThing();
+ resolve();
+ }, ms)
+});
+```
+
+Станет возможным переписать так:
+```js
+return delay(ms).then(doSomething);
+```
diff --git a/1-js/10-es-modern/3-promise/anon.png b/1-js/10-es-modern/3-promise/anon.png
new file mode 100644
index 00000000..a1675d2f
Binary files /dev/null and b/1-js/10-es-modern/3-promise/anon.png differ
diff --git a/1-js/10-es-modern/3-promise/article.md b/1-js/10-es-modern/3-promise/article.md
index b06a23f1..a575f667 100644
--- a/1-js/10-es-modern/3-promise/article.md
+++ b/1-js/10-es-modern/3-promise/article.md
@@ -21,7 +21,7 @@ Promise -- это специальный объект, который содер
- Код, которому надо сделать что-то асинхронно, создаёт объект `promise` и возвращает его.
- Внешний код, получив `promise`, навешивает на него обработчики.
-- По завершении асинхронного процесса асинхронный код переводит `promise` в состояние `fulfilled` (с результатом) или `rejected` (с ошибкой). При этом автоматически вызываются обработчики.
+- По завершении процесса асинхронный код переводит `promise` в состояние `fulfilled` (с результатом) или `rejected` (с ошибкой). При этом автоматически вызываются соответствующие обработчики во внешнем коде.
Синтаксис создания `Promise`:
@@ -29,8 +29,9 @@ Promise -- это специальный объект, который содер
```js
var promise = new Promise(function(resolve, reject) {
// Эта функция будет вызвана автоматически
+
// В ней можно делать любые асинхронные операции,
- // А когда они завершаться — вызвать:
+ // А когда они завершаться — нужно вызвать одно из:
// resolve(результат) при успешном выполнении
// reject(ошибка) при ошибке
})
@@ -61,10 +62,11 @@ promise.then(null, onRejected)
[/smart]
[smart header="Синхронный `throw` -- то же самое, что `reject`"]
-Если в функции промиса происходит ошибка или синхронный `throw`, то вызывается `reject`:
+Если в функции промиса происходит синхронный `throw` (или иная ошибка), то вызывается `reject`:
```js
//+ run
var p = new Promise((resolve, reject) => {
+ // то же что reject(new Error("o_O"))
throw new Error("o_O");
})
@@ -85,7 +87,7 @@ p.catch(alert); // Error: o_O
var promise = new Promise((resolve, reject) => {
setTimeout(() => {
- // переводит в состояние fulfilled с результатом "result"
+ // переведёт промис в состояние fulfilled с результатом "result"
resolve("result");
}, 1000);
@@ -135,6 +137,11 @@ promise
Конечно, вместо `setTimeout` мог бы быть и запрос к серверу и ожидание ввода пользователя, или другой асинхронный процесс.
+[smart header="Только один аргумент"]
+Функции `resolve/reject` принимают ровно один аргумент -- результат/ошибку.
+
+Именно он передаётся обработчикам в `.then`, как можно видеть в примерах выше.
+[/smart]
## Promise после reject/resolve -- неизменны
@@ -203,11 +210,11 @@ promise
В качестве примера сделаем такую обёртку для запросов при помощи XMLHttpRequest.
-Функция `loadUrl(url)` будет возвращать промис, который при успешной загрузки данных с `url` будет переходить в `fulfilled` с этими данными, а при ошибке -- в `rejected` с информацией об ошибке:
+Функция `httpGet(url)` будет возвращать промис, который при успешной загрузки данных с `url` будет переходить в `fulfilled` с этими данными, а при ошибке -- в `rejected` с информацией об ошибке:
```js
//+ autorun
-function loadUrl(url) {
+function httpGet(url) {
return new Promise(function(resolve, reject) {
@@ -221,7 +228,9 @@ function loadUrl(url) {
*/!*
} else {
*!*
- reject(new Error(this.statusText));
+ var error = new Error(this.statusText);
+ error.code = this.status;
+ reject(error);
*/!*
}
};
@@ -244,7 +253,7 @@ function loadUrl(url) {
```js
//+ run
-loadUrl("/article/promise/user.json")
+httpGet("/article/promise/user.json")
.then(
response => alert(`Fulfilled: ${response}`),
error => alert(`Rejected: ${error}`)
@@ -253,11 +262,9 @@ loadUrl("/article/promise/user.json")
[smart header="Метод `fetch`"]
-Заметим, что ряд современных браузеров уже поддерживает [fetch](https://fetch.spec.whatwg.org) -- новый встроенный метод для AJAX-запросов, призванный заменить XMLHttpRequest. Он, конечно, гораздо мощнее, чем `loadUrl`. И -- да, этот метод использует промисы. Полифилл для него доступен на [](https://github.com/github/fetch).
+Заметим, что ряд современных браузеров уже поддерживает [fetch](https://fetch.spec.whatwg.org) -- новый встроенный метод для AJAX-запросов, призванный заменить XMLHttpRequest. Он, конечно, гораздо мощнее, чем `httpGet`. И -- да, этот метод использует промисы. Полифилл для него доступен на [](https://github.com/github/fetch).
[/smart]
-Далее мы увидим ещё примеры, а пока -- рассмотрим важные свойства `promise`.
-
## Цепочки промисов
@@ -271,14 +278,14 @@ loadUrl("/article/promise/user.json")
...И сделать код расширяемым, чтобы цепочку можно было легко продолжить.
-Вот код для этого, использующий функцию `loadUrl`, описанную выше:
+Вот код для этого, использующий функцию `httpGet`, описанную выше:
```js
//+ run
'use strict';
// сделать запрос
-loadUrl('/article/promise/user.json')
+httpGet('/article/promise/user.json')
*!*
// 1. Получить данные о пользователе в JSON и передать дальше
*/!*
@@ -295,7 +302,7 @@ loadUrl('/article/promise/user.json')
.then(user => {
console.log(user);
*!*
- return loadUrl(`https://api.github.com/users/${user.name}`);
+ return httpGet(`https://api.github.com/users/${user.name}`);
*/!*
})
*!*
@@ -319,7 +326,7 @@ loadUrl('/article/promise/user.json')
Самое главное в этом коде -- последовательность вызовов:
```js
-loadUrl(...)
+httpGet(...)
.then(...)
.then(...)
.then(...)
@@ -327,7 +334,7 @@ loadUrl(...)
При чейнинге, то есть последовательных вызовах `.then...then..then`, в каждый следующий `then` переходит результат от предыдущего.
-**Причём, если `then` вернул промис, то в следующий `then` будет передан не сам промис, а его результат.**
+**Причём, если очередной `then` вернул промис, то далее по цепочке будет передан не сам этот промис, а его результат.**
В коде выше:
@@ -341,22 +348,26 @@ loadUrl(...)
+Значком "песочные часы" помечены периоды ожидания. Если `then` возвращает промис, то до его выполнения может пройти некоторое время, оставшаяся часть цепочки ждёт.
+
Обратим внимание, что последний `then` в нашем примере ничего не возвращает. Если мы хотим, чтобы после `setTimeout` `(*)` асинхронная цепочка могла быть продолжена, то последний `then` тоже должен вернуть промис.
-Это общее правило. Если внутри `then` стартует новый асинхронный процесс, то для того, чтобы дождаться его окончания, мы должны вернуть промис, который перейдёт в состояние "выполнен" после `setTimeout`.
+Это стандартный приём. Если внутри `then` стартует новый асинхронный процесс, то для того, чтобы оставшаяся часть цепочки выполнилась после его окончания, мы должны вернуть промис, который перейдёт в состояние "выполнен" после `setTimeout`.
+
+
Строку `(*)` для этого нужно переписать так:
```js
.then(githubUser => {
...
- // вместо setTimeout(() => img.remove(), 3000);
+ // вместо setTimeout(() => img.remove(), 3000); (*)
return new Promise((resolve, reject) => {
setTimeout(() => {
img.remove();
- // после таймаута — просто resolve, без результата,
- // чтобы управление перешло в следующий then
+ // после таймаута — вызов resolve,
+ // можно без результата, чтобы управление перешло в следующий then
// (или можно передать данные пользователя дальше по цепочке)
resolve();
}, 3000);
@@ -364,7 +375,7 @@ loadUrl(...)
})
```
-Теперь, если к цепочке добавится ещё `then`, то он будет вызван после окончания `setTimeout`.
+Теперь, если к цепочке добавить ещё `then`, то он будет вызван после окончания `setTimeout`.
## Перехват ошибок
@@ -387,11 +398,11 @@ loadUrl(...)
'use strict';
*!*
-// в loadUrl обратимся к несуществующей странице
+// в httpGet обратимся к несуществующей странице
*/!*
-loadUrl('/page-not-exists')
+httpGet('/page-not-exists')
.then(response => JSON.parse(response))
- .then(user => loadUrl(`https://api.github.com/users/${user.name}`))
+ .then(user => httpGet(`https://api.github.com/users/${user.name}`))
.then(githubUser => {
githubUser = JSON.parse(githubUser);
@@ -414,142 +425,245 @@ loadUrl('/page-not-exists')
*/!*
```
+В примере выше ошибка возникает в первом же `httpGet`, но `catch` с тем же успехом поймал бы ошибку во втором `httpGet` или в `JSON.parse`.
+
Принцип очень похож на обычный `try..catch`: мы делаем асинхронную цепочку из `.then`, а затем, когда нужно перехватить ошибки, вызываем `.catch(onRejected)`.
-[smart header="А что после catch?"]
-Обработчик `onRejected` получает ошибку и должен обработать её.
+[smart header="А что после `catch`?"]
+Обработчик `.catch(onRejected)` получает ошибку и должен обработать её.
Здесь два варианта развития событий:
-- Если ошибка не критичная, то он возвращает значение через `return`, и управление переходит в ближайший `onFulfilled`.
-- Если продолжить выполнение с такой ошибкой нельзя, то он делает `throw`, и тогда ошибка переходит в ближайший `onRejected`.
+
- Если ошибка не критичная, то обработчик возвращает значение через `return`, и управление переходит в ближайший `.then(onFulfilled)`.
+- Если продолжить выполнение с такой ошибкой нельзя, то он делает `throw`, и тогда ошибка переходит в ближайший `.catch(onRejected)`.
+
+Это также похоже на обычный `try..catch` -- в блоке `catch` ошибка либо обрабатывается, и тогда выполнение кода продолжается как обычно, либо он делает `throw`. Существенное отличие -- в том, что промисы асинхронные, поэтому при отсутствии внешнего `.catch` ошибка не "вываливается" в консоль и не "убивает" скрипт.
+
+Ведь возможно, что новый обработчик `.catch` будет добавлен в цепочку позже.
[/smart]
## Промисы в деталях
-Посмотрим внимательнее, что такое промис и как он работает, в соответствии со стандартом ES-2015.
+Самым основным источником информации по промисам является, разумеется, [стандарт](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-promise-objects).
+Чтобы наше понимание промисов было полным, и мы могли с лёгкостью разрешать сложные ситуации, посмотрим внимательнее, что такое промис и как он работает, но уже не в общих словах, а детально, в соответствии со стандартом EcmaScript.
+Согласно стандарту, у объекта `new Promise(executor)` при создании есть четыре внутренних свойства:
+
+- `PromiseState` -- состояние, вначале "pending".
+- `PromiseResult` -- результат, при создании значения нет.
+- `PromiseFulfillReactions` -- список функций-обработчиков успешного выполнения.
+- `PromiseRejectReactions` -- список функций-обработчиков ошибки.
+
-Поток выполнения сразу станет очевидным, как только мы разберём очень простое правило.
+
-Оно состоит из трёх частей:
+Когда функция-executor вызывает reject или resolve, то `PromiseState` становится `"resolved"` или `"rejected"`, а все функции-обработчики из соответствующего списка перемещаются в специальную системную очередь `"PromiseJobs"`.
-
-- Каждый `promise.then/catch` возвращает новый промис `newPromise`.
-- Ссылка на `newPromise` сохраняется в записывается в `promise`.
-При успешном выполнении этого промиса, вызывается следующий `onFulfilled`, если ошибка, то `onRejected`.
-- Этот обработчик возвращает... см. пункт 1.
-
+Эта очередь автоматически выполняется, когда интерпретатору "нечего делать". Иначе говоря, все функции выполнятся асинхронно, одна за другой, по завершении текущего кода, примерно как `setTimeout(..,0)`.
-Давайте по шагам.
+Исключение из этого правила -- если `resolve` возвращает другой Promise. Тогда дальнейшее выполнение ожидает его результата (в очередь помещается специальная задача), и функции-обработчики выполняются уже с ним.
-Очевидно, что каждый .then/catch должен промис. Это всегда так, иначе мы бы не смогли организовать чейнинг.
+Добавляет обработчики в списки один метод: `.then(onResolved, onRejected)`. Метод `.catch(onRejected)` -- всего лишь сокращённая запись `.then(null, onRejected)`.
-Этот промис -- всегда новый, не равный предыдущему.
+Он делает следующее:
+
+- Если `PromiseState == "pending"`, то есть промис ещё не выполнен, то обработчики добавляются в соответствующие списки.
+- Иначе обработчики сразу помещаются в очередь на выполнение.
+
-Проверим это:
-
-```js
-//+ run
-// Создадим промис и цепочку .then
-var promise = new Promise((resolve, reject) => {
- setTimeout(() => resolve(1), 1000);
-});
-
-var promise2 = promise
- .then(alert);
-
-// Выведем результат then
-alert(promise2); // да, это промис: [object Promise]
-alert(promise == promise2); // да, это новый промис
-```
-
-[smart header="Обработчики -- всегда асинхронны"]
-Кстати, обработчики в `.then/catch` всегда выполняются асинхронно, как будто обёрнуты в `setTimeout(..., 0)`, даже если внутри синхронная функция.
+Здесь важно, что обработчики можно добавлять в любой момент. Можно до выполнения промиса (они подождут), а можно -- после (выполнятся в ближайшее время, через асинхронную очередь).
Например:
+
```js
//+ run
-var promise = new Promise((resolve, reject) => {
- resolve("result")
-});
+// Промис выполнится сразу же
+var promise = new Promise((resolve, reject) => resolve(1));
-// сработает асинхронно
-promise.then(alert); // (2)
+// PromiseState = "resolved"
+// PromiseResult = 1
-alert("before promise"); // (1)
+// Добавили обработчик к выполненному промису
+promise.then(alert); // ...он сработает тут же
```
-При запуске этого кода выведется сначала `(1)`, а потом `(2)`.
+Разумеется, можно добавлять и много обработчиков на один и тот же промис:
-Такая "форсированная" асинхронность предусмотрена стандартом, чтобы избежать ситуаций, когда некий код работает то синхронно, то асинхронно, и возможных при этом багов.
-[/smart]
-
-Обработчики добавляются в общий список.
-
-
-
-
-При выполнении обработчика `.then/catch` -- он может либо что-то вернуть
-
-
-- Обработчика вернул значение (или ничего не вернул, что можно считать `return undefined`)
-
-
-
-Пример:
-
-
-Ошибкой считается либо вызов `reject`, либо синхронный `throw` в promise-функции:
```js
-var promise = new Promise((resolve, reject) {
-
- // эти две строки делают одно и то же:
- // переводят промис в состояние "rejected"
- throw new Error("...");
- reject(new Error("..."))
+//+ run
+// Промис выполнится сразу же
+var promise = new Promise((resolve, reject) => resolve(1));
-});
-```
-
-Обратим внимание, что `throw` корректно обрабатывается только если он синхронный.
-
-Вот так -- не подойдёт:
-
-```js
-var promise = new Promise((resolve, reject) {
-
- setTimeout(() => {
- // нельзя так делать, асинхронно должен быть reject
- throw new Error("...");
- }, 1000);
-
-});
-```
-
-На
-
-
-Мы уже использовали это неявно, при загрузке пользователя в примере выше:
-
-```js
-loadUrl('/article/promise/user.json')
- .then(response => {
- // ...
+promise.then( function f1(result) {
*!*
- let user = JSON.parse(response);
+ alert(result); // 1
+*/!*
+ return 'f1';
+})
+
+promise.then( function f2(result) {
+*!*
+ alert(result); // 1
+*/!*
+ return 'f2';
+})
+```
+
+Вид объекта `promise` после этого:
+
+
+
+На этой иллюстрации можно увидеть, что `.then` если один из обработчиков не указан, добавляет его "от себя", следующим образом:
+
+- Для успешного выполнения -- функция `Identity`, которая выглядит как `arg => return arg`, то есть возвращает аргумент без изменений.
+- Для ошибки -- функция `Thrower`, которая выглядит как `arg => throw arg`, то есть генерирует ошибку.
+
+
+Это, по сути дела, формальность, но без неё некоторые особенности поведения промисов могут "не сойтись" в общую логику, поэтому мы упоминаем о ней здесь.
+
+Обратим внимание, в этом примере намеренно *не используется чейнинг*. То есть, обработчики добавляются именно на один и тот же промис.
+
+Поэтому оба `alert` выдадут одно значение `1`. Алгоритм такой -- все функции из списка обработчиков вызываются с результатом промиса, одна за другой. Никакой передачи результатов между обработчиками одного промиса нет, а сам результат промиса (`PromiseResult`) после установки не меняется.
+
+**Для того, чтобы результат обработчика передать следующей функции, `.then` создаёт новый промис и возвращает его.**
+
+В примере выше создаётся два таких промиса, каждый из которых даёт свою ветку выполнения:
+
+
+
+Изначально эти новые промисы -- пустые. Когда в будущем выполнятся обработчики `f1, f2`, то их результат будет передан в новые промисы по стандартному принципу:
+
+
+- Если вернётся обычное значение (не промис), новый промис перейдёт в `"resolved"` с ним.
+- Если был `throw`, то новый промис перейдёт в состояние `"rejected"` с ошибкой.
+- Если вернётся промис, то используем его результат (он может быть как `resolved`, так и `rejected`).
+
+
+
+
+Чтобы лучше понять происходящее, посмотрим на цепочку, которая получается в процессе написания кода для показа github-аватара.
+
+Первый промис и обработка его результата:
+
+```js
+httpGet('/article/promise/user.json')
+ .then(JSON.parse)
+```
+
+
+
+
+Если промис завершился через `resolve`, то результат -- в `JSON.parse`, если `reject` -- то в Thrower.
+
+Как было сказано выше, `Thrower` -- это стандартная внутренняя функция, которая автоматически используется, если второй обработчик не указан. Можно сказать, что второй обработчик выглядит так:
+
+```js
+*!*
+function thrower(err) {
+ throw err;
+}
+*/!*
+
+httpGet('/article/promise/user.json')
+ .then(JSON.parse, thrower)
+```
+
+Заметим, что когда обработчик в промисах делает `throw`, то ошибка не "валит" скрипт и не выводится в консоли. Она просто будет передана в ближайший следующий обработчик `onRejected`.
+
+Добавим в код ещё строку:
+
+```js
+httpGet('/article/promise/user.json')
+ .then(JSON.parse)
+*!*
+ .then(user => httpGet(`https://api.github.com/users/${user.name}`))
+*/!*
+```
+
+Цепочка "выросла вниз":
+
+
+
+Функция `JSON.parse` либо возвращает объект с данными, либо генерирует ошибку (что расценивается как `reject`).
+
+Если всё хорошо, то `then(user => httpGet(…))` вернёт новый промис, на который стоят уже два обработчика:
+
+
+```js
+httpGet('/article/promise/user.json')
+ .then(JSON.parse)
+ .then(user => httpGet(`https://api.github.com/users/${user.name}`))
+ .then(
+*!*
+ JSON.parse,
+ function avatarError(error) {
+ if (error.code == 404) {
+ return {name: "NoGithub", avatar_url: '/article/promise/anon.png'};
+ } else {
+ throw error;
+ }
+ }
*/!*
- return user;
})
```
-Если при `JSON.parse` будет синтаксическая ошибка (некорректный JSON), то
+
+
+Наконец-то хоть какая-то обработка ошибок!
+
+Обработчик `avatarError` перехватит ошибки, которые были ранее. Функция `httpGet` при генерации ошибки записывает её HTTP-код в свойство `error.code`, так что мы легко можем понять -- что это:
+
+
+- Если страница на Github не найдена -- можно продолжить выполнение, используя "аватар по умолчанию"
+- Иначе -- пробрасываем ошибку дальше.
+
+
+Итого, после добавления оставшейся части цепочки, картина получается следующей:
+
+```js
+//+ run
+'use strict';
+
+httpGet('/article/promise/userNoGithub.json')
+ .then(JSON.parse)
+ .then(user => loadUrl(`https://api.github.com/users/${user.name}`))
+ .then(
+ JSON.parse,
+ function githubError(error) {
+ if (error.code == 404) {
+ return {name: "NoGithub", avatar_url: '/article/promise/anon.png'};
+ } else {
+ throw error;
+ }
+ }
+ })
+ .then(function showAvatar(githubUser) {
+ let img = new Image();
+ img.src = githubUser.avatar_url;
+ img.className = "promise-avatar-example";
+ document.body.appendChild(img);
+ setTimeout(() => img.remove(), 3000);
+ })
+ .catch(function genericError(error) {
+ alert(error); // Error: Not Found
+ });
+```
+
+
+
+В конце срабатывает общий обработчик `genericError`, который перехватывает любые ошибки. В данном случае ошибки, которые в него попадут, уже носят критический характер, что-то серьёзно не так. Чтобы посетитель не удивился отсутствию информации, мы показываем ему сообщение об этом.
+
+Можно и как-то иначе вывести уведомление о проблеме, главное -- не забыть обработать ошибки в конце. Если последнего `catch` не будет, а цепочка завершится с ошибкой, то посетитель об этом не узнает.
+
+В консоли тоже ничего не будет, так как ошибка остаётся "внутри" промиса, ожидая добавления следующего обработчика `onRejected`, которому будет передана.
+
+
diff --git a/1-js/10-es-modern/3-promise/promiseEcma.png b/1-js/10-es-modern/3-promise/promiseEcma.png
new file mode 100644
index 00000000..f27e0e0b
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseEcma.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseEcma@2x.png b/1-js/10-es-modern/3-promise/promiseEcma@2x.png
new file mode 100644
index 00000000..6fa3bd76
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseEcma@2x.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseHandlerVariants.png b/1-js/10-es-modern/3-promise/promiseHandlerVariants.png
new file mode 100644
index 00000000..c2c4a734
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseHandlerVariants.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseHandlerVariants@2x.png b/1-js/10-es-modern/3-promise/promiseHandlerVariants@2x.png
new file mode 100644
index 00000000..5f1f4da6
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseHandlerVariants@2x.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseInit.png b/1-js/10-es-modern/3-promise/promiseInit.png
index 2ebb001b..dc2e324f 100644
Binary files a/1-js/10-es-modern/3-promise/promiseInit.png and b/1-js/10-es-modern/3-promise/promiseInit.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseInit@2x.png b/1-js/10-es-modern/3-promise/promiseInit@2x.png
index bff15fce..957f91f7 100644
Binary files a/1-js/10-es-modern/3-promise/promiseInit@2x.png and b/1-js/10-es-modern/3-promise/promiseInit@2x.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-1.png b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-1.png
new file mode 100644
index 00000000..3f84d6fd
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-1.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-1@2x.png b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-1@2x.png
new file mode 100644
index 00000000..6602a3fb
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-1@2x.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-2.png b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-2.png
new file mode 100644
index 00000000..9d2c01cb
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-2.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-2@2x.png b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-2@2x.png
new file mode 100644
index 00000000..c8ae285e
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-2@2x.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-3.png b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-3.png
new file mode 100644
index 00000000..27a61c64
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-3.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-3@2x.png b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-3@2x.png
new file mode 100644
index 00000000..3954f250
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-3@2x.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-4.png b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-4.png
new file mode 100644
index 00000000..a59a1a44
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-4.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-4@2x.png b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-4@2x.png
new file mode 100644
index 00000000..6c196a3c
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain-4@2x.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseLoadAvatarChain.png b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain.png
new file mode 100644
index 00000000..ea162ad1
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseLoadAvatarChain@2x.png b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain@2x.png
new file mode 100644
index 00000000..1e5f23bb
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseLoadAvatarChain@2x.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseTwo.png b/1-js/10-es-modern/3-promise/promiseTwo.png
new file mode 100644
index 00000000..9ef03e37
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseTwo.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseTwo@2x.png b/1-js/10-es-modern/3-promise/promiseTwo@2x.png
new file mode 100644
index 00000000..1e9ea11d
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseTwo@2x.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseTwoThen.png b/1-js/10-es-modern/3-promise/promiseTwoThen.png
new file mode 100644
index 00000000..25922cc0
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseTwoThen.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseTwoThen@2x.png b/1-js/10-es-modern/3-promise/promiseTwoThen@2x.png
new file mode 100644
index 00000000..b2130043
Binary files /dev/null and b/1-js/10-es-modern/3-promise/promiseTwoThen@2x.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseUserFlow.png b/1-js/10-es-modern/3-promise/promiseUserFlow.png
index a61d7498..19b2a7cf 100644
Binary files a/1-js/10-es-modern/3-promise/promiseUserFlow.png and b/1-js/10-es-modern/3-promise/promiseUserFlow.png differ
diff --git a/1-js/10-es-modern/3-promise/promiseUserFlow@2x.png b/1-js/10-es-modern/3-promise/promiseUserFlow@2x.png
index 815c41dd..fff1d353 100644
Binary files a/1-js/10-es-modern/3-promise/promiseUserFlow@2x.png and b/1-js/10-es-modern/3-promise/promiseUserFlow@2x.png differ
diff --git a/1-js/10-es-modern/3-promise/user-no-guthub.json b/1-js/10-es-modern/3-promise/user-no-guthub.json
new file mode 100644
index 00000000..9e23f32b
--- /dev/null
+++ b/1-js/10-es-modern/3-promise/user-no-guthub.json
@@ -0,0 +1,4 @@
+{
+ "name": "an-unknown-person-32662",
+ "isAdmin": false
+}
diff --git a/1-js/10-es-modern/3-promise/userNoGithub.json b/1-js/10-es-modern/3-promise/userNoGithub.json
new file mode 100644
index 00000000..9e23f32b
--- /dev/null
+++ b/1-js/10-es-modern/3-promise/userNoGithub.json
@@ -0,0 +1,4 @@
+{
+ "name": "an-unknown-person-32662",
+ "isAdmin": false
+}
diff --git a/1-js/10-es-modern/index.md b/1-js/10-es-modern/index.md
index 3791b281..0e5ff0bc 100644
--- a/1-js/10-es-modern/index.md
+++ b/1-js/10-es-modern/index.md
@@ -1,4 +1,4 @@
-# Современные возможности ES-2015
+# Современные возможности ES-2015 [в работе]
Современный стандарт ES-2015 и его расширения для JavaScript.
diff --git a/1-js/4-data-structures/7-array/array-pop.png b/1-js/4-data-structures/7-array/array-pop.png
index af9d78be..672d87a9 100644
Binary files a/1-js/4-data-structures/7-array/array-pop.png and b/1-js/4-data-structures/7-array/array-pop.png differ
diff --git a/1-js/4-data-structures/7-array/array-pop@2x.png b/1-js/4-data-structures/7-array/array-pop@2x.png
index 223a3f62..0fd34a87 100644
Binary files a/1-js/4-data-structures/7-array/array-pop@2x.png and b/1-js/4-data-structures/7-array/array-pop@2x.png differ
diff --git a/1-js/4-data-structures/7-array/array-shift.png b/1-js/4-data-structures/7-array/array-shift.png
index 37cd1218..2236d731 100644
Binary files a/1-js/4-data-structures/7-array/array-shift.png and b/1-js/4-data-structures/7-array/array-shift.png differ
diff --git a/1-js/4-data-structures/7-array/array-shift@2x.png b/1-js/4-data-structures/7-array/array-shift@2x.png
index e94202db..5e36dda7 100644
Binary files a/1-js/4-data-structures/7-array/array-shift@2x.png and b/1-js/4-data-structures/7-array/array-shift@2x.png differ
diff --git a/1-js/4-data-structures/7-array/array-speed.png b/1-js/4-data-structures/7-array/array-speed.png
index d7989367..fee6b518 100644
Binary files a/1-js/4-data-structures/7-array/array-speed.png and b/1-js/4-data-structures/7-array/array-speed.png differ
diff --git a/1-js/4-data-structures/7-array/array-speed@2x.png b/1-js/4-data-structures/7-array/array-speed@2x.png
index 4c38c9a9..4419e1cd 100644
Binary files a/1-js/4-data-structures/7-array/array-speed@2x.png and b/1-js/4-data-structures/7-array/array-speed@2x.png differ
diff --git a/1-js/4-data-structures/8-array-methods/9-output-single-linked-list/linked-list.png b/1-js/4-data-structures/8-array-methods/9-output-single-linked-list/linked-list.png
index 1a5ae35e..0e714094 100644
Binary files a/1-js/4-data-structures/8-array-methods/9-output-single-linked-list/linked-list.png and b/1-js/4-data-structures/8-array-methods/9-output-single-linked-list/linked-list.png differ
diff --git a/1-js/4-data-structures/8-array-methods/9-output-single-linked-list/linked-list@2x.png b/1-js/4-data-structures/8-array-methods/9-output-single-linked-list/linked-list@2x.png
index 73eabc39..feeefb72 100644
Binary files a/1-js/4-data-structures/8-array-methods/9-output-single-linked-list/linked-list@2x.png and b/1-js/4-data-structures/8-array-methods/9-output-single-linked-list/linked-list@2x.png differ
diff --git a/1-js/4-data-structures/9-array-iteration/reduce.png b/1-js/4-data-structures/9-array-iteration/reduce.png
index 9cc46dee..5ca1b5a0 100644
Binary files a/1-js/4-data-structures/9-array-iteration/reduce.png and b/1-js/4-data-structures/9-array-iteration/reduce.png differ
diff --git a/1-js/4-data-structures/9-array-iteration/reduce@2x.png b/1-js/4-data-structures/9-array-iteration/reduce@2x.png
index 3264c699..0140b5d2 100644
Binary files a/1-js/4-data-structures/9-array-iteration/reduce@2x.png and b/1-js/4-data-structures/9-array-iteration/reduce@2x.png differ
diff --git a/1-js/5-functions-closures/6-memory-management/family-no-family.png b/1-js/5-functions-closures/6-memory-management/family-no-family.png
index fe544cce..f37ef2a6 100644
Binary files a/1-js/5-functions-closures/6-memory-management/family-no-family.png and b/1-js/5-functions-closures/6-memory-management/family-no-family.png differ
diff --git a/1-js/5-functions-closures/6-memory-management/family-no-family@2x.png b/1-js/5-functions-closures/6-memory-management/family-no-family@2x.png
index db0d823b..9764e2e8 100644
Binary files a/1-js/5-functions-closures/6-memory-management/family-no-family@2x.png and b/1-js/5-functions-closures/6-memory-management/family-no-family@2x.png differ
diff --git a/1-js/5-functions-closures/6-memory-management/family-no-father-2.png b/1-js/5-functions-closures/6-memory-management/family-no-father-2.png
index cab6f9a5..663a361e 100644
Binary files a/1-js/5-functions-closures/6-memory-management/family-no-father-2.png and b/1-js/5-functions-closures/6-memory-management/family-no-father-2.png differ
diff --git a/1-js/5-functions-closures/6-memory-management/family-no-father-2@2x.png b/1-js/5-functions-closures/6-memory-management/family-no-father-2@2x.png
index 9cebdd4b..b0062c97 100644
Binary files a/1-js/5-functions-closures/6-memory-management/family-no-father-2@2x.png and b/1-js/5-functions-closures/6-memory-management/family-no-father-2@2x.png differ
diff --git a/1-js/5-functions-closures/6-memory-management/family-no-father.png b/1-js/5-functions-closures/6-memory-management/family-no-father.png
index 2c5ea4e1..3b410731 100644
Binary files a/1-js/5-functions-closures/6-memory-management/family-no-father.png and b/1-js/5-functions-closures/6-memory-management/family-no-father.png differ
diff --git a/1-js/5-functions-closures/6-memory-management/family-no-father@2x.png b/1-js/5-functions-closures/6-memory-management/family-no-father@2x.png
index 870e1c3e..2eaa35f2 100644
Binary files a/1-js/5-functions-closures/6-memory-management/family-no-father@2x.png and b/1-js/5-functions-closures/6-memory-management/family-no-father@2x.png differ
diff --git a/1-js/5-functions-closures/6-memory-management/family.png b/1-js/5-functions-closures/6-memory-management/family.png
index 231170b2..58edaa55 100644
Binary files a/1-js/5-functions-closures/6-memory-management/family.png and b/1-js/5-functions-closures/6-memory-management/family.png differ
diff --git a/1-js/5-functions-closures/6-memory-management/family@2x.png b/1-js/5-functions-closures/6-memory-management/family@2x.png
index 95b0e7e7..7d9e98a5 100644
Binary files a/1-js/5-functions-closures/6-memory-management/family@2x.png and b/1-js/5-functions-closures/6-memory-management/family@2x.png differ
diff --git a/1-js/7-js-misc/3-setTimeout-setInterval/setinterval-interval.png b/1-js/7-js-misc/3-setTimeout-setInterval/setinterval-interval.png
index 51c4bdfe..0a815bdb 100644
Binary files a/1-js/7-js-misc/3-setTimeout-setInterval/setinterval-interval.png and b/1-js/7-js-misc/3-setTimeout-setInterval/setinterval-interval.png differ
diff --git a/1-js/7-js-misc/3-setTimeout-setInterval/setinterval-interval@2x.png b/1-js/7-js-misc/3-setTimeout-setInterval/setinterval-interval@2x.png
index 672b106d..1e764160 100644
Binary files a/1-js/7-js-misc/3-setTimeout-setInterval/setinterval-interval@2x.png and b/1-js/7-js-misc/3-setTimeout-setInterval/setinterval-interval@2x.png differ
diff --git a/1-js/7-js-misc/3-setTimeout-setInterval/settimeout-interval.png b/1-js/7-js-misc/3-setTimeout-setInterval/settimeout-interval.png
index 364f909d..b6909cc2 100644
Binary files a/1-js/7-js-misc/3-setTimeout-setInterval/settimeout-interval.png and b/1-js/7-js-misc/3-setTimeout-setInterval/settimeout-interval.png differ
diff --git a/1-js/7-js-misc/3-setTimeout-setInterval/settimeout-interval@2x.png b/1-js/7-js-misc/3-setTimeout-setInterval/settimeout-interval@2x.png
index b4f5685a..657ec0db 100644
Binary files a/1-js/7-js-misc/3-setTimeout-setInterval/settimeout-interval@2x.png and b/1-js/7-js-misc/3-setTimeout-setInterval/settimeout-interval@2x.png differ
diff --git a/1-js/9-prototypes/1-prototype/proto-animal-rabbit.png b/1-js/9-prototypes/1-prototype/proto-animal-rabbit.png
index 80888f27..c2b6ede2 100644
Binary files a/1-js/9-prototypes/1-prototype/proto-animal-rabbit.png and b/1-js/9-prototypes/1-prototype/proto-animal-rabbit.png differ
diff --git a/1-js/9-prototypes/1-prototype/proto-animal-rabbit@2x.png b/1-js/9-prototypes/1-prototype/proto-animal-rabbit@2x.png
index b5395718..d0e116d8 100644
Binary files a/1-js/9-prototypes/1-prototype/proto-animal-rabbit@2x.png and b/1-js/9-prototypes/1-prototype/proto-animal-rabbit@2x.png differ
diff --git a/1-js/9-prototypes/3-native-prototypes/native-prototypes-array-tostring.png b/1-js/9-prototypes/3-native-prototypes/native-prototypes-array-tostring.png
index 2338e7b5..4ed5dbd4 100644
Binary files a/1-js/9-prototypes/3-native-prototypes/native-prototypes-array-tostring.png and b/1-js/9-prototypes/3-native-prototypes/native-prototypes-array-tostring.png differ
diff --git a/1-js/9-prototypes/3-native-prototypes/native-prototypes-array-tostring@2x.png b/1-js/9-prototypes/3-native-prototypes/native-prototypes-array-tostring@2x.png
index f90ce022..757f4041 100644
Binary files a/1-js/9-prototypes/3-native-prototypes/native-prototypes-array-tostring@2x.png and b/1-js/9-prototypes/3-native-prototypes/native-prototypes-array-tostring@2x.png differ
diff --git a/1-js/9-prototypes/3-native-prototypes/native-prototypes-classes.png b/1-js/9-prototypes/3-native-prototypes/native-prototypes-classes.png
index 0b80717b..e1135834 100644
Binary files a/1-js/9-prototypes/3-native-prototypes/native-prototypes-classes.png and b/1-js/9-prototypes/3-native-prototypes/native-prototypes-classes.png differ
diff --git a/1-js/9-prototypes/3-native-prototypes/native-prototypes-classes@2x.png b/1-js/9-prototypes/3-native-prototypes/native-prototypes-classes@2x.png
index 26bbec9e..db1a0b8e 100644
Binary files a/1-js/9-prototypes/3-native-prototypes/native-prototypes-classes@2x.png and b/1-js/9-prototypes/3-native-prototypes/native-prototypes-classes@2x.png differ
diff --git a/1-js/9-prototypes/3-native-prototypes/native-prototypes-object.png b/1-js/9-prototypes/3-native-prototypes/native-prototypes-object.png
index b1c549f3..125f68e2 100644
Binary files a/1-js/9-prototypes/3-native-prototypes/native-prototypes-object.png and b/1-js/9-prototypes/3-native-prototypes/native-prototypes-object.png differ
diff --git a/1-js/9-prototypes/3-native-prototypes/native-prototypes-object@2x.png b/1-js/9-prototypes/3-native-prototypes/native-prototypes-object@2x.png
index a303eb36..77cdf9c5 100644
Binary files a/1-js/9-prototypes/3-native-prototypes/native-prototypes-object@2x.png and b/1-js/9-prototypes/3-native-prototypes/native-prototypes-object@2x.png differ
diff --git a/1-js/9-prototypes/5-class-inheritance/class-inheritance-array-object.png b/1-js/9-prototypes/5-class-inheritance/class-inheritance-array-object.png
index b03e9fbb..5de99e36 100644
Binary files a/1-js/9-prototypes/5-class-inheritance/class-inheritance-array-object.png and b/1-js/9-prototypes/5-class-inheritance/class-inheritance-array-object.png differ
diff --git a/1-js/9-prototypes/5-class-inheritance/class-inheritance-array-object@2x.png b/1-js/9-prototypes/5-class-inheritance/class-inheritance-array-object@2x.png
index 6bd075a3..31e5da8e 100644
Binary files a/1-js/9-prototypes/5-class-inheritance/class-inheritance-array-object@2x.png and b/1-js/9-prototypes/5-class-inheritance/class-inheritance-array-object@2x.png differ
diff --git a/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-animal.png b/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-animal.png
index 09d18806..d242a125 100644
Binary files a/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-animal.png and b/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-animal.png differ
diff --git a/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-animal@2x.png b/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-animal@2x.png
index 52518f91..64906600 100644
Binary files a/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-animal@2x.png and b/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-animal@2x.png differ
diff --git a/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-run-animal.png b/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-run-animal.png
index 5c669a71..3f479cec 100644
Binary files a/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-run-animal.png and b/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-run-animal.png differ
diff --git a/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-run-animal@2x.png b/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-run-animal@2x.png
index 4583fbc0..1bd04c3a 100644
Binary files a/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-run-animal@2x.png and b/1-js/9-prototypes/5-class-inheritance/class-inheritance-rabbit-run-animal@2x.png differ
diff --git a/2-ui/1-document/1-browser-environment/windowObjects.png b/2-ui/1-document/1-browser-environment/windowObjects.png
index 8c499eac..a06085ce 100644
Binary files a/2-ui/1-document/1-browser-environment/windowObjects.png and b/2-ui/1-document/1-browser-environment/windowObjects.png differ
diff --git a/2-ui/1-document/1-browser-environment/windowObjects@2x.png b/2-ui/1-document/1-browser-environment/windowObjects@2x.png
index 0e9ba1e5..8446fdfd 100644
Binary files a/2-ui/1-document/1-browser-environment/windowObjects@2x.png and b/2-ui/1-document/1-browser-environment/windowObjects@2x.png differ
diff --git a/2-ui/1-document/17-coordinates/coords.png b/2-ui/1-document/17-coordinates/coords.png
index 01620d5e..2f7fb46d 100644
Binary files a/2-ui/1-document/17-coordinates/coords.png and b/2-ui/1-document/17-coordinates/coords.png differ
diff --git a/2-ui/1-document/17-coordinates/coords@2x.png b/2-ui/1-document/17-coordinates/coords@2x.png
index c1245744..a832cc33 100644
Binary files a/2-ui/1-document/17-coordinates/coords@2x.png and b/2-ui/1-document/17-coordinates/coords@2x.png differ
diff --git a/2-ui/1-document/4-traversing-dom/dom-links-elements.png b/2-ui/1-document/4-traversing-dom/dom-links-elements.png
index 8683e6e7..ee1516d4 100644
Binary files a/2-ui/1-document/4-traversing-dom/dom-links-elements.png and b/2-ui/1-document/4-traversing-dom/dom-links-elements.png differ
diff --git a/2-ui/1-document/4-traversing-dom/dom-links-elements@2x.png b/2-ui/1-document/4-traversing-dom/dom-links-elements@2x.png
index 3331f572..42b8549a 100644
Binary files a/2-ui/1-document/4-traversing-dom/dom-links-elements@2x.png and b/2-ui/1-document/4-traversing-dom/dom-links-elements@2x.png differ
diff --git a/2-ui/1-document/4-traversing-dom/dom-links.png b/2-ui/1-document/4-traversing-dom/dom-links.png
index f5b2b707..a3371ab0 100644
Binary files a/2-ui/1-document/4-traversing-dom/dom-links.png and b/2-ui/1-document/4-traversing-dom/dom-links.png differ
diff --git a/2-ui/1-document/4-traversing-dom/dom-links@2x.png b/2-ui/1-document/4-traversing-dom/dom-links@2x.png
index bbd339ff..b5e3a4e7 100644
Binary files a/2-ui/1-document/4-traversing-dom/dom-links@2x.png and b/2-ui/1-document/4-traversing-dom/dom-links@2x.png differ
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside.png b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside.png
index 04000687..e58bb5a2 100644
Binary files a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside.png and b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside.png differ
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside@2x.png b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside@2x.png
index 022d169d..22ec22ca 100644
Binary files a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside@2x.png and b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside@2x.png differ
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems.png b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems.png
index ac003f9b..72244fde 100644
Binary files a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems.png and b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems.png differ
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems@2x.png b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems@2x.png
index 65ce484c..57a88e22 100644
Binary files a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems@2x.png and b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems@2x.png differ
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout.png b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout.png
index 789ad11d..b00b09f1 100644
Binary files a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout.png and b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout.png differ
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout@2x.png b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout@2x.png
index 09e8dea3..761d2157 100644
Binary files a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout@2x.png and b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout@2x.png differ
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-to-child.png b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-to-child.png
index 00a433d6..0bf4b029 100644
Binary files a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-to-child.png and b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-to-child.png differ
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-to-child@2x.png b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-to-child@2x.png
index 39b9561e..15cee968 100644
Binary files a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-to-child@2x.png and b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-to-child@2x.png differ
diff --git a/4-ajax/5-xhr-crossdomain/xhr-another-domain.png b/4-ajax/5-xhr-crossdomain/xhr-another-domain.png
index f24acf97..c65826d5 100644
Binary files a/4-ajax/5-xhr-crossdomain/xhr-another-domain.png and b/4-ajax/5-xhr-crossdomain/xhr-another-domain.png differ
diff --git a/4-ajax/5-xhr-crossdomain/xhr-another-domain@2x.png b/4-ajax/5-xhr-crossdomain/xhr-another-domain@2x.png
index c5564287..478bd94c 100644
Binary files a/4-ajax/5-xhr-crossdomain/xhr-another-domain@2x.png and b/4-ajax/5-xhr-crossdomain/xhr-another-domain@2x.png differ
diff --git a/4-ajax/5-xhr-crossdomain/xhr-preflight.png b/4-ajax/5-xhr-crossdomain/xhr-preflight.png
index 365dd66e..86b9a502 100644
Binary files a/4-ajax/5-xhr-crossdomain/xhr-preflight.png and b/4-ajax/5-xhr-crossdomain/xhr-preflight.png differ
diff --git a/4-ajax/5-xhr-crossdomain/xhr-preflight@2x.png b/4-ajax/5-xhr-crossdomain/xhr-preflight@2x.png
index 707ba32a..7556e679 100644
Binary files a/4-ajax/5-xhr-crossdomain/xhr-preflight@2x.png and b/4-ajax/5-xhr-crossdomain/xhr-preflight@2x.png differ
diff --git a/6-optimize/4-memory-leaks/leak-xhr-2.png b/6-optimize/4-memory-leaks/leak-xhr-2.png
index 73090cf1..9f9e90f4 100644
Binary files a/6-optimize/4-memory-leaks/leak-xhr-2.png and b/6-optimize/4-memory-leaks/leak-xhr-2.png differ
diff --git a/6-optimize/4-memory-leaks/leak-xhr-2@2x.png b/6-optimize/4-memory-leaks/leak-xhr-2@2x.png
index 803d9b87..4cbddbf5 100644
Binary files a/6-optimize/4-memory-leaks/leak-xhr-2@2x.png and b/6-optimize/4-memory-leaks/leak-xhr-2@2x.png differ
diff --git a/figures.sketch b/figures.sketch
index 8a53a83a..dea8516d 100644
Binary files a/figures.sketch and b/figures.sketch differ