Sort nodes and remove duplicates
@param Node[] $nodes
@return Node[]
484619
protected static function sortUnique($nodes) {
    $sort = [];
    $detached = [];
    foreach ($nodes as $node) {
      $key = $node->sortKey();
      if ($key[0] === '~') {
        $detached[] = $node;
      }
      else {
        $sort[$key] = $node;
      }
    }
    ksort($sort, SORT_NATURAL);
    return array_merge(array_values($sort), $detached);
  }
1008484
public function resetNodeStats()
    {
        foreach ($this->nodeMap as &$nodeStat) {
            foreach ($this->nodeIncrements as $key => $value) {
                if (isset($nodeStat[$key])) {
                    $nodeStat[$key] = $value;
                }
            }
        }

        return $this;
    }
419310
private function _getTreeNodesIds($nodes)
    {
        $result = [];

        foreach ($nodes as $node) {
            $result[] = $node->id;
        }

        return $result;
    }
565925
protected function _removeFromTree($node)
    {
        $config = $this->getConfig();
        $left = $node->get($config['left']);
        $right = $node->get($config['right']);
        $parent = $node->get($config['parent']);

        $node->set($config['parent'], null);

        if ($right - $left == 1) {
            return $this->_table->save($node);
        }

        $primary = $this->_getPrimaryKey();
        $this->_table->updateAll(
            [$config['parent'] => $parent],
            [$config['parent'] => $node->get($primary)]
        );
        $this->_sync(1, '-', 'BETWEEN ' . ($left + 1) . ' AND ' . ($right - 1));
        $this->_sync(2, '-', "> {$right}");
        $edge = $this->_getMax();
        $node->set($config['left'], $edge + 1);
        $node->set($config['right'], $edge + 2);
        $fields = [$config['parent'], $config['left'], $config['right']];

        $this->_table->updateAll($node->extract($fields), [$primary => $node->get($primary)]);

        foreach ($fields as $field) {
            $node->setDirty($field, false);
        }

        return $node;
    }
1157832
public function cleanupNodesWithIds($ids)
    {
        $ids = array_merge($this->getRelatedNodeIds($ids), $ids);

        if (!empty($ids)) {
            $repositories = $this->getNodeRepositories($ids);

            //delete all the nodes
            $this->getService('repos:base.node')->destroy($ids);

            //set the creator,updator,authors to null
            $in = '('.implode(',', $ids).')';
            $query[] = "last_comment_id = IF(last_comment_id IN $in, NULL, last_comment_id)";
            $query[] = "created_by = IF(created_by IN $in, NULL, created_by)";
            $query[] = "modified_by = IF(modified_by IN $in, NULL, modified_by)";
            $query[] = "last_comment_by = IF(last_comment_by IN $in, NULL, last_comment_by)";
            $query = implode(', ', $query);
            $where = $this->getService('repos:base.node')
                        ->getQuery()
                        ->where("last_comment_by IN $in OR created_by IN $in OR modified_by IN $in OR last_comment_by IN $in");

            $this->getService('repos:base.node')->update($query, $where);

            //cleanup all the relationship of every deleted node
            $query = $this->getService('repos:base.edge')
                ->getQuery()
                ->where('nodeA.id', 'IN', $ids)
                ->where('nodeB.id', 'IN', $ids, 'OR');

            $this->getService('repos:base.edge')->destroy($query);

            //now lets the repositories know so they can
            //handle the cleanup
            foreach ($repositories as $repository) {
                $context = $repository->getCommandContext();
                $context->node_ids = $ids;
                $repository->getCommandChain()->run('after.deletenodes', $context);
            }
        }
    }
1032202
protected function mergeTrees(array $trees): array
    {
        if (count($trees) == 0) {
            return [];
        }

        $tree1 = array_shift($trees);
        while (count($trees)) {
            $tree2 = array_shift($trees);
            foreach ($tree2 as $key => $value) {
                if (in_array($key, $this->permissionKeys)) {
                    $tree1 = $tree2;
                    break;
                }
                if (isset($tree1[$key]) && is_array($value)) {
                    $tree1[$key] = $this->mergeTrees([$tree1[$key], $tree2[$key]]);
                    continue;
                }
                $tree1[$key] = $value;
            }
        }

        return $tree1;
    }
1113313
public function duplicateWithChildren()
    {
        /** @var SiteTree $clone */
        $clone = $this->duplicate();
        $children = $this->AllChildren();

        if ($children) {
            /** @var SiteTree $child */
            $sort = 0;
            foreach ($children as $child) {
                $childClone = method_exists($child, 'duplicateWithChildren')
                    ? $child->duplicateWithChildren()
                    : $child->duplicate();
                $childClone->ParentID = $clone->ID;
                //retain sort order by manually setting sort values
                $childClone->Sort = ++$sort;
                $childClone->write();
            }
        }

        return $clone;
    }
435301
public function findNodesOfType(array $nodes, string $type): array
    {
        $collectedNodes = [];

        foreach ($nodes as $node) {
            if (is_array($node)) {
                $collectedNodes = array_merge(
                    $this->findNodesOfType($node, $type),
                    $collectedNodes
                );
            } elseif ($node instanceof Node) {
                if (is_a($node, $type, true)) {
                    $collectedNodes[] = $node;
                }

                $collectedNodes = array_merge(
                    $this->findNodesOfType(
                        AstHelper::getSubNodes($node),
                        $type
                    ),
                    $collectedNodes
                );
            }
        }

        return $collectedNodes;
    }
479279
protected function filterList(array $nodes = array(), array $rules = array())
  {
    if(!empty($rules))
    {
      foreach($nodes as $node)
      {
        if(!$node instanceof Node) continue;

        $props = $node->getInfo(FALSE);
        $props = array_intersect_key($props, $rules);

        foreach($props as $key => $val)
        {
          if($val instanceof Str)
          {
            $match = $val->contains($rules[$key], TRUE);
          }
          else
          {
            $match = $val == $rules[$key];
          }

          if($match === FALSE)
          {
            unset($nodes[$node->getId()]);
          }
        }
      }
    }

    return $nodes;
  }
183763
protected static function processMastersOrSlaves(array $servers)
    {
        foreach ($servers as $idx => $node) {
            $processed = array();
            $count = count($node);

            for ($i = 0; $i < $count; ++$i) {
                $processed[$node[$i]] = $node[++$i];
            }

            $servers[$idx] = $processed;
        }

        return $servers;
    }
1334303
public function mapTree(array $nodes, array $mappedNodes = []) {
        if (!$mappedNodes) {
            return $nodes;
        }

        $tree = [];
        $pk = $this->getRepository()->getPrimaryKey();

        foreach ($nodes as $node) {
            $id = $node[$pk];

            if (isset($mappedNodes[$id])) {
                $node[$this->getConfig('treeField') ?: 'Nodes'] = $this->mapTree($mappedNodes[$id], $mappedNodes);
            }

            $tree[] = $node;
        }

        return $tree;
    }
1143480
public function discardNodes(array $nodes)
    {
        $discardedNodeIdentifiers = [];
        foreach ($nodes as $node) {
            $this->doDiscardNode($node, $discardedNodeIdentifiers);
        }
    }
569471
protected function performRemove(Node $node)
    {
        $subtree = $this->get(
            $node->getId(),
            $node[$this->getRootIdName()]
        );

        $sorter = $this->sorter();

        $byDepth = $sorter->byDepthReversed($sorter->flatify($subtree));

        array_walk_recursive($byDepth, function($node, $key){
            $node->delete();
        });

        return $this;
    }
19178
public function beforeTraverse(array $nodes)
    {
        if (empty($nodes)) {
            return $nodes;
        }

        $last = \end($nodes);

        if ($last instanceof Namespace_) {
            $kind = $last->getAttribute('kind');

            // Treat all namespace statements pre-PHP-Parser v3.1.2 as "open",
            // even though we really have no way of knowing.
            if ($kind === null || $kind === Namespace_::KIND_SEMICOLON) {
                // Save the current namespace for open namespaces
                $this->setNamespace($last->name);
            } else {
                // Clear the current namespace after a braced namespace
                $this->setNamespace(null);
            }

            return $nodes;
        }

        return $this->namespace ? [new Namespace_($this->namespace, $nodes)] : $nodes;
    }
691476
public function after($nodes) {
    foreach ($this->nodes as $i => $node) {
      $node->after($i === 0 ? $nodes : clone $nodes);
    }
    return $this;
  }
394348
public static function sort(array $versions) : array
    {
        usort(
            $versions,
            function (Version $a, Version $b) {
                return VersionComparator::compare($a, $b);
            }
        );

        return $versions;
    }
246718
public function getExpandedTree(Node ...$nodes): MerkleTree
    {
        $thisTree = $this->nodes;
        foreach ($nodes as $node) {
            $thisTree []= $node;
        }
        return (new MerkleTree(...$thisTree))
            ->setHashSize($this->outputSize)
            ->setPersonalizationString($this->personalization);
    }