docs: function updateNodeContextSelection(root, oldSelection, newSelection, rootUpdate, ignoreRootSelection){
      // exit if no changes
      if (oldSelection === newSelection)
        return;
  
      // main part
      var nextNode;
      var cursor = root;
      var selected = [];
  
      // update root context selection if necessary
      if (rootUpdate)
      {
        root.contextSelection = newSelection;
        if (root.selected && !root.selectedRA_)
          selected.push(root);
      }
  
      while (cursor)
      {
        // go into deep
        // if node has selection and node is not root, don't go into deep
        nextNode = !cursor.selection || (ignoreRootSelection && cursor === root)
          ? cursor.firstChild
          : null;
  
        if (nextNode && nextNode.contextSelection !== oldSelection)
          throw 'Try change wrong context selection';
  
        while (!nextNode)
        {
          // stop traversal if cursor on root again
          if (cursor === root)
          {
            // remove selected nodes from old selection, or add to new one
            if (selected.length)
            {
              if (oldSelection)
                oldSelection.remove(selected);
  
              if (newSelection)
              {
                newSelection.add(selected);
  
                // remove selected from nodes that was not added to new selection set
                for (var i = 0; i < selected.length; i++)
                {
                  var node = selected[i];
                  if (node.selected && !newSelection.has(node))
                  {
                    node.selected = false;
                    node.emit_unselect();
                  }
                }
              }
            }
  
            return;
          }
  
          // go to next sibling
          nextNode = cursor.nextSibling;
  
          // if no sibling, going up
          if (!nextNode)
            cursor = cursor.parentNode;
        }
  
        // update cursor
        cursor = nextNode;
  
        // store selected nodes
        if (cursor.selected && !cursor.selectedRA_)
          selected.push(cursor);
  
        // change context selection
        cursor.contextSelection = newSelection;
      }
    }