diff --git a/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/_js.view/solution.js b/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/_js.view/solution.js
new file mode 100644
index 00000000..106b9ca8
--- /dev/null
+++ b/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/_js.view/solution.js
@@ -0,0 +1,28 @@
+function formatDate(date) {
+ if (typeof date == 'number') {
+ // перевести секунды в миллисекунды и преобразовать к Date
+ date = new Date(date * 1000);
+ } else if (typeof date == 'string') {
+ // разобрать строку и преобразовать к Date
+ date = date.split('-');
+ date = new Date(date[0], date[1] - 1, date[2]);
+ } else if (Array.isArray(date)) {
+ date = new Date(date[0], date[1], date[2]);
+ }
+ // преобразования для поддержки полиморфизма завершены,
+ // теперь мы работаем с датой (форматируем её)
+
+ var day = date.getDate();
+ if (day < 10) day = '0' + day;
+
+ var month = date.getMonth() + 1;
+ if (month < 10) month = '0' + month;
+
+ // взять 2 последние цифры года
+ var year = date.getFullYear() % 100;
+ if (year < 10) year = '0' + year;
+
+ var formattedDate = day + '.' + month + '.' + year;
+
+ return formattedDate;
+}
\ No newline at end of file
diff --git a/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/_js.view/test.js b/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/_js.view/test.js
new file mode 100644
index 00000000..a458b62f
--- /dev/null
+++ b/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/_js.view/test.js
@@ -0,0 +1,18 @@
+describe("formatDate", function() {
+ it("читает дату вида гггг-мм-дд из строки", function() {
+ assert.equal(formatDate('2011-10-02'), "02.10.11");
+ });
+
+ it("читает дату из числа 1234567890 (миллисекунды)", function() {
+ assert.equal(formatDate(1234567890), "14.02.09");
+ });
+
+ it("читает дату из массива вида [гггг, м, д]", function() {
+ assert.equal(formatDate([2014, 0, 1]), "01.01.14");
+ });
+
+ it("читает дату из объекта Date", function() {
+ assert.equal(formatDate(new Date(2014, 0, 1)), "01.01.14");
+ });
+
+});
\ No newline at end of file
diff --git a/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/solution.md b/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/solution.md
new file mode 100644
index 00000000..878033e9
--- /dev/null
+++ b/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/solution.md
@@ -0,0 +1,15 @@
+Для определения примитивного типа строка/число подойдет оператор [typeof](#type-typeof).
+
+Примеры его работы:
+
+```js
+//+ run
+alert( typeof 123 ); // "number"
+alert( typeof "строка" ); // "string"
+alert( typeof new Date() ); // "object"
+alert( typeof [] ); // "object"
+```
+
+Оператор `typeof` не умеет различать разные типы объектов, они для него все на одно лицо: `"object"`. Поэтому он не сможет отличить `Date` от `Array`.
+
+Для отличия `Array` используем вызов `Array.isArray`. Если он неверен, значит у нас дата.
\ No newline at end of file
diff --git a/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/task.md b/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/task.md
new file mode 100644
index 00000000..6dcf7974
--- /dev/null
+++ b/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/task.md
@@ -0,0 +1,26 @@
+# Полиморфная функция formatDate
+
+[importance 5]
+
+Напишите функцию `formatDate(date)`, которая возвращает дату в формате `dd.mm.yy`.
+
+Ее первый аргумент должен содержать дату в одном из видов:
+
+
Как объект `Date`.
+
Как строку в формате `yyyy-mm-dd`.
+
Как число *секунд* с `01.01.1970`.
+
Как массив `[гггг, мм, дд]`, месяц начинается с нуля
+
+Для этого вам понадобится определить тип данных аргумента и, при необходимости, преобразовать входные данные в нужный формат.
+
+Пример работы:
+
+```js
+function formatDate(date) { /* ваш код */ }
+
+alert( formatDate('2011-10-02') ); // 02.10.11
+alert( formatDate(1234567890) ); // 14.02.09
+alert( formatDate([2014, 0, 1]) ); // 01.01.14
+alert( formatDate(new Date(2014, 0, 1)) ); // 01.01.14
+```
+
diff --git a/1-js/7-js-misc/1-class-instanceof/article.md b/1-js/7-js-misc/1-class-instanceof/article.md
new file mode 100644
index 00000000..f84e41f6
--- /dev/null
+++ b/1-js/7-js-misc/1-class-instanceof/article.md
@@ -0,0 +1,252 @@
+# Типы данных: [[Class]], instanceof и утки
+
+Время от времени бывает удобно создавать так называемые "полиморфные" функции, то есть такие, которые по-разному обрабатывают аргументы, в зависимости от их типа. Например, функция вывода может по-разному форматировать числа и даты.
+
+Для реализации такой возможности нужен способ определить тип переменной.
+
+## Оператор typeof
+
+Мы уже знакомы с простейшим способом -- оператором [typeof](#type-typeof).
+
+Оператор `typeof` надежно работает с примитивными типами, кроме `null`, а также с функциями. Он возвращает для них тип в виде строки:
+
+```js
+//+ run no-beautify
+alert( typeof 1 ); // 'number'
+alert( typeof true ); // 'boolean'
+alert( typeof "Текст" ); // 'string'
+alert( typeof undefined ); // 'undefined'
+alert( typeof null ); // 'object' (ошибка в языке)
+alert( typeof alert ); // 'function'
+```
+
+...Но все объекты, включая массивы и даты для `typeof` -- на одно лицо, они имеют один тип `'object'`:
+
+```js
+//+ run
+alert( typeof {} ); // 'object'
+alert( typeof [] ); // 'object'
+alert( typeof new Date ); // 'object'
+```
+
+Поэтому различить их при помощи `typeof` нельзя, и в этом его основной недостаток.
+
+## Секретное свойство [[Class]]
+
+Для встроенных объектов есть одна "секретная" возможность узнать их тип, которая связана с методом `toString`.
+
+Во всех встроенных объектах есть специальное свойство `[[Class]]`, в котором хранится информация о его типе или конструкторе.
+
+Оно взято в квадратные скобки, так как это свойство -- внутреннее. Явно получить его нельзя, но можно прочитать его "в обход", воспользовавшись методом `toString` стандартного объекта `Object`.
+
+Его внутренняя реализация выводит `[[Class]]` в небольшом обрамлении, как `"[object значение]"`.
+
+Например:
+
+```js
+//+ run
+var toString = {}.toString;
+
+var arr = [1, 2];
+alert( toString.call(arr) ); // [object Array]
+
+var date = new Date;
+alert( toString.call(date) ); // [object Date]
+
+var obj = { name: "Вася" };
+alert( toString.call(date) ); // [object Object]
+```
+
+В первой строке мы взяли метод `toString`, принадлежащий именно стандартному объекту `{}`. Нам пришлось это сделать, так как у `Date` и `Array` -- свои собственные методы `toString`, которые работают иначе.
+
+Затем мы вызываем этот `toString` в контексте нужного объекта `obj`, и он возвращает его внутреннее, невидимое другими способами, свойство `[[Class]]`.
+
+**Для получения `[[Class]]` нужна именно внутренняя реализация `toString` стандартного объекта `Object`, другая не подойдёт.**
+
+К счастью, методы в JavaScript -- это всего лишь функции-свойства объекта, которые можно скопировать в переменную и применить на другом объекте через `call/apply`. Что мы и делаем для `{}.toString`.
+
+Метод также можно использовать с примитивами:
+
+```js
+//+ run
+alert( {}.toString.call(123) ); // [object Number]
+alert( {}.toString.call("строка") ); // [object String]
+```
+
+[warn header="Вызов `{}.toString` в консоли может выдать ошибку"]
+При тестировании кода в консоли вы можете обнаружить, что если ввести в командную строку `{}.toString.call(...)` -- будет ошибка. С другой стороны, вызов `alert( {}.toString... )` -- работает.
+
+Эта ошибка возникает потому, что фигурные скобки `{ }` в основном потоке кода интерпретируются как блок. Интерпретатор читает `{}.toString.call(...)` так:
+
+```js
+//+ no-beautify
+{ } // пустой блок кода
+.toString.call(...) // а что это за точка в начале? не понимаю, ошибка!
+```
+
+Фигурные скобки считаются объектом, только если они находятся в контексте выражения. В частности, оборачивание в скобки `( {}.toString... )` тоже сработает нормально.
+[/warn]
+
+
+Для большего удобства можно сделать функцию `getClass`, которая будет возвращать только сам `[[Class]]`:
+
+```js
+//+ run
+function getClass(obj) {
+ return {}.toString.call(obj).slice(8, -1);
+}
+
+alert( getClass(new Date) ); // Date
+alert( getClass([1, 2, 3]) ); // Array
+```
+
+Заметим, что свойство `[[Class]]` есть и доступно для чтения указанным способом -- у всех *встроенных* объектов. Но его нет у объектов, которые создают *наши функции*. Точнее, оно есть, но равно всегда `"Object"`.
+
+Например:
+
+```js
+//+ run
+function User() {}
+
+var user = new User();
+
+alert( {}.toString.call(user) ); // [object Object], не [object User]
+```
+
+Поэтому узнать тип таким образом можно только для встроенных объектов.
+
+## Метод Array.isArray()
+
+Для проверки на массивов есть специальный метод: `Array.isArray(arr)`. Он возвращает `true` только если `arr` -- массив:
+
+```js
+//+ run
+alert( Array.isArray([1,2,3]) ); // true
+alert( Array.isArray("not array")); // false
+```
+
+Но этот метод -- единственный в своём роде.
+
+Других аналогичных, типа `Object.isObject`, `Date.isDate` -- нет.
+
+
+## Оператор instanceof
+
+Оператор `instanceof` позволяет проверить, создан ли объект данной функцией, причём работает для любых функций -- как встроенных, так и наших.
+
+```js
+//+ run
+function User() {}
+
+var user = new User();
+
+alert( user instanceof User ); // true
+```
+
+Таким образом, `instanceof`, в отличие от `[[Class]]` и `typeof` может помочь выяснить тип для новых объектов, созданных нашими конструкторами.
+
+Заметим, что оператор `instanceof` -- сложнее, чем кажется. Он учитывает наследование, которое мы пока не проходили, но скоро изучим, и затем вернёмся к `instanceof` в главе [](/instanceof).
+
+
+## Утиная типизация
+
+Альтернативный подход к типу -- "утиная типизация", которая основана на одной известной пословице: *"If it looks like a duck, swims like a duck and quacks like a duck, then it probably is a duck (who cares what it really is)"*.
+
+В переводе: *"Если это выглядит как утка, плавает как утка и крякает как утка, то, вероятно, это утка (какая разница, что это на самом деле)"*.
+
+Смысл утиной типизации -- в проверке необходимых методов и свойств.
+
+Например, мы можем проверить, что объект -- массив, не вызывая `Array.isArray`, а просто уточнив наличие важного для нас метода, например `splice`:
+
+```js
+//+ run
+var something = [1, 2, 3];
+
+if (something.splice) {
+ alert( 'Это утка! То есть, массив!' );
+}
+```
+
+Обратите внимание -- в `if` мы не вызываем метод `something.splice()`, а пробуем получить само свойство `something.splice`. Для массивов оно всегда есть и является функцией, т.е. даст в логическом контексте `true`.
+
+Проверить на дату можно, определив наличие метода `getTime`:
+
+```js
+//+ run
+var x = new Date();
+
+if (x.getTime) {
+ alert( 'Дата!' );
+ alert( x.getTime() ); // работаем с датой
+}
+```
+
+С виду такая проверка хрупка, ее можно "сломать", передав похожий объект с тем же методом.
+
+Но как раз в этом и есть смысл утиной типизации: если объект похож на дату, у него есть методы даты, то будем работать с ним как с датой (какая разница, что это на самом деле).
+
+То есть, мы намеренно позволяем передать в код нечто менее конкретное, чем определённый тип, чтобы сделать его более универсальным.
+
+[smart header="Проверка интерфейса"]
+Если говорить словами "классического программирования", то "duck typing" -- это проверка реализации объектом требуемого интерфейса. Если реализует -- ок, используем его. Если нет -- значит это что-то другое.
+[/smart]
+
+
+## Пример полиморфной функции
+
+Пример полиморфной функции -- `sayHi(who)`, которая будет говорить "Привет" своему аргументу, причём если передан массив -- то "Привет" каждому:
+
+```js
+//+ run
+function sayHi(who) {
+
+ if (Array.isArray(who)) {
+ who.forEach(sayHi);
+ } else {
+ alert( 'Привет, ' + who );
+ }
+}
+
+// Вызов с примитивным аргументом
+sayHi("Вася"); // Привет, Вася
+
+// Вызов с массивом
+sayHi(["Саша", "Петя"]); // Привет, Саша... Петя
+
+// Вызов с вложенными массивами - тоже работает!
+sayHi(["Саша", "Петя", ["Маша", "Юля"]]); // Привет Саша..Петя..Маша..Юля
+```
+
+Проверку на массив в этом примере можно заменить на "утиную" -- нам ведь нужен только метод `forEach`:
+
+```js
+//+ run
+function sayHi(who) {
+
+ if (who.forEach) { // если есть forEach
+ who.forEach(sayHi); // предполагаем, что он ведёт себя "как надо"
+ } else {
+ alert( 'Привет, ' + who );
+ }
+}
+```
+
+## Итого
+
+Для написания полиморфных (это удобно!) функций нам нужна проверка типов.
+
+
+
Для примитивов с ней отлично справляется оператор `typeof`.
+
+У него две особенности:
+
+
Он считает `null` объектом, это внутренняя ошибка в языке.
+
Для функций он возвращает `function`, по стандарту функция не считается базовым типом, но на практике это удобно и полезно.
+
+
+
Для встроенных объектов мы можем получить тип из скрытого свойства `[[Class]]`, при помощи вызова `{}.toString.call(obj).slice(8, -1)`. Не работает для конструкторов, которые объявлены нами.
+
+
Оператор `obj instanceof Func` проверяет, создан ли объект `obj` функцией `Func`, работает для любых конструкторов. Более подробно мы разберём его в главе [](/instanceof).
+
И, наконец, зачастую достаточно проверить не сам тип, а просто наличие нужных свойств или методов. Это называется "утиная типизация".
+
+
diff --git a/10-regular-expressions-javascript/10-regexp-backreferences/article.md b/10-regular-expressions-javascript/10-regexp-backreferences/article.md
index bb8e3a82..2fd40485 100644
--- a/10-regular-expressions-javascript/10-regexp-backreferences/article.md
+++ b/10-regular-expressions-javascript/10-regexp-backreferences/article.md
@@ -1,9 +1,13 @@
-# Обратные ссылки \\n и $n
+# Обратные ссылки: \n и $n
+
+Скобочные группы можно не только получать в результате.
На скобочные группы можно ссылаться как в самом паттерне, так и в строке замены.
[cut]
-Ссылки в строке замены мы уже видели: они имеют вид `$n`, где `n` -- это номер скобочной группы. Вместо `$n` подставляется содержимое соответствующей скобки:
+## Группа в замене
+
+Ссылки в строке замены имеют вид `$n`, где `n` -- это номер скобочной группы. Вместо `$n` подставляется содержимое соответствующей скобки:
```js
//+ run
@@ -13,19 +17,26 @@ name = name.replace(/([а-яё]+) ([а-яё]+)/i, "$2, $1");
alert( name ); // Пушкин, Александр
```
-К скобочной группе можно также обратиться в самом шаблоне.
+## Группа в шаблоне
-Рассмотрим это в реальном примере -- необходимо найти строку в кавычках. Эта строка может быть в одинарных кавычках '...' или в двойных "..." -- не важно, в каких именно, но открывающая и закрывающая кавычки должны быть одинаковыми.
+Выше был пример использования содержимого групп в строке замены. Это удобно, когда нужно реорганизовать содержимое или создать новое с использованием старого.
-Как такие строки искать? Регэксп `['"](.*?)['"]` позволяет использовать разные кавычки, но он даст неверный ответ в случае, если одна кавычка ненароком оказалась внутри другой, как например в строке "She's the one":
+Но к скобочной группе можно также обратиться в самом поисковом шаблоне, ссылкой вида `\номер`.
+
+Чтобы было яснее, рассмотрим это на реальной задаче -- необходимо найти в тексте строку в кавычках. Причём кавычки могут быть одинарными '...' или двойными "..." -- и то и другое должно искаться корректно.
+
+Как такие строки искать?
+
+Можно в регэкспе предусмотреть произвольные кавычки: `['"](.*?)['"]`. Такой регэксп найдёт строки вида "...", '...', но он даст неверный ответ в случае, если одна кавычка ненароком оказалась внутри другой, как например в строке "She's the one":
```js
//+ run
-str = "He said:\"She's the one\"."
+str = "He said:\"She's the one\".";
-reg = /['"](.*?)['"]/g
+reg = /['"](.*?)['"]/g;
-alert(str.match(reg)) // "She'
+// Результат не соответствует замыслу
+alert( str.match(reg) ); // "She'
```
Как видно, регэксп нашёл открывающую кавычку ", затем текст, вплоть до новой кавычки ', которая закрывает соответствие.
@@ -34,11 +45,11 @@ alert(str.match(reg)) // "She'
```js
//+ run
-str = "He said:\"She's the one\"."
+str = "He said:\"She's the one\".";
-reg = /(['"])(.*?)\1/g
+reg = /(['"])(.*?)\1/g;
-alert(str.match(reg)) // "She's the one"
+alert( str.match(reg) ); // "She's the one"
```
Теперь работает верно!
@@ -46,7 +57,7 @@ alert(str.match(reg)) // "She's the one"
Обратим внимание на два нюанса:
-
В строке замены ссылка на первую скобочную группу выглядит как `$1`, а в шаблоне нужно использовать `\1`.
-
Чтобы обращаться к скобочной группе -- не важно откуда, она не должна быть исключена из запоминаемых при помощи `?:`, то есть `(?:['"])` не подошло бы.
+
Чтобы использовать скобочную группу в строке замены -- нужно использовать ссылку вида `$1`, а в шаблоне -- обратный слэш: `\1`.
+
Чтобы в принципе иметь возможность обратиться к скобочной группе -- не важно откуда, она не должна быть исключена из запоминаемых при помощи `?:`. Скобочные группы вида `(?:...)` не участвуют в нумерации.
diff --git a/10-regular-expressions-javascript/11-regexp-infinite-backtracking-problem/article.md b/10-regular-expressions-javascript/11-regexp-infinite-backtracking-problem/article.md
index a036a6c6..455ad673 100644
--- a/10-regular-expressions-javascript/11-regexp-infinite-backtracking-problem/article.md
+++ b/10-regular-expressions-javascript/11-regexp-infinite-backtracking-problem/article.md
@@ -1,4 +1,4 @@
-# Чёрная дыра бэктрекинга
+# Чёрная дыра бэктрекинга [todo]
Некоторые регулярные выражения, с виду являясь простыми, могут выполняться оооочень долго, и даже подвешивать браузер.
diff --git a/10-regular-expressions-javascript/9-regexp-groups/article.md b/10-regular-expressions-javascript/9-regexp-groups/article.md
index 192401ae..77ecde32 100644
--- a/10-regular-expressions-javascript/9-regexp-groups/article.md
+++ b/10-regular-expressions-javascript/9-regexp-groups/article.md
@@ -1,4 +1,4 @@
-# Группы [todo]
+# Скобочные группы
Часть шаблона может быть заключена в скобки (...). Такие выделенные части шаблона называют "скобочными выражениями" или "скобочными группами".
@@ -9,6 +9,9 @@
[cut]
+
+## Пример
+
В примере ниже, шаблон (go)+ находит один или более повторяющихся 'go':
```js
@@ -16,30 +19,57 @@
alert( 'Gogogo now!'.match(/(go)+/i ); // "Gogogo"
```
-Без скобок, шаблон /go+/ означал бы g, после которого идёт одна или более o, например: goooo.
+Без скобок, шаблон /go+/ означал бы g, после которого идёт одна или более o, например: goooo. А скобки "группируют" (go) вместе.
-**Скобки нумеруются слева направо. Поисковой движок запоминает содержимое каждой скобки и позволяет обращаться к нему, в том числе -- в шаблоне и строке замены.**
+## Содержимое группы
-Например, найти HTML-тег можно шаблоном <.*?>. Скорее всего, после поиска мы захотим что-то сделать с результатом, и нас будет интересовать содержимое `<...>`.
+Скобки нумеруются слева направо. Поисковой движок запоминает содержимое каждой скобки и позволяет обращаться к нему -- в шаблоне и строке замены и, конечно же, в результатах.
-Для удобства заключим его в скобки: <(.*?)>. Тогда содержимое скобок можно будет получить отдельно.
+Например, найти HTML-тег можно шаблоном <.*?>.
-Используем метод [String#match](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/match). В результирующем массиве будет сначала всё совпадение, а далее -- скобочные группы, в данном случае -- только одна:
+После поиска мы захотим что-то сделать с результатом. Для удобства заключим содержимое `<...>` в скобки: <(.*?)>. Тогда оно будет доступно отдельно.
+
+При поиске методом [String#match](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/match) в результирующем массиве будет сначала всё совпадение, а далее -- скобочные группы. В шаблоне <(.*?)> скобочная группа только одна:
```js
//+ run
-var str = '
, h1
```
-Для поиска всех совпадений, как мы обсуждали ранее, используется метод [RegExp#exec](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec).
+Заметим, что метод [String#match](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/match) выдаёт скобочные группы только при поиске без флага `/.../g`. В примере выше он нашёл только первое совпадение <h1>, а закрывающий </h1> не нашёл, поскольку без флага `/.../g` ищется только первое совпадение.
-**Скобки могут быть и вложенными. В этом случае нумерация также идёт слева направо.**
+Для того, чтобы искать и с флагом `/.../g` и со скобочными группами, используется метод [RegExp#exec](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec):
-Например, в строке <span class="my"> нас может интересовать отдельно тег `span` и, для примера, его первая буква.
+```js
+//+ run
+var str = '
,/h1
+ alert(match);
+}
+```
+
+Теперь найдено оба совпадения <(.*?)>, каждое -- массив из полного совпадения и скобочных групп (одна в данном случае).
+
+## Вложенные группы
+Скобки могут быть и вложенными. В этом случае нумерация также идёт слева направо.
+
+Например, при поиске тега в <span class="my"> нас может интересовать:
+
+
+
Содержимое тега целиком: `span class="my"`.
+
В отдельную переменную для удобства хотелось бы поместить тег: `span`.
+
Также может быть удобно отдельно выделить атрибуты `class="my"`.
, h1
//+ run
var str = '';
-reg = /<(([a-z])[a-z0-9]*).*?>/;
+reg = /<(([a-z]+)\s*([^>]*))>/;
alert( str.match(reg) ); // , span, s
```
Вот так выглядят скобочные группы:
-
-На нулевом месте -- всегда совпадение полностью, далее -- группы. Их вложенность означает всего лишь, что группа 1 содержит группу 2. Нумерация всегда идёт слева направо, по открывающей скобке.
+
+
+На нулевом месте -- всегда совпадение полностью, далее -- группы. Нумерация всегда идёт слева направо, по открывающей скобке.
+
+В данном случае получилось, что группа 1 включает в себя содержимое групп 2 и 3. Это совершенно нормальная ситуация, которая возникает, когда нужно выделить что-то отдельное внутри большей группы.
**Даже если скобочная группа необязательна и не входит в совпадение, соответствующий элемент массива существует (и равен `undefined`).**
@@ -87,40 +120,32 @@ alert( match[1] ); // undefined, для (z)? ничего нет
alert( match[2] ); // c
```
-Длина массива результатов по-прежнему `3`. Она постоянна. А вот для скобочной группы (z)? в ней ничего нет.
+Длина массива результатов по-прежнему `3`. Она постоянна. А вот для скобочной группы (z)? в ней ничего нет, поэтому результат: `["ac", undefined, "c"]`.
-**Скобочную группу можно исключить из запоминаемых и нумеруемых, добавив в её начало ?:**
+## Исключение из запоминания через ?:
-Бывает так, что скобки нужны, чтобы квантификатор правильно применился, а вот запоминать её в массиве не нужно. Тогда мы просто ставим сразу после открывающей скобки `?:`
+Бывает так, что скобки нужны, чтобы квантификатор правильно применился, а вот запоминать её в массиве не нужно.
-В примере ниже есть скобочная группа (go-?), которая сама по себе не интересна, но входит в результаты:
+Скобочную группу можно исключить из запоминаемых и нумеруемых, добавив в её начало ?:.
+
+
+Например, мы хотим найти (go)+, но содержимое скобок (`go`) в отдельный элемент массива выделять не хотим.
+
+Для этого нужно сразу после открывающей скобки поставить `?:`, то есть: (?:go)+.
+
+Например:
```js
//+ run
-var str = "Go-go John!";
+var str = "Gogo John!";
*!*
-var reg = /(go-?)* (\w+)/i;
+var reg = /(?:go)+ (\w+)/i;
*/!*
var result = str.match(reg);
-alert( result[0] ); // Go-go John
-alert( result[1] ); // go
-alert( result[2] ); // John
-```
-
-Исключим её из запоминаемых:
-
-```js
-//+ run
-var str = "Go-go John!";
-*!*
-var reg = /(?:go-?)* (\w+)/i;
-*/!*
-
-var result = str.match(reg);
-
-alert( result[0] ); // Go-go John
+alert( result.length ); // 2
alert( result[1] ); // John
```
+В примере выше массив результатов имеет длину `2` и содержит только полное совпадение и результат (\w+). Это удобно в тех случаях, когда содержимое скобок нас не интересует.
diff --git a/10-regular-expressions-javascript/9-regexp-groups/groups.png b/10-regular-expressions-javascript/9-regexp-groups/groups.png
deleted file mode 100644
index f0cd8c8e..00000000
Binary files a/10-regular-expressions-javascript/9-regexp-groups/groups.png and /dev/null differ
diff --git a/10-regular-expressions-javascript/9-regexp-groups/regexp-nested-groups.svg b/10-regular-expressions-javascript/9-regexp-groups/regexp-nested-groups.svg
new file mode 100644
index 00000000..37961bf4
--- /dev/null
+++ b/10-regular-expressions-javascript/9-regexp-groups/regexp-nested-groups.svg
@@ -0,0 +1,49 @@
+
+
\ No newline at end of file
diff --git a/archive/1-class-property/article.md b/archive/1-class-property/article.md
new file mode 100644
index 00000000..34572c52
--- /dev/null
+++ b/archive/1-class-property/article.md
@@ -0,0 +1,104 @@
+# Секретное свойство [[Class]]
+
+Для встроенных объектов есть одна "секретная" возможность узнать их тип, которая связана с методом `toString`.
+
+Во всех встроенных объектах есть специальное свойство `[[Class]]`, в котором хранится информация о его типе или конструкторе.
+
+Оно взято в квадратные скобки, так как это свойство -- внутреннее. Явно получить его нельзя, но можно прочитать его "в обход", воспользовавшись методом `toString` из `Object`.
+
+[cut]
+
+## Получение [[Class]]
+
+Вернёмся к примеру, который видели раньше:
+
+```js
+//+ run
+var obj = {};
+alert( obj ); // [object Object]
+```
+
+**В выводе стандартного `toString` для объектов внутри `[object ...]` указано как раз значение `[[Class]]`.**
+
+Для обычного объекта это как раз и есть `"Object"`, но если бы такой `toString` запустить для даты, то будет `[object Date]`, для массивов -- `[object Array]` и т.п.
+
+К сожалению или к счастью, но большинство встроенных объектов в JavaScript имеют свой собственный метод `toString`: для массивов он выводит элементы через запятую, для дат -- строчное представление и так далее.
+
+То есть, просто вызов `[1,2,3].toString()` вернёт нам `1,2,3` и никакой информации про `[[Class]]`.
+
+Поэтому для получения `[[Class]]` мы одолжим функцию `toString` у стандартного объекта и запустим её в контексте тех значений, для которых нужно получить тип. В этом нам поможет метод `call`:
+
+```js
+//+ run
+var toClass = {}.toString; // (1)
+
+var arr = [1, 2];
+alert( toClass.call(arr) ); // (2) [object Array]
+
+var date = new Date;
+alert( toClass.call(date) ); // [object Date]
+
+var type = toClass.call(date).slice(8, -1); // (3)
+alert( type ); // Date
+```
+
+Разберем происходящее более подробно.
+
+
+
Можно переписать эту строку в две:
+
+```js
+var obj = {};
+var toClass = obj.toString;
+```
+
+Иначе говоря, мы создаём пустой объект `{}` и копируем ссылку на его метод `toString` в переменную `toClass`.
+
+**Для получения `[[Class]]` нужна именно внутренняя реализация `toString` стандартного объекта `Object`, другая не подойдёт.**
+
Вызываем скопированный метод в контексте нужного объекта `obj`.
+
+Мы могли бы поступить проще -- одолжить метод под другим названием:
+
+```js
+//+ run
+var arr = [1, 2];
+arr.toClass = {}.toString;
+
+alert( arr.toClass() ); // [object Array]
+```
+
+...Но зачем копировать лишнее свойство в объект? Синтаксис `toClass.call(arr)` делает то же самое, поэтому используем его.
+
+
Всё, класс получен. При желании можно убрать обёртку `[object ...]`, взяв подстроку вызовом `slice(8,-1)`.
+
+
+Метод также можно использовать с примитивами:
+
+```js
+//+ run
+alert( {}.toString.call(123) ); // [object Number]
+alert( {}.toString.call("строка") ); // [object String]
+```
+
+[warn header="Вызов `{}.toString` в консоли может выдать ошибку"]
+При тестировании кода в консоли вы можете обнаружить, что если ввести в командную строку `{}.toString.call(...)` -- будет ошибка. С другой стороны, вызов `alert( {}.toString... )` -- работает.
+
+Эта ошибка возникает потому, что фигурные скобки `{ }` в основном потоке кода интерпретируются как блок. Интерпретатор читает `{}.toString.call(...)` так:
+
+```js
+//+ no-beautify
+{ } // пустой блок кода
+.toString.call(...) // а что это за точка в начале? не понимаю, ошибка!
+```
+
+Фигурные скобки считаются объектом, только если они находятся в контексте выражения. В частности, оборачивание в скобки `( {}.toString... )` тоже сработает нормально.
+[/warn]
+
+## Итого
+
+
+
Свойство `[[Class]]` позволяет получить тип для встроенных объектов. Далее мы будем рассматривать создание своих объектов через функцию-конструктор, с ними `[[Class]]` не работает.
+
Для доступа к `[[Class]]` используется `{}.toString.call(obj).slice(8, -1)`.
+
+
+Обычно в JavaScript используется "утиная" типизация. Свойство `[[Class]]` -- самое надёжное средство проверки типа встроенных объектов, но обычно утиной типизации вполне хватает.
\ No newline at end of file
diff --git a/figures.sketch b/figures.sketch
index 264784b2..efa5014c 100644
Binary files a/figures.sketch and b/figures.sketch differ