diff --git a/1-js/10-es-modern/16-generator/article.md b/1-js/10-es-modern/16-generator/article.md
new file mode 100644
index 00000000..465a6242
--- /dev/null
+++ b/1-js/10-es-modern/16-generator/article.md
@@ -0,0 +1,335 @@
+
+# Генераторы
+
+Генераторы -- новый вид функций в современном JavaScript. Они отличаются от обычных тем, что могут приостанавливать своё выполнение, возвращать промежуточный результат и далее возобновлять его позже, в произвольный момент времени.
+
+## Создание генератора
+
+Для объявления генератора используется новая синтаксическая конструкция: `function*` (функция со звёздочкой).
+
+Её называют "функция-генератор" (generator function).
+
+Выглядит это так:
+
+```js
+function* generateSequence() {
+ yield 1;
+ yield 2;
+ return 3;
+}
+```
+
+При запуске `generateSequence()` код такой функции не выполняется!
+
+Вместо этого она возвращает специальный объект, который как раз и называют "генератором".
+
+```js
+// generator function создаёт generator
+let generator = generateSequence();
+```
+
+Правильнее всего будет воспринимать генератор как "замороженный вызов функции":
+
+
+
+При создании генератора код находится в начале своего выполнения.
+
+Основным методом генератора является `next()`. При вызове он возобновляет выполнение кода до ближайшего ключевого слова `yield`. По достижении `yield` выполнение приостанавливается, а значение -- возвращается во внешний код:
+
+```js
+//+ run
+'use strict';
+
+function* generateSequence() {
+ yield 1;
+ yield 2;
+ return 3;
+}
+
+let generator = generateSequence();
+
+let one = generator.next();
+
+alert(JSON.stringify(one)); // {value: 1, done: false}
+```
+
+
+
+Повторный вызов `generator.next()` возобновит выполнение и вернёт результат следующего `yield`:
+
+```js
+let two = generator.next();
+
+alert(JSON.stringify(two)); // {value: 2, done: false}
+```
+
+
+
+И, наконец, последний вызов завершит выполнение функции и вернёт результат `return`:
+
+```js
+let three = generator.next();
+
+alert(JSON.stringify(three)); // {value: 3, *!*done: true*/!*}
+```
+
+
+
+
+Функция завершена. Внешний код должен увидить это из свойства `done:true` и прекратить вызовы. Впрочем, если новые вызовы `generator.next()` и будут, то они не вызовут ошибки, но будут возвращать один и тот же объект: `{done: true}`.
+
+"Открутить назад" завершившийся генератор нельзя, но можно создать новый ещё одним вызовом `generateSequence()` и выполнить его.
+
+## Генератор -- итератор
+
+Как вы, наверно, уже догадались по наличию метода `next()`, генератор является итерируемым объектом.
+
+Его можно перебирать и через `for..of`:
+
+```js
+//+ run
+'use strict';
+
+function* generateSequence() {
+ yield 1;
+ yield 2;
+ return 3;
+}
+
+let generator = generateSequence();
+
+for(let value of generator) {
+ alert(value); // 1, затем 2
+}
+```
+
+Заметим, однако, существенную особенность такого перебора!
+
+При запуске примера выше будет выведено значение `1`, затем `2`. Значение `3` выведено не будет. Это потому что стандартные перебор итератора игнорирует `value` на последнем значении, при `done: true`. Так что результат `return` в цикле `for..of` не выводится.
+
+Соответственно, если мы хотим, чтобы все значения возвращались при переборе через `for..of`, то надо возвращать их через `yield`:
+
+
+```js
+//+ run
+'use strict';
+
+function* generateSequence() {
+ yield 1;
+ yield 2;
+*!*
+ yield 3;
+*/!*
+}
+
+let generator = generateSequence();
+
+for(let value of generator) {
+ alert(value); // 1, затем 2, затем 3
+}
+```
+
+...А зачем вообще `return` при таком раскладе, если его результат игнорируется? Он тоже нужен, но в других ситуациях. Перебор через `for..of` -- в некотором смысле "исключение". Как мы увидим дальше, в других контекстах `return` очень даже востребован.
+
+## Композиция генераторов
+
+Один генератор может включать в себя другие. Это называется композицией.
+
+Разберём композицию на примере.
+
+Пусть у нас есть функция `generateSequence`, которая генерирует последовательность чисел:
+
+```js
+//+ run
+'use strict';
+
+function* generateSequence(start, end) {
+
+ for (let i = start; i <= end; i++) {
+ yield i;
+ }
+
+}
+
+// Используем оператор … для преобразования итерируемого объекта в массив
+let sequence = [...generateSequence(2,5)];
+
+alert(sequence); // 2, 3, 4, 5
+```
+
+Мы хотим на её основе сделать другую функцию `generateAlphaNumCodes()`, которая будет генерировать коды для буквенно-цифровых символов латинского алфавита:
+
+
+- `48..57` -- для `0..9`
+- `65..90` -- для `A..Z`
+- `97..122` -- для `a..z`
+
+
+Далее этот набор кодов можно превратить в строку и использовать, к примеру, для выбора из него случайного пароля. Только символы пунктуации ещё хорошо бы добавить для надёжности, но в этом примере мы будем без них.
+
+Естественно, раз в нашем распоряжении есть готовый генератор `generateSequence`, то хорошо бы его использовать.
+
+Конечно, можно внутри `generateAlphaNum` запустить несколько `generateSequence`, объединить результаты и вернуть, но композиция -- это кое-что получше.
+
+Она выглядит так:
+
+```js
+//+ run
+'use strict';
+
+function* generateSequence(start, end) {
+ for (let i = start; i <= end; i++) yield i;
+}
+
+function* generateAlphaNum() {
+
+*!*
+ // 0..9
+ yield* generateSequence(48, 57);
+
+ // A..Z
+ yield* generateSequence(65, 90);
+
+ // a..z
+ yield* generateSequence(97, 122);
+*/!*
+
+}
+
+let str = '';
+
+for(let code of generateAlphaNum()) {
+ str += String.fromCharCode(code);
+}
+
+alert(str); // 0..9A..Za..z
+```
+
+Здесь использована специальная форма `yield*`. Она применима только к другому генератору и *делегирует* ему выполнение.
+
+То есть, при `yield*` интерпретатор переходит внутрь генератора-аргумента, к примеру, `generateSequence(48, 57)`, выполняет его, и все `yield`, которые он делает, выходят из внешнего генератора.
+
+Получается -- как будто мы вставили код внутреннего генератора во внешний напрямую, вот так:
+
+```js
+//+ run
+'use strict';
+
+function* generateSequence(start, end) {
+ for (let i = start; i <= end; i++) yield i;
+}
+
+function* generateAlphaNum() {
+
+*!*
+ // yield* generateSequence(48, 57);
+ for (let i = 48; i <= 57; i++) yield i;
+
+ // yield* generateSequence(65, 90);
+ for (let i = 65; i <= 90; i++) yield i;
+
+ // yield* generateSequence(97, 122);
+ for (let i = 97; i <= 122; i++) yield i;
+*/!*
+
+}
+
+let str = '';
+
+for(let code of generateAlphaNum()) {
+ str += String.fromCharCode(code);
+}
+
+alert(str); // 0..9A..Za..z
+```
+
+## yield -- дорога в обе стороны
+
+До этого генераторы наиболее напоминали "итераторы на стероидах". Но, как мы сейчас увидим, это не так, есть фундаментальное различие, генераторы гораздо мощнее и гибче.
+
+Всё дело в том, что `yield` -- дорога в обе стороны: он не только возвращает результат наружу, но и может передавать значение извне в генератор.
+
+Вызов `let result = yield value` делает следующее:
+
+
+- Возвращает `value` во внешний код, приостанавливая выполнение генератора.
+- Внешний код может обработать значение, и затем вызвать `next` с аргументом: `generator.next(result)`.
+- Генератор продолжит выполнение, этот аргумент будет записан в `result`.
+
+
+Продемонстрируем это на примере:
+
+```js
+//+ run
+'use strict';
+
+function* gen() {
+*!*
+ // Передать вопрос во внешний код и подождать ответа
+ let result = yield "Сколько будет 2 + 2?";
+*/!*
+
+ alert(result);
+}
+
+let generator = gen();
+
+let question = generator.next().value;
+// { value: "Сколько будет 2 + 2?", done: false }
+
+setTimeout(() => generator.next(4), 2000);
+```
+
+
+
+Выше проиллюстрировано то, что происходит в генераторе:
+
+
+- Первый `.next()` всегда без аргумента, он начинает выполнение и возвращает результат первого `yield`.
+- Результат `yield` переходит во внешний код (в `question`), он может выполнять любые асинхронные задачи.
+- Когда асинхронные задачи готовы, внешний код вызывает `.next(result)`, при этом выполнение продолжается, а `result` выходит из присваивания как результат `yield`.
+
+
+Посмотрим вариант побольше:
+
+```js
+//+ run
+'use strict';
+
+function* gen() {
+ let ask1 = yield "Сколько будет 2 + 2?";
+
+ alert(ask1); // 4
+
+ let ask2 = yield "А сколько будет 3 * 3?"
+
+ alert(ask2); // 9
+}
+
+let generator = gen();
+
+alert( generator.next().value ); // "...2+2?"
+
+alert( generator.next(4).value ); // "...3*3?"
+
+alert( generator.next(9).done ); // true
+```
+
+
+
+
+- Первый `.next()` начинает выполнение... Оно доходит до первого `yield`.
+- Результат возвращается во внешний код.
+- Второй `.next(4)` передаёт `4` обратно в генератор как результат первого `yield` и возобновляет выполнение.
+- ...Оно доходит до второго `yield`, который станет результатом `.next(4)`.
+- Третий `next(9)` передаёт `9` в генератор как результат второго `yield` и возобновляет выполнение, которое завершается окончанием функции, так что `done: true`.
+
+
+Получается "пинг-понг": каждый `next(value)` передаёт в генератор значение, которое становится результатом текущего `yield`, возобновляет выполнение и получает выражение из следующего `yield`.
+
+
+
+Исключением является первый вызов `next`, который не может передать значение в генератор, т.к. ещё не было ни одного `yield`.
+
+
+
diff --git a/1-js/10-es-modern/16-generator/genYield2-2.png b/1-js/10-es-modern/16-generator/genYield2-2.png
new file mode 100644
index 00000000..ea646d05
Binary files /dev/null and b/1-js/10-es-modern/16-generator/genYield2-2.png differ
diff --git a/1-js/10-es-modern/16-generator/genYield2-2@2x.png b/1-js/10-es-modern/16-generator/genYield2-2@2x.png
new file mode 100644
index 00000000..9aa7a21d
Binary files /dev/null and b/1-js/10-es-modern/16-generator/genYield2-2@2x.png differ
diff --git a/1-js/10-es-modern/16-generator/genYield2-3.png b/1-js/10-es-modern/16-generator/genYield2-3.png
new file mode 100644
index 00000000..c1d48604
Binary files /dev/null and b/1-js/10-es-modern/16-generator/genYield2-3.png differ
diff --git a/1-js/10-es-modern/16-generator/genYield2-3@2x.png b/1-js/10-es-modern/16-generator/genYield2-3@2x.png
new file mode 100644
index 00000000..844742cb
Binary files /dev/null and b/1-js/10-es-modern/16-generator/genYield2-3@2x.png differ
diff --git a/1-js/10-es-modern/16-generator/genYield2.png b/1-js/10-es-modern/16-generator/genYield2.png
new file mode 100644
index 00000000..5efec0b9
Binary files /dev/null and b/1-js/10-es-modern/16-generator/genYield2.png differ
diff --git a/1-js/10-es-modern/16-generator/genYield2@2x.png b/1-js/10-es-modern/16-generator/genYield2@2x.png
new file mode 100644
index 00000000..440263b5
Binary files /dev/null and b/1-js/10-es-modern/16-generator/genYield2@2x.png differ
diff --git a/1-js/10-es-modern/16-generator/generateSequence-1.png b/1-js/10-es-modern/16-generator/generateSequence-1.png
new file mode 100644
index 00000000..c5016287
Binary files /dev/null and b/1-js/10-es-modern/16-generator/generateSequence-1.png differ
diff --git a/1-js/10-es-modern/16-generator/generateSequence-1@2x.png b/1-js/10-es-modern/16-generator/generateSequence-1@2x.png
new file mode 100644
index 00000000..2a1e0f68
Binary files /dev/null and b/1-js/10-es-modern/16-generator/generateSequence-1@2x.png differ
diff --git a/1-js/10-es-modern/16-generator/generateSequence-2.png b/1-js/10-es-modern/16-generator/generateSequence-2.png
new file mode 100644
index 00000000..65e1e58e
Binary files /dev/null and b/1-js/10-es-modern/16-generator/generateSequence-2.png differ
diff --git a/1-js/10-es-modern/16-generator/generateSequence-2@2x.png b/1-js/10-es-modern/16-generator/generateSequence-2@2x.png
new file mode 100644
index 00000000..473c2ee4
Binary files /dev/null and b/1-js/10-es-modern/16-generator/generateSequence-2@2x.png differ
diff --git a/1-js/10-es-modern/16-generator/generateSequence-3.png b/1-js/10-es-modern/16-generator/generateSequence-3.png
new file mode 100644
index 00000000..8bc4418f
Binary files /dev/null and b/1-js/10-es-modern/16-generator/generateSequence-3.png differ
diff --git a/1-js/10-es-modern/16-generator/generateSequence-3@2x.png b/1-js/10-es-modern/16-generator/generateSequence-3@2x.png
new file mode 100644
index 00000000..d28d52bf
Binary files /dev/null and b/1-js/10-es-modern/16-generator/generateSequence-3@2x.png differ
diff --git a/1-js/10-es-modern/16-generator/generateSequence-4.png b/1-js/10-es-modern/16-generator/generateSequence-4.png
new file mode 100644
index 00000000..53064927
Binary files /dev/null and b/1-js/10-es-modern/16-generator/generateSequence-4.png differ
diff --git a/1-js/10-es-modern/16-generator/generateSequence-4@2x.png b/1-js/10-es-modern/16-generator/generateSequence-4@2x.png
new file mode 100644
index 00000000..d19b217c
Binary files /dev/null and b/1-js/10-es-modern/16-generator/generateSequence-4@2x.png differ
diff --git a/1-js/10-es-modern/6-es-objects/article.md b/1-js/10-es-modern/6-es-object/article.md
similarity index 100%
rename from 1-js/10-es-modern/6-es-objects/article.md
rename to 1-js/10-es-modern/6-es-object/article.md
diff --git a/1-js/10-es-modern/7-es-classes/article.md b/1-js/10-es-modern/7-es-class/article.md
similarity index 100%
rename from 1-js/10-es-modern/7-es-classes/article.md
rename to 1-js/10-es-modern/7-es-class/article.md
diff --git a/1-js/10-es-modern/9-iterators/article.md b/1-js/10-es-modern/9-iterator/article.md
similarity index 100%
rename from 1-js/10-es-modern/9-iterators/article.md
rename to 1-js/10-es-modern/9-iterator/article.md
diff --git a/2-ui/3-event-details/9-keyboard-events/article.md b/2-ui/3-event-details/9-keyboard-events/article.md
index 6fc0f579..815716ff 100644
--- a/2-ui/3-event-details/9-keyboard-events/article.md
+++ b/2-ui/3-event-details/9-keyboard-events/article.md
@@ -215,7 +215,7 @@ document.getElementById('only-upper').onkeypress = function(e) {
[/online]
-## Невосместимости [#keyboard-events-order]
+## Несовместимости [#keyboard-events-order]
Некоторые несовместимости в порядке срабатывания клавиатурных событий (когда что) ещё существуют.
diff --git a/figures.sketch b/figures.sketch
index dea8516d..40ea4688 100644
Binary files a/figures.sketch and b/figures.sketch differ