+ // here's the code
+ let hello = "world";
+
+...
+```
+
+There's also a JavaScript highlighting library, e.g. [Prism.js](https://prismjs.com/). A call to `Prism.highlightElem(pre)` examines the contents of such `pre` elements and adds colored syntax highlighting, similar to what you in examples here, this page.
+
+Generally, when a page loads, e.g. at the bottom of the page, we can search for elements `pre[class*="language"]` and call `Prism.highlightElem` on them:
+
+```js
+// highlight all code snippets on the page
+document.querySelectorAll('pre[class*="language"]').forEach(Prism.highlightElem);
+```
+
+Now the `` snippet looks like this (without line numbers by default):
+
+```js
+// here's the code
+let hello = "world";
+```
+
+Everything's simple so far, right? There are `` code snippets in HTML, we highlight them.
+
+Now let's go on. Let's say we're going to dynamically fetch materials from a server. We'll study methods for that [later in the tutorial](info:fetch-basics). For now it only matters that we fetch an HTML article from a webserver and display it on demand:
+
+```js
+let article = /* fetch new content from server */
+articleElem.innerHTML = article;
+```
+
+The new `article` HTML may contain code snippets. We need to call `Prism.highlightElem` on them, otherwise they won't get highlighted.
+
+**Who's responsibility is to call `Prism.highlightElem` for a dynamically loaded article?**
+
+We could append that call to the code that loads an article, like this:
+
+```js
+let article = /* fetch new content from server */
+articleElem.innerHTML = article;
+
+*!*
+let snippets = articleElem.querySelectorAll('pre[class*="language-"]');
+snippets.forEach(Prism.highlightElem);
+*/!*
+```
+
+...But imagine, we have many places where we load contents with code: articles, quizzes, forum posts. Do we need to put the highlighting call everywhere? Then we need to be careful, not to forget about it.
+
+And what if we load the content into a third-party engine? E.g. we have a forum written by someone else, that loads contents dynamically, and we'd like to add syntax highlighting to it. No one likes to patch third-party scripts.
+
+Luckily, there's another option.
+
+We can use `MutationObserver` to automatically detect code snippets inserted in the page and highlight them.
+
+So we'll handle the highlighting functionality in one place, relieving us from the need to integrate it.
+
+## Dynamic highlight demo
+
+Here's the working example.
+
+If you run this code, it starts observing the element below and highlighting any code snippets that appear there:
+
+```js run
+let observer = new MutationObserver(mutations => {
+
+ for(let mutation of mutations) {
+ // examine new nodes
+
+ for(let node of mutation.addedNodes) {
+ // skip newly added text nodes
+ if (!(node instanceof HTMLElement)) continue;
+
+ // check the inserted element for being a code snippet
+ if (node.matches('pre[class*="language-"]')) {
+ Prism.highlightElement(node);
+ }
+
+ // search its subtree for code snippets
+ for(let elem of node.querySelectorAll('pre[class*="language-"]')) {
+ Prism.highlightElement(elem);
+ }
+ }
+ }
+
+});
+
+let demoElem = document.getElementById('highlight-demo');
+
+observer.observe(demoElem, {childList: true, subtree: true});
+```
+
+Demo element with id="highlight-demo", obverved by the example above.
+
+The code below populates `innerHTML`. If you've run the code above, snippets will get highlighted:
+
+```js run
+let demoElem = document.getElementById('highlight-demo');
+
+// dynamically insert content with code snippets
+demoElem.innerHTML = `A code snippet is below:
+ let hello = "world!";
+ Another one:
+
+ .class { margin: 5px; }
+
+`;
+```
+
+Now we have `MutationObserver` that can track all highlighting in observed elements or the whole `document`. We can add/remove code snippets in HTML without thinking about it.
+
+
+## Garbage collection
+
+Observers use weak references to nodes internally. That is: if a node is removed from DOM, and becomes unreachable, then it becomes garbage collected, an observer doesn't prevent that.
+
+Still, we can release observers any time:
+
+- `observer.disconnect()` -- stops the observation.
+
+Additionally:
+
+- `mutationRecords = observer.takeRecords()` -- gets a list of unprocessed mutation records, those that happened, but the callback did not handle them.
+
+```js
+// we're going to disconnect the observer
+// it might have not yet handled some mutations
+let mutationRecords = observer.takeRecords();
+// process mutationRecords
+
+// now all handled, disconnect
+observer.disconnect();
+```
+
+## Summary
+
+`MutationObserver` can react on changes in DOM: attributes, added/removed elements, text content.
+
+We can use it to track changes introduced by other parts of our own or 3rd-party code.
+
+For example, to post-process dynamically inserted content, as demo `innerHTML`, like highlighting in the example above.
diff --git a/10-misc/index.md b/10-misc/index.md
new file mode 100644
index 00000000..65ab3188
--- /dev/null
+++ b/10-misc/index.md
@@ -0,0 +1,4 @@
+
+# Miscellaneous
+
+Not yet categorized articles.
diff --git a/2-ui/1-document/07-modifying-document/article.md b/2-ui/1-document/07-modifying-document/article.md
index 22907554..16aacb45 100644
--- a/2-ui/1-document/07-modifying-document/article.md
+++ b/2-ui/1-document/07-modifying-document/article.md
@@ -136,7 +136,7 @@ Here's a brief list of methods to insert a node into a parent element (`parentEl
```
To insert `newLi` as the first element, we can do it like this:
-
+
```js
list.insertBefore(newLi, list.firstChild);
```
@@ -335,6 +335,74 @@ An example of copying the message:
```
+
+## DocumentFragment [#document-fragment]
+
+`DocumentFragment` is a special DOM node that serves as a wrapper to pass around groups of nodes.
+
+We can append other nodes to it, but when we insert it somewhere, then it "disappears", leaving its content inserted instead.
+
+For example, `getListContent` below generates a fragment with `