遍历Trie树，生成check与base
@param array $tree
@param int $base
346549
private function traverseTreeForCompress(array &$tree, int $base,
        string $prefix = '') {

        // 先处理当前层级
        foreach ($tree as $code => $children_tree) {
            $state = $this->getState($base, $code);
            $this->check[$state] = $base;
        }

        // 再处理子级
        foreach ($tree as $code => $children_tree) {
            $state = $this->getState($base, $code);
            $word  = $prefix . $this->index_code[$code];

            // 计算此子级的check 即当前节点的base
            if ($children_tree) {
                $next_base = $this->findBegin($children_tree);
                $this->beginUse($next_base);
                $this->base[$state] = $next_base;

                $this->traverseTreeForCompress($children_tree, $next_base, $word);
            } else {
                // 叶节点
                $this->base[$state] = -$this->check[$state];

                // 创建 word 的 state 索引
                $this->word_states[$state] = $word;
            }
        }
    }
472614
public function index(Tree $tree = null): ResponseInterface
    {
        $multiple_tree_threshold = (int) Site::getPreference('MULTIPLE_TREE_THRESHOLD', self::MULTIPLE_TREE_THRESHOLD);
        $gedcom_files            = $this->gedcomFiles(WT_DATA_DIR);

        $all_trees = Tree::getAll();

        // On sites with hundreds or thousands of trees, this page becomes very large.
        // Just show the current tree, the default tree, and unimported trees
        if (count($all_trees) >= $multiple_tree_threshold) {
            $all_trees = array_filter($all_trees, static function (Tree $x) use ($tree): bool {
                return $x->getPreference('imported') === '0' || $tree->id() === $x->id() || $x->name() === Site::getPreference('DEFAULT_GEDCOM');
            });
        }

        $default_tree_name  = $this->generateNewTreeName();
        $default_tree_title = I18N::translate('My family tree');

        $title = I18N::translate('Manage family trees');

        return $this->viewResponse('admin/trees', [
            'all_trees'               => $all_trees,
            'default_tree_name'       => $default_tree_name,
            'default_tree_title'      => $default_tree_title,
            'gedcom_files'            => $gedcom_files,
            'multiple_tree_threshold' => $multiple_tree_threshold,
            'title'                   => $title,
        ]);
    }
322989
public function exportServer(Tree $tree): ResponseInterface
    {
        $filename = WT_DATA_DIR . $tree->name();

        // Force a ".ged" suffix
        if (strtolower(substr($filename, -4)) !== '.ged') {
            $filename .= '.ged';
        }

        try {
            // To avoid partial trees on timeout/diskspace/etc, write to a temporary file first
            $stream = fopen($filename . '.tmp', 'wb');
            $tree->exportGedcom($stream);
            fclose($stream);
            rename($filename . '.tmp', $filename);

            /* I18N: %s is a filename */
            FlashMessages::addMessage(I18N::translate('The family tree has been exported to %s.', Html::filename($filename)), 'success');
        } catch (Throwable $ex) {
            FlashMessages::addMessage(
                I18N::translate('The file %s could not be created.', Html::filename($filename)) . '<hr><samp dir="ltr">' . $ex->getMessage() . '</samp>',
                'danger'
            );
        }

        $url = route('admin-trees', [
            'ged' => $tree->name(),
        ]);

        return redirect($url);
    }
842091
public function merge (TreeInterface $tree) {
		$this -> apply($tree -> asArray(), $this -> classname);

		return $this;
	}
199026
private function validContacts(Tree $tree): array
    {
        $contacts = [
            $this->user_service->find((int) $tree->getPreference('CONTACT_USER_ID')),
            $this->user_service->find((int) $tree->getPreference('WEBMASTER_USER_ID')),
        ];

        return array_filter($contacts);
    }
1222703
public function getAdminAction(Tree $tree): ResponseInterface
    {
        $this->layout = 'layouts/administration';

        $faqs = $this->faqsForTree($tree);

        $min_block_order = DB::table('block')
            ->where('module_name', '=', $this->name())
            ->where(static function (Builder $query) use ($tree): void {
                $query
                    ->whereNull('gedcom_id')
                    ->orWhere('gedcom_id', '=', $tree->id());
            })
            ->min('block_order');

        $max_block_order = DB::table('block')
            ->where('module_name', '=', $this->name())
            ->where(static function (Builder $query) use ($tree): void {
                $query
                    ->whereNull('gedcom_id')
                    ->orWhere('gedcom_id', '=', $tree->id());
            })
            ->max('block_order');

        $title = I18N::translate('Frequently asked questions') . ' — ' . $tree->title();

        return $this->viewResponse('modules/faq/config', [
            'faqs'            => $faqs,
            'max_block_order' => $max_block_order,
            'min_block_order' => $min_block_order,
            'title'           => $title,
            'tree'            => $tree,
            'tree_names'      => Tree::getNameList(),
        ]);
    }
481697
public static function addEditLog($message, Tree $tree): void
    {
        self::addLog($message, self::TYPE_EDIT, $tree);
    }
434387
final public function accessLevel(Tree $tree, string $interface): int
    {
        $access_levels = app('cache.array')
            ->rememberForever('module_privacy' . $tree->id(), static function () use ($tree): Collection {
                return DB::table('module_privacy')
                    ->where('gedcom_id', '=', $tree->id())
                    ->get();
            });

        $row = $access_levels->first(function (stdClass $row) use ($interface): bool {
            return $row->interface === $interface && $row->module_name === $this->name();
        });

        return $row ? (int) $row->access_level : $this->access_level;
    }
673337
private void add(int previous, int index, Trie.Node node) {

        if (!node.getChildren().isEmpty() && node.hasSinglePath()
                        && node.getChildren().get(0).getKey() != TERMINATING_CHARACTER) { // If node has only one path, put the rest in tail array
            baseBuffer.put(index, tailIndex); // current index of tail array
            addToTail(node.getChildren().get(0));
            checkBuffer.put(index, previous);
            return; // No more child to process
        }

        int startIndex = (compact ? 0 : index);
        int base = findBase(startIndex, node.getChildren());

        baseBuffer.put(index, base);

        if (previous >= 0) {
            checkBuffer.put(index, previous); // Set check value
        }

        for (Trie.Node child : node.getChildren()) { // For each child to double array trie
            if (compact) {
                add(index, base + child.getKey(), child);
            } else {
                add(index, index + base + child.getKey(), child);
            }
        }

    }
522262
public function contactAction(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $body       = $request->get('body', '');
        $from_email = $request->get('from_email', '');
        $from_name  = $request->get('from_name', '');
        $subject    = $request->get('subject', '');
        $to         = $request->get('to', '');
        $url        = $request->get('url', '');
        $ip         = $request->getClientIp() ?? '127.0.0.1';

        $to_user = $this->user_service->findByUserName($to);

        if ($to_user === null) {
            throw new NotFoundHttpException();
        }

        if (!in_array($to_user, $this->validContacts($tree), false)) {
            throw new AccessDeniedHttpException('Invalid contact user id');
        }

        $errors = $body === '' || $subject === '' || $from_email === '' || $from_name === '';

        if (!preg_match('/^[^@]+@([^@]+)$/', $from_email, $match) || !checkdnsrr($match[1])) {
            FlashMessages::addMessage(I18N::translate('Please enter a valid email address.'), 'danger');
            $errors = true;
        }

        if (preg_match('/(?!' . preg_quote(WT_BASE_URL, '/') . ')(((?:ftp|http|https):\/\/)[a-zA-Z0-9.-]+)/', $subject . $body, $match)) {
            FlashMessages::addMessage(I18N::translate('You are not allowed to send messages that contain external links.') . ' ' . /* I18N: e.g. ‘You should delete the “http://” from “http://www.example.com” and try again.’ */
                I18N::translate('You should delete the “%1$s” from “%2$s” and try again.', $match[2], $match[1]), 'danger');
            $errors = true;
        }

        if ($errors) {
            return redirect(route('contact', [
                'body'       => $body,
                'from_email' => $from_email,
                'from_name'  => $from_name,
                'subject'    => $subject,
                'to'         => $to,
                'tree'       => $tree,
                'url'        => $url,
            ]));
        }

        $sender = new GuestUser($from_email, $from_name);

        if ($this->deliverMessage($tree, $sender, $to_user, $subject, $body, $url, $ip)) {
            FlashMessages::addMessage(I18N::translate('The message was successfully sent to %s.', e($to_user->realName())), 'success');

            $url = $url ?: route('tree-page', ['ged' => $tree->name()]);

            return redirect($url);
        }

        FlashMessages::addMessage(I18N::translate('The message was not sent.'), 'danger');

        $redirect_url = route('contact', [
            'body'       => $body,
            'from_email' => $from_email,
            'from_name'  => $from_name,
            'subject'    => $subject,
            'to'         => $to,
            'url'        => $url,
        ]);

        return redirect($redirect_url);
    }
897341
public void checkSubTree(TreePath tp, boolean check) {
        CheckedNode cn = nodesCheckingState.get(tp);
        cn.isSelected = check;
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent();
        for (int i = 0 ; i < node.getChildCount() ; i++) {              
            checkSubTree(tp.pathByAddingChild(node.getChildAt(i)), check);
        }
        cn.allChildrenSelected = check;
        if (check) {
            checkedPaths.add(tp);
        } else {
            checkedPaths.remove(tp);
        }
        updatePredecessorsAllChildrenSelectedState(tp);
    }
1283308
protected function buildDomainRows(array $tree)
    {
        $rows = [];

        /** @var \Platformsh\Cli\Service\PropertyFormatter $formatter */
        $formatter = $this->getService('property_formatter');

        foreach ($tree as $domain) {
            $rows[] = [
                'name' => $domain->id,
                'ssl' => $formatter->format((bool) $domain['ssl']['has_certificate']),
                'created_at' => $formatter->format($domain['created_at'], 'created_at'),
                'updated_at' => $formatter->format($domain['updated_at'], 'updated_at'),
            ];
        }

        return $rows;
    }
710942
public function listIsEmpty(Tree $tree): bool
    {
        return !DB::table('sources')
            ->where('s_file', '=', $tree->id())
            ->exists();
    }
855331
@SuppressWarnings("unchecked")
  public final void integrityCheck(AbstractRStarTree<N, E, ?> tree) {
    // leaf node
    if(isLeaf()) {
      for(int i = 0; i < getCapacity(); i++) {
        E e = getEntry(i);
        if(i < getNumEntries() && e == null) {
          throw new RuntimeException("i < numEntries && entry == null");
        }
        if(i >= getNumEntries() && e != null) {
          throw new RuntimeException("i >= numEntries && entry != null");
        }
      }
    }

    // dir node
    else {
      N tmp = tree.getNode(getEntry(0));
      boolean childIsLeaf = tmp.isLeaf();

      for(int i = 0; i < getCapacity(); i++) {
        E e = getEntry(i);

        if(i < getNumEntries() && e == null) {
          throw new RuntimeException("i < numEntries && entry == null");
        }

        if(i >= getNumEntries() && e != null) {
          throw new RuntimeException("i >= numEntries && entry != null");
        }

        if(e != null) {
          N node = tree.getNode(e);

          if(childIsLeaf && !node.isLeaf()) {
            for(int k = 0; k < getNumEntries(); k++) {
              tree.getNode(getEntry(k));
            }

            throw new RuntimeException("Wrong Child in " + this + " at " + i);
          }

          if(!childIsLeaf && node.isLeaf()) {
            throw new RuntimeException("Wrong Child: child id no leaf, but node is leaf!");
          }

          node.integrityCheckParameters((N) this, i);
          node.integrityCheck(tree);
        }
      }

      if(LoggingConfiguration.DEBUG) {
        Logger.getLogger(this.getClass().getName()).fine("DirNode " + getPageID() + " ok!");
      }
    }
  }
635453
private static function addTreeNode(array &$tree, $parent, $node, $prepend = false)
    {
        if ($parent === null) {
            if (array_key_exists($node, $tree)) {
                throw new \Exception('Node already exists');
            }
            if ($prepend) {
                $tree = array_merge([$node => []], $tree);
            } else {
                $tree[$node] = [];
            }

            return true;
        }
        foreach ($tree as $key => &$value) {
            if ($key === $parent) {
                return self::addTreeNode($value, null, $node, $prepend);
            } else {
                if (self::addTreeNode($value, $parent, $node, $prepend)) {
                    return true;
                }
            }
        }

        return false;
    }
41378
protected function renderNode($tree, $depth = 0, $cap = 0) {

        $n = count($tree);
        foreach ($tree as $k => $next) {
            for ($pre = "", $i = $depth - 1; $i >= 0; $i--){
                $pre.= $cap >> $i & 1 ? "│  " : "   ";
            }
            echo $pre, --$n > 0 ? '├──' : '└──', $k, PHP_EOL;
            if (false === empty($next)){
                $this->renderNode($next, $depth + 1, ($cap << 1) | ($n > 0));
            }
        }
    }
76899
public function create(array $tree, string $base_tree): array
    {
        return $this->getApi()->request($this->getApi()
                                             ->sprintf('/repos/:owner/:repo/git/trees', $this->getGitData()->getOwner(),
                                                 $this->getGitData()->getRepo()), Request::METHOD_POST, [
                'tree'      => $tree,
                'base_tree' => $base_tree
            ]);
    }