diff --git a/2-ui/1-document/5-searching-elements-dom/2-tree-info/solution.md b/2-ui/1-document/5-searching-elements-dom/2-tree-info/solution.md
new file mode 100644
index 00000000..55b45737
--- /dev/null
+++ b/2-ui/1-document/5-searching-elements-dom/2-tree-info/solution.md
@@ -0,0 +1,18 @@
+Сделаем цикл по узлам `
`:
+
+```js
+var lis = document.getElementsByTagName('li');
+
+for (i = 0; i < lis.length; i++) {
+ ...
+}
+```
+
+В цикле для каждого `lis[i]` можно получить текст, используя свойство `firstChild`. Ведь первым в `
` является как раз текстовый узел, содержащий текст названия.
+
+Также можно получить количество потомков, используя `lis[i].getElementsByTagName('li')`.
+
+Напишите код с этой подсказкой.
+
+Если уж не выйдет -- тогда откройте решение.
+
diff --git a/2-ui/1-document/5-searching-elements-dom/2-tree-info/solution.view/index.html b/2-ui/1-document/5-searching-elements-dom/2-tree-info/solution.view/index.html
new file mode 100644
index 00000000..e9b5d644
--- /dev/null
+++ b/2-ui/1-document/5-searching-elements-dom/2-tree-info/solution.view/index.html
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
Животные
+
+
Млекопитающие
+
+
Коровы
+
Ослы
+
Собаки
+
Тигры
+
+
+
Другие
+
+
Змеи
+
Птицы
+
Ящерицы
+
+
+
+
+
Рыбы
+
+
Аквариумные
+
+
Гуппи
+
Скалярии
+
+
+
+
Морские
+
+
Морская форель
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/2-ui/1-document/5-searching-elements-dom/2-tree-info/source.view/index.html b/2-ui/1-document/5-searching-elements-dom/2-tree-info/source.view/index.html
new file mode 100644
index 00000000..2f45460c
--- /dev/null
+++ b/2-ui/1-document/5-searching-elements-dom/2-tree-info/source.view/index.html
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
Животные
+
+
Млекопитающие
+
+
Коровы
+
Ослы
+
Собаки
+
Тигры
+
+
+
Другие
+
+
Змеи
+
Птицы
+
Ящерицы
+
+
+
+
+
Рыбы
+
+
Аквариумные
+
+
Гуппи
+
Скалярии
+
+
+
+
Морские
+
+
Морская форель
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/2-ui/1-document/5-searching-elements-dom/2-tree-info/task.md b/2-ui/1-document/5-searching-elements-dom/2-tree-info/task.md
new file mode 100644
index 00000000..5ffd808d
--- /dev/null
+++ b/2-ui/1-document/5-searching-elements-dom/2-tree-info/task.md
@@ -0,0 +1,14 @@
+# Дерево
+
+[importance 5]
+
+Есть дерево из тегов `
/
`.
+
+Напишите код, который для каждого элемента `
` выведет:
+
+
Текст непосредственно в нём (без подразделов).
+
Количество вложенных в него элементов `
` -- всех, с учётом вложенных.
+
+
+[demo src="solution"]
+
diff --git a/6-optimize/1-optimize-intro/article.md b/6-optimize/1-optimize-intro/article.md
new file mode 100644
index 00000000..a0e9c5c3
--- /dev/null
+++ b/6-optimize/1-optimize-intro/article.md
@@ -0,0 +1,5 @@
+# Введение
+
+В отличие от ряда других курсов учебника, этот раздел -- не является курсом как таковым. Связное и грамотное изложение темы требует времени, которое я пока не могу ему уделить. Но, надеюсь, смогу в будущем.
+
+Пока что раздел содержит лишь некоторые статьи-заметки по теме оптимизации, которые, надеюсь, будут вам полезны.
diff --git a/6-optimize/2-minification/article.md b/6-optimize/2-minification/article.md
new file mode 100644
index 00000000..22cb1700
--- /dev/null
+++ b/6-optimize/2-minification/article.md
@@ -0,0 +1,513 @@
+# Как работают сжиматели JavaScript
+
+Перед выкладыванием JavaScript на "боевую" машину -- пропускаем его через минификатор (также говорят "сжиматель"), который удаляет пробелы и по-всякому оптимизирует код, уменьшая его размер.
+
+В этой статье мы посмотрим, как работают современные минификаторы, за счёт чего они укорачивают код и какие с ними возможны проблемы.
+[cut]
+
+## Современные сжиматели
+
+Рассматриваемые в этой статье алгоритмы и подходы относятся к минификаторам последнего поколения.
+
+Вот их список:
+
+
+Самые широко используемые -- первые два, поэтому будем рассматривать в первую очередь их.
+
+Наша цель -- понять, как они работают, и что интересного с их помощью можно сотворить.
+
+## С чего начать?
+
+Для GCC:
+
+
+
Убедиться, что стоит [Java](http://java.oracle.com)
+
Скачать и распаковать [](http://closure-compiler.googlecode.com/files/compiler-latest.zip), нам нужен файл `compiler.jar`.
+
+
+Обратите внимание на флаг `--charset` для GCC. Без него русские буквы будут закодированы во что-то типа `\u1234`.
+
+Google Closure Compiler также содержит [песочницу](http://closure-compiler.appspot.com/home) для тестирования сжатия и [веб-сервис](https://developers.google.com/closure/compiler/docs/gettingstarted_api?hl=ru), на который код можно отправлять для сжатия. Но скачать файл обычно гораздо проще, поэтому его редко где используют.
+
+Для UglifyJS:
+
+
+
Убедиться, что стоит [Node.js](http://nodejs.org)
+
Поставить `npm install -g uglify-js`.
+
Сжать файл `my.js`: `uglifyjs my.js -o my.min.js`
+
+
+## Что делает минификатор?
+
+Все современные минификаторы работают следующим образом:
+
+
Разбирают JavaScript-код в синтаксическое дерево.
+
+Также поступает любой интерпретатор JavaScript перед тем, как его выполнять. Но затем, вместо исполнения кода...
+
Бегают по этому дереву, анализируют и оптимизируют его.
+
Записывают из синтаксического дерева получившийся код.
+
+
+## Как выглядит дерево?
+
+Посмотреть синтаксическое дерево можно, запустив компилятор со специальным флагом.
+
+Для GCC есть даже способ вывести его:
+
+
+
Сначала сгенерируем дерево в формате [DOT](http://en.wikipedia.org/wiki/DOT_language):
+
+```
+java -jar compiler.jar --js my.js --use_only_custom_externs --print_tree >my.dot
+```
+
+Здесь флаг `--print_tree` выводит дерево, а `--use_only_custom_externs` убирает лишнюю служебную информацию.
+
+
Файл в этом формате используется в различных программах для графопостроения.
+
+Чтобы превратить его в обычную картинку, подойдёт утилита `dot` из пакета [Graphviz](http://www.graphviz.org/):
+
+```
+// конвертировать в формат png
+dot -Tpng my.dot -o my.png
+
+// конвертировать в формат svg
+dot -Tsvg my.dot -o my.svg
+```
+
+
+
+
+Пример кода `my.js`:
+
+```js
+function User(name) {
+
+ this.sayHi = function() {
+ alert( name );
+ };
+
+}
+```
+
+Результат, получившееся из `my.js` дерево:
+
+
+
+В узлах-эллипсах на иллюстрации выше стоит тип, например `FUNCTION` (функция) или `NAME` (имя переменной). Комментарии к ним на русском языке добавлены мной вручную.
+
+Кроме него к каждому узлу привязаны конкретные данные. Сжиматель умеет ходить по этому дереву и менять его, как пожелает.
+
+[smart header="Комментарии JSDoc"]
+Обычно когда код превращается в дерево -- из него естественным образом исчезают комментарии и пробелы. Они не имеют значения при выполнении, поэтому игнорируются.
+
+Но Google Closure Compiler добавляет в дерево информацию из *комментариев JSDoc*, т.е. комментариев вида `/** ... */`, например:
+
+```js
+*!*
+/**
+ * Номер минимальной поддерживаемой версии IE
+ * @const
+ * @type {number}
+ */
+*/!*
+var minIEVersion = 8;
+```
+
+Такие комментарии не создают новых узлов дерева, а добавляются в качестве информации к существующем. В данном случае -- к переменной `minIEVersion`.
+
+В них может содержаться информация о типе переменной (`number`) и другая, которая поможет сжимателю лучше оптимизировать код (`const` -- константа).
+
+[/smart]
+
+## Оптимизации
+
+Сжиматель бегает по дереву, ищет "паттерны" -- известные ему структуры, которые он знает, как оптимизировать, и обновляет дерево.
+
+В разных минификаторах реализован разный набор оптимизаций, сами оптимизации применяются в разном порядке, поэтому результаты работы могут отличаться. В примерах ниже даётся результат работы GCC.
+
+
+
Лишние переменные убраны. Для этого сжиматель создаёт вспомогательную внутреннюю структуру данных, в которой хранятся сведения о "пути использования" каждой переменной. Если одна переменная заканчивает свой путь и начинает другая, то вполне можно дать им одно имя.
+
Кроме того, операции `elem = getElementsById` и `elem.parentNode` объединены, но это уже другая оптимизация.
Если переменная присваивается, но не используется, она может быть удалена. В примере выше эта оптимизация была применена к переменной `parent`, а затем и к параметру `node`.
+
Заведомо ложная ветка `if(0) { .. }` убрана, заведомо истинная -- оставлена.
+
+То же самое будет с условиями в других конструкциях, например `a = true ? c : d` превратится в `a = c`.
+
Код после `return` удалён как недостижимый.
+
+
+
Переписывание синтаксических конструкций
+
+До оптимизации:
+
+```js
+var i = 0;
+while (i++ < 10) {
+ alert( i );
+}
+
+if (i) {
+ alert( i );
+}
+
+if (i == '1') {
+ alert( 1 );
+} else if (i == '2') {
+ alert( 2 );
+} else {
+ alert( i );
+}
+```
+
+После оптимизации:
+
+```js
+//+ no-beautify
+for(var i=0;10>i++;)alert(i);i&&alert(i);"1"==i?alert(1):"2"==i?alert(2):alert(i);
+```
+
+
+
Конструкция `while` переписана в `for`.
+
Конструкция `if (i) ...` переписана в `i&&...`.
+
Конструкция `if (cond) ... else ...` была переписана в `cond ? ... : ...`.
+
+
+
Инлайнинг функций
+
+*Инлайнинг функции* -- приём оптимизации, при котором функция заменяется на своё тело.
+
+До оптимизации:
+
+```js
+function sayHi(message) {
+
+ var elem = createMessage('div', message);
+ showElement(elem);
+
+ function createMessage(tagName, message) {
+ var el = document.createElement(tagName);
+ el.innerHTML = message;
+ return el;
+ }
+
+ function showElement(elem) {
+ document.body.appendChild(elem);
+ }
+}
+```
+
+После оптимизации (переводы строк также будут убраны):
+
+```js
+function sayHi(b) {
+ var a = document.createElement("div");
+ a.innerHTML = b;
+ document.body.appendChild(a)
+};
+```
+
+
+
Вызовы функций `createMessage` и `showElement` заменены на тело функций. В данном случае это возможно, так как функции используются всего по разу.
+
Эта оптимизация применяется не всегда. Если бы каждая функция использовалась много раз, то с точки зрения размера выгоднее оставить их "как есть".
+
+
+
Инлайнинг переменных
+
Переменные заменяются на значение, если оно заведомо известно.
+
+До оптимизации:
+
+```js
+(function() {
+ var isVisible = true;
+ var hi = "Привет вам из JavaScript";
+
+ window.sayHi = function() {
+ if (isVisible) {
+ alert( hi );
+ alert( hi );
+ alert( hi );
+ alert( hi );
+ alert( hi );
+ alert( hi );
+ alert( hi );
+ alert( hi );
+ alert( hi );
+ alert( hi );
+ alert( hi );
+ alert( hi );
+ }
+ }
+
+})();
+```
+
+После оптимизации:
+
+```js
+(function() {
+ window.sayHi = function() {
+ alert( "Привет вам из JavaScript" );
+ alert( "Привет вам из JavaScript" );
+ alert( "Привет вам из JavaScript" );
+ alert( "Привет вам из JavaScript" );
+ alert( "Привет вам из JavaScript" );
+ alert( "Привет вам из JavaScript" );
+ alert( "Привет вам из JavaScript" );
+ alert( "Привет вам из JavaScript" );
+ alert( "Привет вам из JavaScript" );
+ alert( "Привет вам из JavaScript" );
+ alert( "Привет вам из JavaScript" );
+ alert( "Привет вам из JavaScript" );
+ };
+ }
+})();
+```
+
+
+
Переменная `isVisible` заменена на `true`, после чего `if` стало возможным убрать.
+
Переменная `hi` заменена на строку.
+
+
+Казалось бы -- зачем менять `hi` на строку? Ведь код стал ощутимо длиннее!
+
+...Но всё дело в том, что минификатор знает, что дальше код будет сжиматься при помощи gzip. Во всяком случае, все правильно настроенные сервера так делают.
+
+[Алгоритм работы gzip](http://www.gzip.org/algorithm.txt) заключается в том, что он ищет повторы в данных и выносит их в специальный "словарь", заменяя на более короткий идентификатор. Архив как раз и состоит из словаря и данных, в которых дубликаты заменены на идентификаторы.
+
+Если вынести строку обратно в переменную, то получится как раз частный случай такого сжатия -- взяли `"Привет вам из JavaScript"` и заменили на идентификатор `hi`. Но gzip справляется с этим лучше, поэтому эффективнее будет оставить именно строку. Gzip сам найдёт дубликаты и сожмёт их.
+
+Плюс такого подхода станет очевиден, если сжать gzip оба кода -- до и после минификации. Минифицированный gzip-сжатый код в итоге даст меньший размер.
+
+
+
Разные мелкие оптимизации
+
Кроме основных оптимизаций, описанных выше, есть ещё много мелких:
+
+
Упрощаются простые вызовы `Array/Object`
+
+```js
+//+ no-beautify
+a = new Array() => a = []
+o = new Object() => o = {}
+```
+
+Эта оптимизация предполагает, что `Array` и `Object` не переопределены программистом. Для включения её в UglifyJS нужен флаг `--unsafe`.
+
+
...И еще некоторые другие мелкие изменения кода...
+
+
+
+
+
+
+## Подводные камни
+
+Описанные оптимизации, в целом, безопасны, но есть ряд подводных камней.
+
+### Конструкция with
+
+Рассмотрим код:
+
+```js
+//+ no-beautify
+function changePosition(style) {
+ var position, test;
+
+*!*
+ with (style) {
+ position = 'absolute';
+ }
+*/!*
+}
+```
+
+Куда будет присвоено значение `position = 'absolute'`?
+
+Это неизвестно до момента выполнения: если свойство `position` есть в `style` -- то туда, а если нет -- то в локальную переменную.
+
+Можно ли в такой ситуации заменить локальную переменную на более короткую? Очевидно, нет:
+
+```js
+//+ no-beautify
+function changePosition(style) {
+ var a, b;
+
+*!*
+ with (style) { // а что, если в style нет такого свойства?
+ position = 'absolute';// куда будет осуществлена запись? в window.position?
+ }
+*/!*
+}
+```
+
+Такая же опасность для сжатия кроется в использованном `eval`. Ведь `eval` может обращаться к локальным переменным:
+
+```js
+//+ no-beautify
+function f(code) {
+ var myVar;
+
+ eval(code); // а что, если будет присвоение eval("myVar = ...") ?
+
+ alert(myVar);
+```
+
+Получается, что при наличии `eval` мы не имеем права переименовывать локальные переменные. Причём (!), если функция является вложенноой, то и во внешних функциях тоже.
+
+А ведь сжатие переменных -- очень важная оптимизация. Как правило, она уменьшает размер сильнее всего.
+
+Что делать? Разные минификаторы поступают по-разному.
+
+
+
UglifyJS -- не будет переименовывать переменные. Так что наличие `with/eval` сильно повлияет на степень сжатие кода.
+
GCC -- всё равно сожмёт локальные переменные. Это, конечно же, может привести к ошибкам, причём в сжатом коде, отлаживать который не очень-то удобно. Поэтому он выдаст предупреждение о наличии опасной конструкции.
+
+
+Ни тот ни другой вариант нас, по большому счёту, не устраивают.
+
+**Для того, чтобы код сжимался хорошо и работал правильно, не используем `with` и `eval`.**
+
+Либо, если уж очень надо использовать -- делаем это с оглядкой на поведение минификатора, чтобы не было проблем.
+
+### Условная компиляция IE10-
+
+В IE10- поддерживалось [условное выполнение JavaScript](http://msdn.microsoft.com/en-us/library/121hztk3.aspx).
+
+Синтаксис: `/*@cc_on код */`.
+
+Такой код выполнится в IE10-, например:
+
+```js
+//+ run
+var isIE /*@cc_on =true@*/ ;
+
+alert( isIE ); // true в IE10-
+```
+
+Можно хитро сделать, чтобы комментарий остался, например так:
+
+```js
+//+ run
+var isIE = new Function('', '/*@cc_on return true@*/')();
+
+alert( isIE ); // true в IE.
+```
+
+
+...Однако, с учётом того, что в современных IE11+ эта компиляция не работает в любом случае, лучше избавиться от неё вообще.
+
+В следующих главах мы посмотрим, какие продвинутые возможности есть в минификаторах, как сделать сжатие более эффективным.
+
diff --git a/6-optimize/2-minification/my.svg b/6-optimize/2-minification/my.svg
new file mode 100644
index 00000000..a04ec2c4
--- /dev/null
+++ b/6-optimize/2-minification/my.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/6-optimize/3-better-minification/article.md b/6-optimize/3-better-minification/article.md
new file mode 100644
index 00000000..5220f678
--- /dev/null
+++ b/6-optimize/3-better-minification/article.md
@@ -0,0 +1,172 @@
+# Улучшаем сжатие кода
+
+Здесь мы обсудим разные приёмы, которые используются, чтобы улучшить сжатие кода.
+[cut]
+## Больше локальных переменных
+
+Например, код jQuery обёрнут в функцию, запускаемую "на месте".
+
+```js
+(function(window, undefined) {
+ // ...
+ var jQuery = ...
+
+ window.jQuery = jQuery; // сделать переменную глобальной
+
+})(window);
+```
+
+Переменные `window` и `undefined` стали локальными. Это позволит сжимателю заменить их на более короткие.
+
+## ООП без прототипов
+
+Приватные переменные будут сжаты и заинлайнены.
+
+Например, этот код хорошо сожмётся:
+
+```js
+function User(firstName, lastName) {
+ var fullName = firstName + ' ' + lastName;
+
+ this.sayHi = function() {
+ showMessage(fullName);
+ }
+
+ function showMessage(msg) {
+ alert( '**' + msg + '**' );
+ }
+}
+```
+
+..А этот -- плохо:
+
+```js
+function User(firstName, lastName) {
+ this._firstName = firstName;
+ this._lastName = lastName;
+}
+
+User.prototype.sayHi = function() {
+ this._showMessage(this._fullName);
+}
+
+
+User.prototype._showMessage = function(msg) {
+ alert( '**' + msg + '**' );
+}
+```
+
+Сжимаются только локальные переменные, свойства объектов не сжимаются, поэтому эффект от сжатия для второго кода будет совсем небольшим.
+
+При этом, конечно, нужно иметь в виду общий стиль ООП проекта, достоинства и недостатки такого подхода.
+
+## Сжатие под платформу, define
+
+Можно делать разные сборки в зависимости от платформы (мобильная/десктоп) и браузера.
+
+Ведь не секрет, что ряд функций могут быть реализованы по разному, в зависимости от того, поддерживает ли среда выполнения нужную возможность.
+
+### Способ 1: локальная переменная
+
+Проще всего это сделать локальной переменной в модуле:
+
+```js
+(function($) {
+
+*!*
+ /** @const */
+ var platform = 'IE';
+*/!*
+
+ // .....
+
+ if (platform == 'IE') {
+ alert( 'IE' );
+ } else {
+ alert( 'NON-IE' );
+ }
+
+})(jQuery);
+```
+
+Нужное значение директивы можно вставить при подготовке JavaScript к сжатию.
+
+Сжиматель заинлайнит её и оптимизирует соответствующие IE.
+
+### Способ 2: define
+
+UglifyJS и GCC позволяют задать значение глобальной переменной из командной строки.
+
+В GCC эта возможность доступна лишь в "продвинутом режиме" работы оптимизатора, который мы рассмотрим далее (он редко используется).
+
+Удобнее в этом плане устроен UglifyJS. В нём можно указать флаг `-d SYMBOL[=VALUE]`, который заменит все переменные `SYMBOL` на указанное значение `VALUE`. Если `VALUE` не указано, то оно считается равным `true`.
+
+Флаг не работает, если переменная определена явно.
+
+Например, рассмотрим код:
+
+```js
+// my.js
+if (isIE) {
+ alert( "Привет от IE" );
+} else {
+ alert( "Не IE :)" );
+}
+```
+
+Сжатие вызовом `uglifyjs -d isIE my.js` даст:
+
+```js
+alert( "Привет от IE" );
+```
+
+..Ну а чтобы код работал в обычном окружении, нужно определить в нём значение переменной по умолчанию. Это обычно делается в каком-то другом файле (на весь проект), так как если объявить `var isIE` в этом, то флаг `-d isIE` не сработает.
+
+Но можно и "хакнуть" сжиматель, объявив переменную так:
+
+```js
+// объявит переменную при отсутствии сжатия
+// при сжатии не повредит
+window.isIE = window.isIE || getBrowserVersion();
+```
+
+## Убираем вызовы console.*
+
+Минификатор имеет в своём распоряжении дерево кода и может удалить ненужные вызовы.
+
+Для UglifyJS это делают опции компилятора:
+
+
`drop_debugger` -- убирает вызовы `debugger`.
+
`drop_console` -- убирает вызовы `console.*`.
+
+
+Можно написать и дополнительную функцию преобразования, которая убирает другие вызовы, например для `log.*`:
+
+```js
+var uglify = require('uglify-js');
+var pro = uglify.uglify;
+
+function ast_squeeze_console(ast) {
+ var w = pro.ast_walker(),
+ walk = w.walk,
+ scope;
+ return w.with_walkers({
+ "stat": function(stmt) {
+ if (stmt[0] === "call" && stmt[1][0] == "dot" && stmt[1][1] instanceof Array && stmt[1][1][0] == 'name' && stmt[1][1][1] == "log") {
+ return ["block"];
+ }
+ return ["stat", walk(stmt)];
+ },
+ "call": function(expr, args) {
+ if (expr[0] == "dot" && expr[1] instanceof Array && expr[1][0] == 'name' && expr[1][1] == "console") {
+ return ["atom", "0"];
+ }
+ }
+ }, function() {
+ return walk(ast);
+ });
+};
+```
+
+Эту функцию следует вызвать на результате `parse`, и она пройдётся по дереву и удалит все вызовы `log.*`.
+
diff --git a/6-optimize/4-memory-leaks/article.md b/6-optimize/4-memory-leaks/article.md
new file mode 100644
index 00000000..08ed1610
--- /dev/null
+++ b/6-optimize/4-memory-leaks/article.md
@@ -0,0 +1,317 @@
+# Утечки памяти
+
+*Утечки памяти* происходят, когда браузер по какой-то причине не может освободить память от недостижимых объектов.
+
+Обычно это происходит автоматически ([](/memory-management)). Кроме того, браузер освобождает память при переходе на другую страницу. Поэтому утечки в реальной жизни проявляют себя в двух ситуациях:
+
+[cut]
+
+
Приложение, в котором посетитель все время на одной странице и работает со сложным JavaScript-интерфейсом. В этом случае утечки могут постепенно съедать доступную память.
+
Страница регулярно делает что-то, вызывающее утечку памяти. Посетитель (например, менеджер) оставляет компьютер на ночь включенным, чтобы не закрывать браузер с кучей вкладок. Приходит утром -- а браузер съел всю память и рухнул и сильно тормозит.
+
+Утечки бывают из-за ошибок браузера, ошибок в расширениях браузера и, гораздо реже, по причине ошибок в архитектуре JavaScript-кода. Мы разберём несколько наиболее частых и важных примеров.
+
+## Коллекция утечек в IE
+
+### Утечка DOM ↔ JS в IE8-
+
+IE до версии 8 не умел очищать циклические ссылки, появляющиеся между DOM-объектами и объектами JavaScript. В результате и DOM и JS оставались в памяти навсегда.
+
+В браузере IE8 была проведена серьёзная работа над ошибками, но утечка в IE8- появляется, если круговая ссылка возникает "через объект".
+
+Чтобы было понятнее, о чём речь, посмотрите на следующий код. Он вызывает утечку памяти в IE8-:
+
+```
+function leak() {
+ // Создаём новый DIV, добавляем к BODY
+ var elem = document.createElement('div');
+ document.body.appendChild(elem);
+
+ // Записываем в свойство жирный объект
+ elem.__expando = {
+ bigAss: new Array(1000000).join('lalala')
+ };
+
+*!*
+ // Создаём круговую ссылку. Без этой строки утечки не будет.
+ elem.__expando.__elem = elem;
+*/!*
+
+ // Удалить элемент из DOM. Браузер должен очистить память.
+ elem.parentElement.removeChild(elem);
+}
+```
+
+Полный пример (только для IE8-, а также IE9 в режиме совместимости с IE8):
+
+[codetabs src="leak-ie8"]
+
+
+Круговая ссылка и, как следствие, утечка может возникать и неявным образом, через замыкание:
+
+```js
+function leak() {
+ var elem = document.createElement('div');
+ document.body.appendChild(elem);
+
+ elem.__expando = {
+ bigAss: new Array(1000000).join('lalala'),
+*!*
+ method: function() {} // создаётся круговая ссылка через замыкание
+*/!*
+ };
+
+ // Удалить элемент из DOM. Браузер должен очистить память.
+ elem.parentElement.removeChild(elem);
+}
+```
+
+Полный пример (IE8-, IE9 в режиме совместимости с IE8):
+
+[codetabs src="leak-ie8-2"]
+
+Без привязки метода `method` к элементу здесь утечки не возникнет.
+
+Бывает ли такая ситуация в реальной жизни? Или это -- целиком синтетический пример, для заумных программистов?
+
+Да, конечно бывает. Например, при разработке графических компонент -- бывает удобно присвоить DOM-элементу ссылку на JavaScript-объект, который представляет собой компонент. Это упрощает делегирование и, в общем-то, логично, что DOM-элемент знает о компоненте на себе. Но в IE8- прямая привязка ведёт к утечке памяти!
+
+Примерно так:
+```js
+function Menu(elem) {
+ elem.onclick = function() {};
+}
+
+var menu = new Menu(elem); // Menu содержит ссылку на elem
+*!*
+elem.menu = menu; // такая привязка или что-то подобное ведёт к утечке в IE8
+*/!*
+```
+
+Полный пример (IE8-, IE9 в режиме совместимости с IE8):
+
+[codetabs src="leak-ie8-widget"]
+
+### Утечка IE8 при обращении к коллекциям таблицы
+
+Эта утечка происходит только в IE8 в стандартном режиме. В нём при обращении к табличным псевдо-массивам (напр. `rows`) создаются и не очищаются внутренние ссылки, что приводит к утечкам.
+
+Также воспроизводится в новых IE в режиме совместимости с IE8.
+
+Код:
+
+```js
+var elem = document.createElement('div'); // любой элемент
+
+function leak() {
+
+ elem.innerHTML = '
1
';
+
+*!*
+ elem.firstChild.rows[0]; // просто доступ через rows[] приводит к утечке
+ // при том, что мы даже не сохраняем значение в переменную
+*/!*
+
+ elem.removeChild(elem.firstChild); // удалить таблицу (*)
+ // alert(elem.childNodes.length) // выдал бы 0, elem очищен, всё честно
+}
+```
+
+Полный пример (IE8):
+
+[codetabs src="leak-ie8-table"]
+
+Особенности:
+
+
Если убрать отмеченную строку, то утечки не будет.
+
Если заменить строку `(*)` на `elem.innerHTML = ''`, то память будет очищена, т.к. этот способ работает по-другому, нежели просто `removeChild` (см. главу [](/memory-management)).
+
Утечка произойдёт не только при доступе к `rows`, но и к другим свойствам, например `elem.firstChild.tBodies[0]`.
+
+
+Эта утечка проявляется, в частности, при удалении детей элемента следующей функцией:
+
+```js
+function empty(elem) {
+ while (elem.firstChild) elem.removeChild(elem.firstChild);
+}
+```
+
+Если идёт доступ к табличным коллекциям и регулярное обновление таблиц при помощи DOM-методов -- утечка в IE8 будет расти.
+
+Более подробно вы можете почитать об этой утечке в статье [Утечки памяти в IE8, или страшная сказка со счастливым концом](http://habrahabr.ru/post/141451/).
+
+### Утечка через XmlHttpRequest в IE8-
+
+Следующий код вызывает утечки памяти в IE8-:
+
+```js
+function leak() {
+ var xhr = new XMLHttpRequest();
+
+ xhr.open('GET', '/server.do', true);
+
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4 && xhr.status == 200) {
+ // ...
+ }
+ }
+
+ xhr.send(null);
+}
+```
+
+Как вы думаете, почему? Если вы внимательно читали то, что написано выше, то имеете информацию для ответа на этот вопрос..
+
+Посмотрим, какая структура памяти создается при каждом запуске:
+
+
+
+Когда запускается асинхронный запрос `xhr`, браузер создаёт специальную внутреннюю ссылку (internal reference) на этот объект. находится в процессе коммуникации. Именно поэтому объект `xhr` будет жив после окончания работы функции.
+
+Когда запрос завершен, браузер удаляет внутреннюю ссылку, `xhr` становится недостижимым и память очищается... Везде, кроме IE8-.
+
+
+Полный пример (IE8):
+
+[codetabs src="leak-ie8-xhr"]
+
+Чтобы это исправить, нам нужно разорвать круговую ссылку `XMLHttpRequest ↔ JS`. Например, можно удалить `xhr` из замыкания:
+
+```js
+function leak() {
+ var xhr = new XMLHttpRequest();
+
+ xhr.open('GET', 'something.js?' + Math.random(), true);
+
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState != 4) return;
+
+ if (xhr.status == 200) {
+ document.getElementById('test').innerHTML++;
+ }
+
+*!*
+ xhr = null; // по завершении запроса удаляем ссылку из замыкания
+*/!*
+ }
+
+ xhr.send(null);
+}
+```
+
+
+
+Теперь циклической ссылки нет -- и не будет утечки.
+
+
+## Объемы утечек памяти
+
+Объем "утекающей" памяти может быть небольшим. Тогда это почти не ощущается. Но так как замыкания ведут к сохранению переменных внешних функций, то одна функция может тянуть за собой много чего ещё.
+
+Представьте, вы создали функцию, и одна из ее переменных содержит очень большую по объему строку (например, получает с сервера).
+
+```js
+function f() {
+ var data = "Большой объем данных, например, переданных сервером"
+
+ /* делаем что-то хорошее (ну или плохое) с полученными данными */
+
+ function inner() {
+ // ...
+ }
+
+ return inner;
+}
+```
+
+Пока функция `inner` остается в памяти, `LexicalEnvironment` с переменной большого объема внутри висит в памяти.
+
+Висит до тех пор, пока функция `inner` жива.
+
+Как правило, JavaScript не знает, какие из переменных функции `inner` будут использованы, поэтому оставляет их все. Исключение -- виртуальная машина V8 (Chrome, Opera, Node.JS), она часто (не всегда) видит, что переменная не используется во внутренних функциях, и очистит память.
+
+В других же интерпретаторах, даже если код спроектирован так, что никакой утечки нет, по вполне разумной причине может создаваться множество функций, а память будет расти потому, что функция тянет за собой своё замыкание.
+
+Сэкономить память здесь вполне можно. Мы же знаем, что переменная `data` не используется в `inner`. Поэтому просто обнулим её:
+
+```js
+function f() {
+ var data = "Большое количество данных, например, переданных сервером"
+
+ /* действия с data */
+
+ function inner() {
+ // ...
+ }
+
+*!*
+ data = null; // когда data станет не нужна -
+*/!*
+
+ return inner;
+}
+```
+
+## Поиск и устранение утечек памяти
+
+### Проверка на утечки
+
+Существует множество шаблонов утечек и ошибок в браузерах, которые могут приводить к утечкам. Для их устранения сперва надо постараться изолировать и воспроизвести утечку.
+
+
+
**Необходимо помнить, что браузер может очистить память не сразу когда объект стал недостижим, а чуть позже.** Например, сборщик мусора может ждать, пока не будет достигнут определенный лимит использования памяти, или запускаться время от времени.
+
+Поэтому если вы думаете, что нашли проблему и тестовый код, запущенный в цикле, течёт -- подождите примерно минуту, добейтесь, чтобы памяти ело стабильно и много. Тогда будет понятно, что это не особенность сборщика мусора.
**Если речь об IE, то надо смотреть "Виртуальную память" в списке процессов, а не только обычную "Память".** Обычная может очищаться за счет того, что перемещается в виртуальную (на диск).
+
Для простоты отладки, если есть подозрение на утечку конкретных объектов, в них добавляют большие свойства-маркеры. Например, подойдет фрагмент текста: `new Array(999999).join('leak')`.
+
+
+### Настройка браузера
+
+Утечки могут возникать из-за расширений браузера, взимодействющих со страницей. Еще более важно, что **утечки могут быть следствием конфликта двух браузерных расширений** Например, было такое: память текла когда включены расширения Skype и плагин антивируса одновременно.
+
+Чтобы понять, в расширениях дело или нет, нужно отключить их:
+
+
+
Отключить Flash.
+
Отключить анивирусную защиту, проверку ссылок и другие модули и дополнения.
+
Отключить плагины. Отключить ВСЕ плагины.
+
+
+ Для IE есть параметр коммандной строки:
+
+```
+"C:\Program Files\Internet Explorer\iexplore.exe" -extoff
+```
+
+Кроме того необходимо отключить сторонние расширения в свойствах IE.
+
+
+
+
+
+
Firefox необходимо запускать с чистым профилем. Используйте следующую команду для запуска менеджера профилей и создания чистого пустого профиля:
+
+```
+firefox --profilemanager
+```
+
+
+
+
+
+
+## Инструменты
+
+Пожалуй, единственный браузер с поддержкой отладки памяти -- это Chrome. В инструментах разработчика вкладка Timeline -- Memory показывает график использования памяти.
+
+
+
+Можем посмотреть, сколько памяти и куда он использует.
+
+Также в Profiles есть кнопка Take Heap Snapshot, здесь можно сделать и исследовать снимок текущего состояния страницы. Снимки можно сравнивать друг с другом, выяснять количество новых объектов. Можно смотреть, почему объект не очищен и кто на него ссылается.
+
+Замечательная статья на эту тему есть в документации: [Chrome Developer Tools: Heap Profiling](http://code.google.com/chrome/devtools/docs/heap-profiling.html).
+
+Утечки памяти штука довольно сложная. В борьбе с ними вам определенно понадобится одна вещь: *Удача!*
+
+
diff --git a/6-optimize/4-memory-leaks/chrome.png b/6-optimize/4-memory-leaks/chrome.png
new file mode 100644
index 00000000..0c88b10b
Binary files /dev/null and b/6-optimize/4-memory-leaks/chrome.png differ
diff --git a/6-optimize/4-memory-leaks/goodluck.png b/6-optimize/4-memory-leaks/goodluck.png
new file mode 100644
index 00000000..918b5022
Binary files /dev/null and b/6-optimize/4-memory-leaks/goodluck.png differ
diff --git a/6-optimize/4-memory-leaks/ie1.png b/6-optimize/4-memory-leaks/ie1.png
new file mode 100644
index 00000000..ae04e2cc
Binary files /dev/null and b/6-optimize/4-memory-leaks/ie1.png differ
diff --git a/6-optimize/4-memory-leaks/ie2.png b/6-optimize/4-memory-leaks/ie2.png
new file mode 100644
index 00000000..93617434
Binary files /dev/null and b/6-optimize/4-memory-leaks/ie2.png differ
diff --git a/6-optimize/4-memory-leaks/ie9_disable1.png b/6-optimize/4-memory-leaks/ie9_disable1.png
new file mode 100644
index 00000000..84c98b78
Binary files /dev/null and b/6-optimize/4-memory-leaks/ie9_disable1.png differ
diff --git a/6-optimize/4-memory-leaks/ie9_disable2.png b/6-optimize/4-memory-leaks/ie9_disable2.png
new file mode 100644
index 00000000..3817bc53
Binary files /dev/null and b/6-optimize/4-memory-leaks/ie9_disable2.png differ
diff --git a/6-optimize/4-memory-leaks/leak-ie8-2.view/index.html b/6-optimize/4-memory-leaks/leak-ie8-2.view/index.html
new file mode 100644
index 00000000..b89b80de
--- /dev/null
+++ b/6-optimize/4-memory-leaks/leak-ie8-2.view/index.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Нажимайте на кнопку и наблюдайте, как увеличивается количество занимаемой браузером памяти.
+
+
+
+
+
\ No newline at end of file
diff --git a/6-optimize/4-memory-leaks/leak-ie8-table.view/index.html b/6-optimize/4-memory-leaks/leak-ie8-table.view/index.html
new file mode 100644
index 00000000..e0017dce
--- /dev/null
+++ b/6-optimize/4-memory-leaks/leak-ie8-table.view/index.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
Нажимайте на кнопку и наблюдайте, как увеличивается количество занимаемой браузером памяти.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/6-optimize/4-memory-leaks/leak-ie8-widget.view/index.html b/6-optimize/4-memory-leaks/leak-ie8-widget.view/index.html
new file mode 100644
index 00000000..1bdd947c
--- /dev/null
+++ b/6-optimize/4-memory-leaks/leak-ie8-widget.view/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Нажимайте на кнопку и наблюдайте, как увеличивается количество занимаемой браузером памяти.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/6-optimize/4-memory-leaks/leak-ie8-xhr.view/index.html b/6-optimize/4-memory-leaks/leak-ie8-xhr.view/index.html
new file mode 100644
index 00000000..67329b91
--- /dev/null
+++ b/6-optimize/4-memory-leaks/leak-ie8-xhr.view/index.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
Страница создаёт объект XMLHttpRequest каждые 50мс.
+
+
Нажмите на кнопку и смотрите на память, она течёт в IE<9.
+
+
+
+
+
+
Количество запросов: 0
+
+
+
+
\ No newline at end of file
diff --git a/6-optimize/4-memory-leaks/leak-ie8.view/index.html b/6-optimize/4-memory-leaks/leak-ie8.view/index.html
new file mode 100644
index 00000000..c2c1a4fc
--- /dev/null
+++ b/6-optimize/4-memory-leaks/leak-ie8.view/index.html
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Нажимайте на кнопку и наблюдайте, как увеличивается количество занимаемой браузером памяти.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/6-optimize/4-memory-leaks/leak-xhr-2.svg b/6-optimize/4-memory-leaks/leak-xhr-2.svg
new file mode 100644
index 00000000..e6faf68c
--- /dev/null
+++ b/6-optimize/4-memory-leaks/leak-xhr-2.svg
@@ -0,0 +1,37 @@
+
+
\ No newline at end of file
diff --git a/6-optimize/4-memory-leaks/leak-xhr.svg b/6-optimize/4-memory-leaks/leak-xhr.svg
new file mode 100644
index 00000000..967a4b3c
--- /dev/null
+++ b/6-optimize/4-memory-leaks/leak-xhr.svg
@@ -0,0 +1,43 @@
+
+
\ No newline at end of file
diff --git a/6-optimize/5-memory-leaks-jquery/article.md b/6-optimize/5-memory-leaks-jquery/article.md
new file mode 100644
index 00000000..70b76c45
--- /dev/null
+++ b/6-optimize/5-memory-leaks-jquery/article.md
@@ -0,0 +1,144 @@
+
+# Утечки памяти при использовании jQuery
+
+В jQuery для хранения обработчиков событий и других вспомогательных данных, связанных с DOM-элементами, используется внутренний объект, который в jQuery 1 доступен через $.data.
+
+В jQuery 2 доступ к нему закрыт через замыкание, он стал локальной переменной внутри jQuery с именем `data_priv`, но в остальном всё работает точно так, как описано, и с теми же последствиями.
+
+## $.data
+
+Встроенная функция `$.data` позволяет хранить привязывать произвольные значения к DOM-узлам.
+
+Например:
+
+```js
+//+ no-beautify
+// присвоить
+$(document).data('prop', { anything: "любой объект" })
+
+// прочитать
+alert( $(document).data('prop').anything ) // любой объект
+```
+
+Реализована она хитрым образом. Данные не хранятся в самом элементе, а во внутреннем объекте jQuery.
+
+jQuery-вызов `elem.data(prop, val)` делает следующее:
+
+
+
Элемент получает уникальный идентификатор, если у него такого еще нет:
+
+```js
+elem[jQuery.expando] = id = ++jQuery.uuid; // средствами jQuery
+```
+
+`jQuery.expando` -- это случайная строка, сгенерированная jQuery один раз при входе на страницу. Уникальное свойство, чтобы ничего важного не перезаписать.
+
...А сами данные сохраняются в специальном объекте `jQuery.cache`:
+
+```js
+//+ no-beautify
+jQuery.cache[id]['prop'] = { anything: "любой объект" };
+```
+
+
+
+
+Когда данные считываются из элемента:
+
+
+
Уникальный идентификатор элемента извлекается из `id = elem[ jQuery.expando]`.
+
Данные считываются из `jQuery.cache[id]`.
+
+
+Смысл этого API в том, что DOM-элемент никогда не ссылается на JavaScript объект напрямую. Задействуется идентификатор, а сами данные хранятся в `jQuery.cache`. Утечек в IE не будет.
+
+К тому же все данные известны библиотеке, так что можно клонировать с ними и т.п.
+
+Как побочный эффект -- возникает утечка памяти, если элемент удален из DOM без дополнительной очистки.
+
+## Примеры утечек в jQuery
+
+Следующая функция `leak` создает jQuery-утечку во всех браузерах:
+
+
+```html
+
+
+
+
+
+
+
+Утечка идёт...
+
+
+```
+
+
+Утечка происходит потому, что обработчик события в jQuery хранится в данных элемента. В строке `(*)` элемент удален очисткой родительского `innerHTML`, но в `jQuery.cache` данные остались.
+
+Более того, система обработки событий в jQuery устроена так, что вместе с обработчиком в данных хранится и ссылка на элемент, так что в итоге оба -- и обработчик и элемент -- остаются в памяти вместе со всем замыканием!
+
+Ещё более простой пример утечки:
+
+Этот код также создает утечку:
+
+```js
+function leak() {
+ $('')
+ .click(function() {})
+}
+```
+
+...То есть, мы создаём элемент, вешаем на него обработчик... И всё.
+
+Такой код ведёт к утечке памяти как раз потому, что элемент `
` создан, но нигде не размещен :). После выполнения функции ссылка на него теряется. Но обработчик события `click` уже сохранил данные в `jQuery.cache`, которые застревают там навсегда.
+
+## Используем jQuery без утечек
+
+Чтобы избежать утечек, описанных выше, для удаления элементов используйте функции jQuery API, а не чистый JavaScript.
+
+Методы remove(), empty() и html() проверяют дочерние элементы на наличие данных и очищают их. Это несколько замедляет процедуру удаления, но зато освобождается память.
+
+К счастью обнаружить такие утечки легко. Проверьте размер `$.cache`. Если он большой и растет, то изучите кэш, посмотрите, какие записи остаются и почему.
+
+## Улучшение производительности jQuery
+
+У способа организации внутренних данных, применённого в jQuery, есть важный побочный эффект.
+
+Функции, удаляющие элементы, также должны удалить и связанные с ними внутренние данные. Для этого нужно для каждого удаляемого элемента проверить -- а нет ли чего во внутреннем хранилище? И, если есть -- удалить.
+
+Представим, что у нас есть большая таблица `
`, и мы хотим обновить её содержимое на новое. Вызов `$('table').html(новые данные)` перед вставкой новых данных аккуратно удалит старые: пробежит по всем ячейкам и проверит внутреннее хранилище.
+
+Если это большая таблица, то обработчики, скорее всего, стоят не на ячейках, а на самом элементе `
`, то есть используется делегирование. А, значит, тратить время на проверку всех подэлементов ни к чему.
+
+Но jQuery-то об этом не знает!
+
+Чтобы "грязно" удалить элемент, без чистки, мы можем сделать это через "обычные" DOM-вызовы или воспользоваться методом detach(). Его официальное назначение -- в том, чтобы убрать элемент из DOM, но сохранить возможность для вставки (и, соответственно, оставить на нём все данные). А неофициальное -- быстро убрать элемент из DOM, без чистки.
+
+Возможен и промежуточный вариант: никто не мешает сделать `elem.detach()` и поместить вызов `elem.remove()` в `setTimeout`. В результате очистка будет происходить асинхронно и незаметно.
+
+## Итого
+
+
+
Утечки памяти при использовании jQuery возможны, если через DOM-методы удалять элементы, к которым привязаны данные или обработчики.
+
Чтобы утечки не было, достаточно убедиться, что элемент удаляется при помощи методов jQuery.
+
Побочный эффект -- при удалении элементов jQuery должна проверить наличие данных для них. Это сильно замедляет процесс удаления большого поддерева DOM.
+
Если мы значем, что обработчиков и данных нет -- гораздо быстрее удалять элементы при помощи вызова `detach` или обычного DOM.
+
+
+
diff --git a/6-optimize/6-memory-removechild-innerhtml/article.md b/6-optimize/6-memory-removechild-innerhtml/article.md
new file mode 100644
index 00000000..5882124d
--- /dev/null
+++ b/6-optimize/6-memory-removechild-innerhtml/article.md
@@ -0,0 +1,147 @@
+# Очистка памяти при removeChild/innerHTML
+
+Управление памятью в случае с DOM работает по сути так же, как и с обычными JavaScript-объектами. Пока объект достижим -- он остаётся в памяти.
+
+Но есть и особенности, поскольку DOM весь переплетён ссылками.
+[cut]
+## Пример
+Для примера рассмотрим следующий HTML:
+
+```html
+
+
+
+
+
+
Список
+
+ Сосед
+
+
+
+
+```
+
+Его DOM (показаны только основные ссылки):
+
+
+
+## Удаление removeChild
+
+Операция `removeChild` разрывает все связи удаляемым узлом и его родителем.
+
+Поэтому, если удалить `DIV` из `BODY`, то всё поддерево под `DIV` станет недостижимым и будет удалено.
+
+А что происходит, если на какой-то элемент внутри удаляемого поддерева есть ссылка?
+
+Например, `UL` сохранён в переменную `list`:
+
+```js
+var list = document.getElementsByTagName('UL')[0];
+document.body.removeChild(document.body.children[0]);
+```
+
+В этом случае, так как из этого `UL` можно по ссылкам добраться до любого другого места DOM, то получается, что все объекты по-прежнему достижимы и должны остаться в памяти:
+
+
+
+То есть, DOM-объекты при использовании `removeChild` работают по той же логике, что и обычные объекты.
+
+## Удаление через innerHTML
+
+А вот удаление через очистку `elem.innerHTML="..."` браузеры интерпретируют по-разному.
+
+По идее, при присвоении `elem.innerHTML=html` из DOM должны удаляться предыдущие узлы и добавляться новые, из указанного `html`. Но стандарт ничего не говорит о том, что делать с узлами после удаления. И тут разные браузеры имеют разное мнение.
+
+Посмотрим, что произойдёт с DOM-структурой при очистке `BODY`, если на какой-либо элемент есть ссылка.
+
+```js
+var list = document.getElementsByTagName('UL')[0];
+document.body.innerHTML = "";
+```
+
+Обращаю внимание -- связь разрывается только между `DIV` и `BODY`, т.е. на верхнем уровне, а `list` -- это произвольный элемент.
+
+Чтобы увидеть, что останется в памяти, а что нет -- запустим код:
+
+```html
+
+
+
+
Список
+
+ Сосед
+
+
+
+```
+
+Как ни странно, браузеры ведут себя по-разному:
+
+
+
+
+
`parentNode`
+
`nextSibling`
+
`children.length`
+
+
+
+
+
Chrome/Safari/Opera
+
`null`
+
`null`
+
`1`
+
+
+
Firefox
+
узел DOM
+
узел DOM
+
`1`
+
+
+
IE 11-
+
`null`
+
`null`
+
`0`
+
+
+
+
+Иными словами, браузеры ведут себя с различной степенью агрессивности по отношению к элементам.
+
+
+
Firefox
+
Главный пацифист. Оставляет всё, на что есть ссылки, т.е. элемент, его родителя, соседей и детей, в точности как при `removeChild`.
+
Chrome/Safari/Opera
+
Считают, что раз мы задали ссылку на `UL`, то нам нужно только это поддерево, а остальные узлы (соседей, родителей) можно удалить.
+
Internet Explorer
+
Как ни странно, самый агрессивный. Удаляет вообще всё, кроме узла, на который есть ссылка. Это поведение одинаково для всех версий IE.
+
+
+На иллюстрации ниже показано, какую часть DOM оставит каждый из браузеров:
+
+
+## Итого
+
+Если на какой-то DOM-узел есть ссылка, то:
+
+
+
При использовании `removeChild` на родителе (или на этом узле, не важно) все узлы, достижимые из данного, остаются в памяти.
+
+То есть, фактически, в памяти может остаться большая часть дерева DOM. Это даёт наибольшую свободу в коде, но может привести к большим "утечкам памяти" из-за сохранения данных, которые реально не нужны.
+
При удалении через `innerHTML` браузеры ведут себя с различной степенью агрессивности. Кросс-браузерно гарантировано одно: сам узел, на который есть ссылка, останется в памяти.
+
+Поэтому обращаться к соседям и детям узла, предок которого удалён через присвоение `innerHTML`, нельзя.
+
+
+
+
+
diff --git a/6-optimize/6-memory-removechild-innerhtml/html-innerhtml.png b/6-optimize/6-memory-removechild-innerhtml/html-innerhtml.png
new file mode 100644
index 00000000..e606be2a
Binary files /dev/null and b/6-optimize/6-memory-removechild-innerhtml/html-innerhtml.png differ
diff --git a/6-optimize/6-memory-removechild-innerhtml/html-list.png b/6-optimize/6-memory-removechild-innerhtml/html-list.png
new file mode 100644
index 00000000..1ffd8ace
Binary files /dev/null and b/6-optimize/6-memory-removechild-innerhtml/html-list.png differ
diff --git a/6-optimize/6-memory-removechild-innerhtml/html.png b/6-optimize/6-memory-removechild-innerhtml/html.png
new file mode 100644
index 00000000..ca8da064
Binary files /dev/null and b/6-optimize/6-memory-removechild-innerhtml/html.png differ
diff --git a/6-optimize/7-gcc-advanced-optimization/article.md b/6-optimize/7-gcc-advanced-optimization/article.md
new file mode 100644
index 00000000..f2a84d14
--- /dev/null
+++ b/6-optimize/7-gcc-advanced-optimization/article.md
@@ -0,0 +1,530 @@
+# GCC: продвинутые оптимизации
+
+Продвинутый режим оптимизации google closure compiler включается опцией --compilation_level ADVANCED_OPTIMIZATIONS.
+
+Слово "продвинутый" (advanced) здесь, пожалуй, не совсем подходит. Было бы более правильно назвать его "супер-агрессивный-ломающий-ваш-неподготовленный-код-режим". Кардинальное отличие применяемых оптимизаций от обычных (simple) -- в том, что они небезопасны.
+
+Чтобы им пользоваться -- надо уметь это делать.
+[cut]
+
+## Основной принцип продвинутого режима
+
+
+
Если в обычном режиме переименовываются только локальные переменные внутри функций, то в "продвинутом" -- на более короткие имена заменяется все.
+
Если в обычном режиме удаляется недостижимый код после return, то в продвинутом -- вообще весь код, который не вызывается в явном виде.
+
+
+Например, если запустить продвинутую оптимизацию на таком коде:
+
+```js
+// my.js
+function test(node) {
+ node.innerHTML = "newValue"
+}
+```
+
+Строка запуска компилятора:
+
+```
+java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js my.js
+```
+
+...То результат будет -- пустой файл. Google Closure Compiler увидит, что функция test не используется, и с чистой совестью вырежет ее.
+
+А в следующем скрипте функция сохранится:
+
+```js
+function test(n) {
+ alert( "this is my test number " + n );
+}
+test(1);
+test(2);
+```
+
+После сжатия:
+
+```js
+function a(b) {
+ alert("this is my test number " + b)
+}
+a(1);
+a(2);
+```
+
+Здесь в скрипте присутствует явный вызов функции, поэтому она сохранилась.
+
+Конечно, есть способы, чтобы сохранить функции, вызов которых происходит вне скрипта, и мы их обязательно рассмотрим.
+
+**Продвинутый режим сжатия не предусматривает сохранения глобальных переменных. Он переименовывает, инлайнит, удаляет вообще все символы, кроме зарезервированных.**
+
+Иначе говоря, продвинутый режим (ADVANCED_OPTIMIZATIONS), в отличие от простого (SIMPLE_OPTIMIZATIONS -- по умолчанию), вообще не заботится о доступности кода извне и сохранении ссылочной целостности относительно внешних скриптов.
+
+Единственное, что он гарантирует -- это внутреннюю ссылочную целостность, и то -- при соблюдении ряда условий и практик программирования.
+
+Собственно, за счет такого агрессивного подхода и достигается дополнительный эффект оптимизации и сжатия скриптов.
+
+[summary]
+То есть, продвинутый режим - это не просто "улучшенный обычный", а принципиально другой, небезопасный и обфусцирующий подход к сжатию.
+
+Этот режим является "фирменной фишкой" Google Closure Compiler, недоступной при использовании других компиляторов.
+[/summary]
+
+Для того, чтобы эффективно сжимать Google Closure Compiler в продвинутом режиме, нужно понимать, что и как он делает. Это мы сейчас обсудим.
+
+### Сохранение ссылочной целостности
+
+Чтобы использовать сжатый скрипт, мы должны иметь возможность вызывать функции под теми именами, которые им дали.
+
+То есть, перед нами стоит задача *сохранения ссылочной целостности*, которая заключается в том, чтобы обеспечить доступность нужных функций для обращений по исходному имени извне скрипта.
+
+Существует два способа сохранения внешней ссылочной целостности: экстерны и экспорты. Мы в подробностях рассмотрим оба, но перед этим необходимо упомянуть о модулях -- другой важнейшей возможности GCC.
+
+### Модули
+
+При сжатии GCC можно указать одновременно много JavaScript-файлов. "Эка невидаль, " -- скажете вы, и будете правы. Да, пока что ничего особого.
+
+Но в дополнение к этому можно явно указать, какие исходные файлы сжать в какие файлы результата. То есть, разбить итоговую сборку на модули.
+
+Так что страницы могут грузить модули по мере надобности. Например, по умолчанию -- главный, а дополнительная функциональность -- загружаться лишь там, где она нужна.
+
+Для такой сборки используется флаг компилятора `--module имя:количество файлов`.
+
+Например:
+
+```
+java -jar compiler.jar --js base.js --js main.js --js admin.js --module
+first:2 --module second:1:first
+```
+
+Эта команда создаст модули: first.js и second.js.
+
+Первый модуль, который назван "first", создан из объединённого и оптимизированного кода первых двух файлов (`base.js` и `main.js`).
+
+Второй модуль, который назван "second", создан из `admin.js` -- это следующий аргумент `--js` после включенных в первый модуль.
+
+Второй модуль в нашем случае зависит от первого. Флаг `--module second:1:first` как раз означает, что модуль `second` будет создан из одного файла после вошедших в предыдущий модуль (`first`) и зависит от модуля `first`.
+
+А теперь -- самое вкусное.
+
+**Ссылочная целостность между всеми получившимися файлами гарантируется.**
+
+Если в одном функция `doFoo` заменена на `b`, то и в другом тоже будет использоваться `b`.
+
+Это означает, что проблем между JS-файлами не будет. Они могут свободно вызывать друг друга без экспорта, пока находятся в единой модульной сборке.
+
+### Экстерны
+
+Экстерн (extern) -- имя, которое числится в специальном списке компилятора. Он должен быть определен вне скрипта, в файле экстернов.
+
+**Компилятор никогда не переименовывает экстерны.**
+
+Например:
+
+```js
+document.onkeyup = function(event) {
+ alert(event.type)
+}
+```
+
+После продвинутого сжатия:
+
+```js
+document.onkeyup = function(a) {
+ alert(a.type)
+}
+```
+
+Как видите, переименованной оказалась только переменная `event`. Такое переименование заведомо безопасно, т.к. `event` -- локальная переменная.
+
+Почему компилятор не тронул остального? Попробуем другой вариант:
+
+```js
+document.blabla = function(event) {
+ alert(event.megaProperty)
+}
+```
+
+После компиляции:
+
+```js
+document.a = function(a) {
+ alert(a.b)
+}
+```
+
+Теперь компилятор переименовал и blabla и megaProperty.
+
+Дело в том, что названия, использованные до этого, были во внутреннем списке экстернов компилятора. Этот список охватывает основные объекты браузеров и находится (под именем externs.zip) в корне архива compiler.jar.
+
+**Компилятор переименовывает имя списка экстернов только когда так названа локальная переменная.**
+
+Например:
+
+```js
+window.resetNode = function(node) {
+ var innerHTML = "test";
+ node.innerHTML = innerHTML;
+}
+```
+
+На выходе:
+
+```js
+window.a = function(a) {
+ a.innerHTML = "test"
+};
+```
+
+Как видите, внутренняя переменная innerHTML не просто переименована - она заинлайнена (заменена на значение). Так как переменная локальна, то любые действия внутри функции с ней безопасны.
+
+А свойство innerHTML не тронуто, как и объект window -- так как они в списке экстернов и не являются локальными переменными.
+
+Это приводит к следующему побочному эффекту. Иногда свойства, которые следовало бы сжать, не сжимаются. Например:
+
+```js
+window['User'] = function(name, type, age) {
+ this.name = name
+ this.type = type
+ this.age = age
+}
+```
+
+После сжатия:
+
+```js
+window.User = function(a, b, c) {
+ this.name = a;
+ this.type = b;
+ this.a = c
+};
+```
+
+Как видно, свойство age сжалось, а name и type -- нет. Это побочный эффект экстернов: name и type -- в списке объектов браузера, и компилятор просто старается не наломать дров.
+
+Поэтому отметим еще одно полезное правило оптимизации:
+
+**Названия своих свойств не должны совпадать с зарезервированными словами (экстернами). Тогда они будут хорошо сжиматься.**
+
+Для задания списка экстернов их достаточно перечислить в файле и указать этот файл флагом --externs <файл экстернов.js>.
+
+При перечислении объектов в файле экстернов - объявляйте их и перечисляйте свойства. Все эти объявления никуда не идут, они используются только для создания списка, который обрабатывается компилятором.
+
+Например, файл `myexterns.js`:
+
+```js
+var dojo = {}
+dojo._scopeMap;
+```
+
+Использование такого файла при сжатии (опция --externs myexterns.js) приведет к тому, что все обращения к символам dojo и к dojo._scopeMap будут не сжаты, а оставлены "как есть".
+
+
+### Экспорт
+
+*Экспорт* -- программный ход, основанный на следующем правиле поведения компилятора.
+
+**Компилятор заменяет обращения к свойствам через кавычки на точку, и при этом не трогает название свойства.**
+
+Например, window['User'] превратится в window.User, но не дальше.
+
+Таким образом можно *"экспортировать"* нужные функции и объекты:
+
+```js
+function SayWidget(elem) {
+ this.elem = elem
+ this.init()
+}
+window['SayWidget'] = SayWidget;
+```
+
+На выходе:
+
+```js
+function a(b) {
+ this.a = b;
+ this.b()
+}
+window.SayWidget = a;
+```
+
+Обратим внимание -- сама функция SayWidget была переименована в a. Но затем -- экспортирована как window.SayWidget, и таким образом доступна внешним скриптам.
+
+Добавим пару методов в прототип:
+
+```js
+function SayWidget(elem) {
+ this.elem = elem;
+ this.init();
+}
+
+SayWidget.prototype = {
+ init: function() {
+ this.elem.style.display = 'none'
+ },
+
+ setSayHandler: function() {
+ this.elem.onclick = function() {
+ alert("hi")
+ };
+ }
+}
+
+window['SayWidget'] = SayWidget;
+SayWidget.prototype['setSayHandler'] = SayWidget.prototype.setSayHandler;
+```
+
+После сжатия:
+
+```js
+//+ no-beautify
+function a(b) {
+ this.a = b;
+ this.b()
+}
+a.prototype = {b:function() {
+ this.a.style.display = "none"
+}, c:function() {
+ this.a.onclick = function() {
+ alert("hi")
+ }
+}};
+window.SayWidget = a;
+a.prototype.setSayHandler = a.prototype.c;
+```
+
+Благодаря строке
+
+```js
+SayWidget.prototype['setSayHandler'] = SayWidget.prototype.setSayHandler
+```
+
+метод setSayHandler экспортирован и доступен для внешнего вызова.
+
+Сама строка экспорта выглядит довольно глупо. По виду -- присваиваем свойство самому себе.
+
+Но логика сжатия GCC работает так, что такая конструкция является экспортом. Справа переименование свойства setSayHandler происходит, а слева -- нет.
+
+[smart header="Планируйте жизнь после сжатия"]
+
+Рассмотрим следующий код:
+
+```js
+window['Animal'] = function() {
+ this.blabla = 1;
+ this['blabla'] = 2;
+}
+```
+
+После сжатия:
+
+```js
+window.Animal = function() {
+ this.a = 1;
+ this.blabla = 2
+};
+```
+
+Как видно, первое обращение к свойству blabla сжалось, а второе (как и все аналогичные) -- преобразовалось в синтаксис через точку.
+В результате получили некорректное поведение кода.
+
+Так что, используя продвинутый режим оптимизации, планируйте поведение кода после сжатия.
+
+**Если где-то возможно обращение к свойствам через квадратные скобки по полному имени -- такое свойство должно быть экспортировано.**
+[/smart]
+
+### goog.exportSymbol и goog.exportProperty
+
+В библиотеке [Google Closure Library](https://developers.google.com/closure/library/) для экспорта есть специальная функция goog.exportSymbol. Вызывается так:
+
+```js
+goog.exportSymbol('my.SayWidget', SayWidget)
+```
+
+Эта функция по сути работает также, как и рассмотренная выше строка с присвоением свойства, но при необходимости создает нужные объекты.
+
+Она аналогична коду:
+
+```js
+window['my'] = window['my'] || {}
+window['my']['SayWidget'] = SayWidget
+```
+
+То есть, если путь к объекту не существует -- exportSymbol создаст нужные пустые объекты.
+
+Функция goog.exportProperty экспортирует свойство объекта:
+
+```js
+goog.exportProperty(SayWidget.prototype, 'setSayHandler', SayWidget.prototype.setSayHandler)
+```
+
+Строка выше - то же самое, что и:
+
+```js
+SayWidget.prototype['setSayHandler'] = SayWidget.prototype.setSayHandler
+```
+
+Зачем они нужны, если все можно сделать простым присваиванием?
+
+Основная цель этих функций -- во взаимодействии с Google Closure Compiler. Они дают информацию компилятору об экспортах, которую он может использовать.
+
+Например, есть недокументированная внутренняя опция externExportsPath, которая генерирует из всех экспортов файл экстернов. Таким образом можно распространять откомпилированный JavaScript-файл как внешнюю библиотеку, с файлом экстернов для удобного внешнего связывания.
+
+Кроме того, экспорт через эти функциями удобен и нагляден.
+
+Если вы используете продвинутый режим оптимизации, то можно взять их из файла base.js Google Closure Library. Можно и подключить этот файл целиком -- оптимизатор при продвинутом сжатии вырежет из него почти всё лишнее, так что overhead будет минимальным.
+
+### Отличия экспорта от экстерна
+
+Между экспортом и экстерном есть кое-что общее. И то и другое дает возможность доступа к объектам под исходным именем, до переименования.
+
+Но, в остальном, это совершенно разные вещи.
+
+
+
+
+
Экстерн
+
Экспорт
+
+
+
+
+
Служит для тотального запрета на переименование всех обращений к свойству.
+Задумано для сохранения обращений к стандартным объектам браузера, внешним библиотекам.
+
Служит для открытия доступа к свойству извне под указанным именем.
+Задумано для открытия внешнего интерфейса к сжатому скрипту.
+
+
+
Работает со свойством, объявленным вне скрипта.
+Вы не можете объявить новое свойство в скрипте и сделать его экстерном.
+
Создает ссылку на свойство, объявленное в скрипте.
+
+
+
Если window - экстерн, то все обращения к window в скрипте останутся как есть.
+
Если user экспортируется, то создается только одна ссылка под полным именем, а все остальные обращения будут сокращены.
+
+
+
+
+
+## Стиль разработки
+
+Посмотрим, как сжиматель поведёт себя на следующем, типичном, объявлении библиотеки:
+
+```js
+(function(window, undefined) {
+
+ // пространство имен и локальная перменная для него
+ var MyFramework = window.MyFramework = {};
+
+ // функция фреймворка, доступная снаружи
+ MyFramework.publicOne = function() {
+ makeElem();
+ };
+
+ // приватная функция фреймворка
+ function makeElem() {
+ var div = document.createElement('div');
+ document.body.appendChild(div);
+ }
+
+ // еще какая-то функция
+ MyFramework.publicTwo = function() {};
+
+})(window);
+
+// использование
+MyFramework.publicOne();
+```
+
+Результат компиляции в обычном режиме:
+
+```js
+//+ no-beautify
+// java -jar compiler.jar --js myframework.js --formatting PRETTY_PRINT
+(function(a) {
+ a = a.MyFramework = {};
+ a.publicOne = function() {
+ var a = document.createElement("div");
+ document.body.appendChild(a)
+ };
+ a.publicTwo = function() {
+ }
+})(window);
+MyFramework.publicOne();
+```
+
+Это -- примерно то, что мы ожидали. Неиспользованный метод `publicTwo` остался, локальные свойства переименованы и заинлайнены.
+
+А теперь продвинутый режим:
+
+```js
+// --compilation_level ADVANCED_OPTIMIZATIONS
+window.a = {};
+MyFramework.b();
+```
+
+Оно не работает! Компилятор попросту не разобрался, что и как вызывается, и превратил рабочий JS-файл в один сплошной баг.
+
+В зависимости от версии GCC у вас может быть и что-то другое.
+
+Всё дело в том, что такой стиль объявления нетипичен для инструментов, которые в самом Google разрабатываются и сжимаются этим минификатором.
+
+Типичный правильный стиль:
+
+```js
+// пространство имен и локальная перменная для него
+var MyFramework = {};
+
+MyFrameWork._makeElem = function() {
+ var div = document.createElement('div');
+ document.body.appendChild(div);
+};
+
+MyFramework.publicOne = function() {
+ MyFramework._makeElem();
+};
+
+MyFramework.publicTwo = function() {};
+
+// использование
+MyFramework.publicOne();
+```
+
+Обычное сжатие здесь будет бесполезно, а вот продвинутый режим идеален:
+
+```js
+// в зависимости от версии GCC результат может отличаться
+MyFrameWork.a = function() {
+ var a = document.createElement("div");
+ document.body.appendChild(a)
+};
+MyFrameWork.a();
+```
+
+Google Closure Compiler не только разобрался в структуре и удалил лишний метод - он заинлайнил функции, чтобы итоговый размер получился минимальным.
+
+Как говорится, преимущества налицо.
+
+## Резюме
+
+Продвинутый режим оптимизации сжимает, оптимизирует и, при возможности, удаляет все свойства и методы, за исключением экстернов.
+
+Это является принципиальным отличием, по сравнению с другими упаковщиками.
+
+Отказ от сохранения внешней ссылочной целостности с одной стороны позволяет увеличить уровень сжатия, но требует поддержки со стороны разработчика.
+
+Основная проблема этого сжатия -- усложнение разработки. Добавляется дополнительный уровень возможных проблем: сжатие. Конечно, можно отлаживать и сжатый код, для этого придуманы [Source Maps](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/), но клиентская разработка и без того достаточно сложна.
+
+Поэтому его используют редко.
+
+Как правило, есть две причины для использования продвинутого режима:
+
+
**Обфускация кода.**
+
+Если в коде после обычного сжатия ещё как-то можно разобраться, то после продвинутого -- уже нет. Всё переименовано и заинлайнено. В теории это, конечно, возможно, но "порог входа" в такой код несоизмеримо выше.
+
+Судя по виду скриптов на сайтах, созданных Google, сам Google жмет свои скрипты именно продвинутым режимом оптимизации. И библиотека Google Closure Library тоже рассчитана на него.
+
**Хорошие сжатие виджетов, счётчиков.**
+
+Небольшой код, который отдаётся наружу, может быть сжат в продвинутом режиме. Так как он небольшой -- все ошибки можно легко исправить, а продвинутый режим гарантирует наилучшее сжатие.
+
diff --git a/6-optimize/8-gcc-check-types/article.md b/6-optimize/8-gcc-check-types/article.md
new file mode 100644
index 00000000..8c625359
--- /dev/null
+++ b/6-optimize/8-gcc-check-types/article.md
@@ -0,0 +1,177 @@
+# GCC: статическая проверка типов
+
+Google Closure Compiler, как и любой кошерный компилятор, старается проверить правильность кода и предупредить о возможных ошибках.
+
+Первым делом он, разумеется, проверяет структуру кода и сразу же выдает такие ошибки как пропущенная скобка или лишняя запятая.
+
+Но, кроме этого, он умеет проверять типы переменных, используя как свои собственные знания о встроенных javascript-функциях и преобразованиях типов,
+так и информацию о типах из JSDoc, указываемую javascript-разработчиком.
+
+Это обеспечивает то, чем так гордятся компилируемые языки -- статическую проверку типов, что позволяет избежать лишних ошибок во время выполнения.
+[cut]
+
+Для вывода предупреждений при проверки типов используется флаг `--jscomp_warning checkTypes`.
+
+## Задание типа при помощи аннотации
+
+Самый очевидный способ задать тип -- это использовать аннотацию. Полный список аннотаций вы найдете в документации.
+
+В следующем примере параметр id функции f1 присваивается переменной boolVar другого типа:
+
+```js
+/** @param {number} id */
+function f(id) {
+ /** @type {boolean} */
+ var boolVar;
+
+ boolVar = id; // (!)
+}
+```
+
+Компиляция с флагом `--jscomp_warning checkTypes` выдаст предупреждение:
+
+```
+f.js:6: WARNING - assignment
+found : number
+required: boolean
+ boolVar = id; // (!)
+ ^
+```
+
+Действительно: произошло присвоение значения типа number переменной типа boolean.
+
+Типы отслеживаются по цепочке вызовов.
+
+Еще пример, на этот раз вызов функции с некорректным параметром:
+
+```js
+/** @param {number} id */
+function f1(id) {
+ f2(id); // (!)
+}
+
+/** @param {string} id */
+function f2(id) {}
+```
+
+Такой вызов приведёт к предупреждению со стороны минификатора:
+
+```
+f2.js:3: WARNING - actual parameter 1 of f2 does not match formal parameter
+found : number
+required: string
+ f2(id); // (!)
+ ^
+```
+
+Действительно, вызов функции f2 произошел с числовым типом вместо строки.
+
+**Отслеживание приведений и типов идёт при помощи графа взаимодействий и выведению (infer) типов, который строит GCC по коду.**
+
+## Знания о преобразовании типов
+
+Google Closure Compiler знает, как операторы javascript преобразуют типы. Такой код уже не выдаст ошибку:
+
+```js
+/** @param {number} id */
+function f1(id) {
+ /** @type {boolean} */
+ var boolVar;
+
+ boolVar = !!id
+}
+```
+
+Действительно - переменная преобразована к типу boolean двойным оператором НЕ.
+А код boolVar = 'test-'+id выдаст ошибку, т.к. конкатенация со строкой дает тип string.
+
+## Знание о типах встроенных функций, объектные типы
+
+Google Closure Compiler содержит описания большинства встроенных объектов и функций javascript вместе с типами параметров и результатов.
+
+Например, объектный тип Node соответствует узлу DOM.
+
+Пример некорректного кода:
+
+```js
+/** @param {Node} node */
+function removeNode(node) {
+ node.parentNode.removeChild(node)
+}
+document.onclick = function() {
+ removeNode("123")
+}
+```
+
+Выдаст предупреждение
+
+```
+f3.js:7: WARNING - actual parameter 1 of removeNode does not match formal parameter
+found : string
+required: (Node|null)
+ removeNode("123")
+ ^
+```
+
+Обратите внимание - в этом примере компилятор выдает required: Node|null. Это потому, что указание объектного типа (не элементарного) подразумевает, что в функцию может быть передан null.
+
+В следующем примере тип указан жестко, без возможности обнуления:
+
+```js
+*!*
+/** @param {!Node} node */
+*/!*
+function removeNode(node) {
+ node.parentNode.removeChild(node)
+}
+```
+
+Восклицательный знак означает, что параметр обязатален.
+
+Найти описания встроенных типов и объектов javascript вы можете в файле экстернов: externs.zip находится в корне архива compiler.jar.
+
+## Интеграция с проверками типов из Google Closure Library
+
+В Google Closure Library есть функции проверки типов: goog.isArray, goog.isDef, goog.isNumber и т.п.
+
+Google Closure Compiler знает о них и понимает, что внутри следующего if переменная может быть только функцией:
+
+```js
+var goog = {
+ isFunction: function(f) {
+ return typeof f == 'function'
+ }
+}
+
+if (goog.isFunction(func)) {
+ func.apply(1, 2)
+}
+```
+
+Сжатие с проверкой выдаст предупреждение:
+
+```
+f.js:6: WARNING - actual parameter 2 of Function.apply does not match formal parameter
+found : number
+required: (Object|null|undefined)
+ func.apply(1, 2)
+ ^ ^
+```
+
+То есть, компилятор увидел, что код, использующий func находится в `if (goog.isFunction(func))` и сделал соответствующий вывод, что это в этой ветке `func` является функцией, а значит вызов `func.apply(1,2)` ошибочен (второй аргумент не может быть числом).
+
+Дело тут именно в интеграции с Google Closure Library. Если поменять `goog` на `g` -- предупреждения не будет.
+
+## Резюме
+
+Из нескольких примеров, которые мы рассмотрели, должна быть понятна общая логика проверки типов.
+
+Соответствующие различным типам и ограничениям на типы аннотации вы можете найти в Документации Google. В частности, возможно указание нескольких возможных типов, типа undefined и т.п.
+
+Также можно указывать количество и тип параметров функции, ключевого слова this, объявлять классы, приватные методы и интерфейсы.
+
+Проверка типов javascript, предоставляемая Google Closure Compiler -- пожалуй, самая продвинутая из существующих на сегодняшний день.
+
+C ней аннотации, документирующие типы и параметры, становятся не просто украшением, а реальным средством проверки, уменьшающим количество ошибок на production.
+
+Очень подробно проверка типов описана в книге [Closure: The Definitive Guide](http://www.ozon.ru/context/detail/id/6089988/), автора Michael Bolin.
\ No newline at end of file
diff --git a/6-optimize/9-gcc-closure-library/article.md b/6-optimize/9-gcc-closure-library/article.md
new file mode 100644
index 00000000..0c02e685
--- /dev/null
+++ b/6-optimize/9-gcc-closure-library/article.md
@@ -0,0 +1,180 @@
+# GCC: интеграция с Google Closure Library
+
+Google Closure Compiler содержит ряд специальных возможностей для интеграции с Google Closure Library.
+
+Здесь важны две вещи.
+
+
Для их использования возможно использовать минимум от Google Closure Library. Например, взять одну или несколько функций из библиотеки.
+
GCC -- расширяемый компилятор, можно добавить к нему свои "фазы оптимизации" для интеграции с другими инструментами и фреймворками.
+
+[cut]
+
+Интеграция с Google Closure Library подключается флагом --process_closure_primitives, который по умолчанию установлен в true. То есть, она включена по умолчанию.
+
+Этот флаг запускает специальный проход компилятора, описанный классом ProcessClosurePrimitives и подключает дополнительную проверку типов ClosureReverseAbstractInterpreter.
+
+Мы рассмотрим все действия, которые при этом происходят, а также некоторые опции, которые безопасным образом используют символы Google Closure Library без объявления флага.
+
+## Преобразование основных символов
+
+Следующие действия описаны в классе ProcessClosurePrimitives.
+
+### Замена константы COMPILED
+
+В Google Closure Library есть переменная:
+
+```js
+/**
+ * @define {boolean} ...
+ */
+var COMPILED = false;
+```
+
+Проход ProcessClosurePrimitives переопределяет ее в true и использует это при оптимизациях, удаляя ветки кода, не предназначены для запуска на production.
+
+Такие функции существуют, например, в ядре Google Closure Library. К ним в первую очередь относятся вызовы, предназначенные для сборки и проверки зависимостей. Они содержат код, обрамленный проверкой COMPILED, например:
+
+```js
+goog.require = function(rule) {
+ // ...
+ if (!COMPILED) {
+ // основное тело функции
+ }
+}
+```
+
+Аналогично может поступить и любой скрипт, даже без использования Google Closure Library:
+
+```js
+/** @define {boolean} */
+var COMPILED = false
+
+Framework = {}
+
+Framework.sayCompiled = function() {
+ if (!COMPILED) {
+ alert("Not compressed")
+ } else {
+ alert("Compressed")
+ }
+}
+```
+
+Для того, чтобы сработало, нужно сжать в продвинутом режиме:
+
+```js
+Framework = {};
+Framework.sayCompiled = Framework.a = function() {
+ alert( "Compressed" );
+};
+```
+
+Компилятор переопределил COMPILED в true и произвел соответствующие оптимизации.
+
+### Автоподстановка локали
+
+В Google Closure Compiler есть внутренняя опция locale
+
+Эта опция переопределяет переменную goog.LOCALE на установленную при компиляции.
+
+Для использования опции locale, на момент написания статьи, ее нужно задать в Java коде компилятора, т.к. соответствующего флага нет.
+
+Как и COMPILED, константу goog.LOCALE можно и использовать в своем коде без библиотеки Google Closure Library.
+
+### Проверка зависимостей
+
+Директивы goog.provide, goog.require, goog.addDependency обрабатываются особым образом.
+
+Все зависимости проверяются, а сами директивы проверки -- удаляются из сжатого файла.
+
+### Экспорт символов
+
+Вызов goog.exportSymbol задаёт экспорт символа.
+
+Если подробнее, то код goog.exportSymbol('a',myVar) эквивалентен
+`window['a'] = myVar`.
+
+
+### Автозамена классов CSS
+
+Google Closure Library умеет преобразовывать классы CSS на более короткие по списку, который задаётся при помощи `goog.setCssNameMapping`.
+
+Например, следующая функция задает такой список.
+
+```js
+ goog.setCssNameMapping({
+ "goog-menu": "a",
+ "goog-menu-disabled": "a-b",
+ "CSS_LOGO": "b",
+ "hidden": "c"
+ });
+```
+
+Тогда следующий вызов преобразуется в "a a-b":
+
+```js
+goog.getCssName('goog-menu') + ' ' + goog.getCssName('goog-menu', 'disabled')
+```
+
+Google Closure Compiler производит соответствующие преобразования в сжатом файле и удаляет вызов setCssNameMapping из кода.
+
+Чтобы это сжатие работало, в HTML/CSS классы тоже должны сжиматься. По всей видимости, в приложениях Google это и происходит, но соответствующие инструменты закрыты от публики.
+
+### Генерация списка экстернов
+
+При объявлении внутренней опции externExportsPath, содержащей путь к файлу, в этот файл будут записаны все экспорты, описанные через goog.exportSymbol/goog.exportProperty.
+
+В дальнейшем этот файл может быть использован как список экстернов для компиляции.
+
+Эта опция может быть полезна для создания внешних библиотек, распространяемых со списком экстернов.
+
+Для её использования нужна своя обёртка вокруг компилятора на Java. Соответствующий проход компилятора описан в классе ExternExportsPass.
+
+### Проверка типов
+
+В Google Closure Library есть ряд функций для проверки типов. Например: goog.isArray, goog.isString, goog.isNumber, goog.isDef и т.п.
+
+Компилятор использует их для проверки типов, более подробно см. [](/gcc-check-types)
+
+Эта логика описана в классе ClosureReverseAbstractInterpreter. Названия функций, определяющих типы, жестко прописаны в Java-коде, поменять их на свои без модификации исходников нельзя.
+
+### Автогенерация экспортов из аннотаций
+
+Для этого в Google Closure Compiler есть внутренняя опция generateExports.
+
+Эта недокументированная опция добавляет проход компилятора, описанный классом GenerateExports.
+
+Он читает аннотации @export и создает из них экспортирующие вызовы goog.exportSymbol/exportProperty. Название экспортирующих функций находится в классе соглашений кодирования, каким по умолчанию является GoogleCodingConvention.
+
+Например:
+
+```js
+/** @export */
+function Widget() {}
+ /** @export */
+Widget.prototype.hide = function() {
+ this.elem.style.display = 'none'
+}
+```
+
+После компиляции в продвинутом режиме:
+
+```js
+function a() {}
+goog.d("Widget", a);
+a.prototype.a = function() {
+ this.b.style.display = "none"
+};
+goog.c(a.prototype, "hide", a.prototype.a);
+```
+
+Свойства благополучно экспортированы. Удобно.
+
+### Резюме
+
+Google Closure Compiler содержит дополнительные фичи, облегчающие интеграцию с Google Closure Library. Некоторые из них весьма полезны, но требуют создания своего Java-файла, который ставит внутренние опции.
+
+При обработке символов компилятор не смотрит, подключена ли библиотека, он находит обрабатывает их просто по именам. Поэтому вы можете использовать свою реализацию соответствующих функций.
+
+Google Closure Compiler можно легко расширить, добавив свои опции и проходы оптимизатора, для интеграции с вашими инструментами.
+