private void buildTrie() {
        try (InputStream in = getClass().getClassLoader()
                                        .getResourceAsStream("com/linecorp/armeria/public_suffixes.txt")) {
            checkState(in != null, "public_suffixes.txt not found.");
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    final String[] labels = line.split("\\.");
                    TrieNode node = trie;
                    for (int i = labels.length - 1; i >= 0; i--) {
                        // assume wildcard is at the first position, we don't need to create a new node for it
                        // but set the current node's isWildcard = true instead
                        if ("*".equals(labels[i])) {
                            node.isWildcard = true;
                            break;
                        }
                        if (node.children == null) {
                            node.children = new HashMap<>();
                        }
                        if (node.children.containsKey(labels[i])) {
                            node = node.children.get(labels[i]);
                            assert node != null;
                        } else {
                            final TrieNode newNode = new TrieNode();
                            if (labels[i].charAt(0) == '!') {
                                newNode.isException = true;
                                node.children.put(labels[i].substring(1), newNode);
                            } else {
                                node.children.put(labels[i], newNode);
                            }
                            node = newNode;
                        }
                    }
                    node.isEnd = true;
                }
            }
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }
Builds a trie from the public suffix rules/list for suffix matching. For example, the following rules
creates such trie:

<pre>{@code
com
s3.amazonaws.com
elb.amazonaws.com
*.compute.amazonaws.com
!foo.compute.amazonaws.com (this is imaginary)

                 com
                  |
        ----- amazonaws -----
       |          |          \
    s3(end)   elb(end)   *compute(end)
                               \
                            !foo(end)
}</pre>

<p>The node with '*' has {@code isWildcard = true}, meaning it matches up to {@code compute}, and
<b>one</b> more label on the left (can be anything). So a domain {@code a.compute.amazonaws.com}
matches this rule, but {@code a.b.compute.amazonaws.com} does not.</p>

<p>The node with '!' has {@code isException = true}, meaning it overrides a wildcard matching. If
{@code !foo.compute.amazonaws.com} is not specified, {@code foo.compute.amazonaws.com} matches
{@code *.compute.amazonaws.com}, and thus is considered a public suffix. However with '!', it is not.
Exception always takes precedence over wildcard.

<p>Note: In the specs, a wildcard '*' may appear anywhere in the rule. However, in practice and in the
Public Suffix List, it only appears in the leftmost position. There has been discussion on updating
the specs to reflect this reality and may soon be applied. See more at
<a href="https://github.com/publicsuffix/list/issues/145">issue</a>.
core/src/main/java/com/linecorp/armeria/internal/client/PublicSuffix.java