private bool?HandleEndTag(Token t, HtmlTreeBuilder tb)
            {
                Token.EndTag endTag = t.AsEndTag();
                string       name   = endTag.Name;

                if (name.Equals("body"))
                {
                    if (!tb.InScope("body"))
                    {
                        tb.Error(this);
                        return(false);
                    }
                    else
                    {
                        // TODO: error if stack contains something not dd, dt, li, optgroup, option, p, rp, rt, tbody, td, tfoot, th, thead, tr, body, html
                        tb.Transition(AfterBody);
                    }
                }
                else if (name.Equals("html"))
                {
                    bool notIgnored = tb.Process(new Token.EndTag("body"));
                    if (notIgnored)
                    {
                        return(tb.Process(endTag));
                    }
                }
                else if (StringSet.Create(@"address article aside blockquote button center details dir div
                                dl fieldset figcaption figure footer header hgroup listing menu
                                nav ol pre section summary ul").Contains(name))
                {
                    // TODO: refactor these lookups
                    if (!tb.InScope(name))
                    {
                        // nothing to close
                        tb.Error(this);
                        return(false);
                    }
                    else
                    {
                        tb.GenerateImpliedEndTags();
                        if (!tb.CurrentElement.NodeName.Equals(name))
                        {
                            tb.Error(this);
                        }
                        tb.PopStackToClose(name);
                    }
                }
                else if (name.Equals("form"))
                {
                    HtmlElement currentForm = tb.FormElement;
                    tb.FormElement = null;

                    if (currentForm == null || !tb.InScope(name))
                    {
                        tb.Error(this);
                        return(false);
                    }
                    else
                    {
                        tb.GenerateImpliedEndTags();
                        if (!tb.CurrentElement.NodeName.Equals(name))
                        {
                            tb.Error(this);
                        }
                        // remove currentForm from stack. will shift anything under up.
                        tb.RemoveFromStack(currentForm);
                    }
                }
                else if (name.Equals("p"))
                {
                    if (!tb.InButtonScope(name))
                    {
                        tb.Error(this);
                        tb.Process(new Token.StartTag(name)); // if no p to close, creates an empty <p></p>
                        return(tb.Process(endTag));
                    }
                    else
                    {
                        tb.GenerateImpliedEndTags(name);
                        if (!tb.CurrentElement.NodeName.Equals(name))
                        {
                            tb.Error(this);
                        }
                        tb.PopStackToClose(name);
                    }
                }
                else if (name.Equals("li"))
                {
                    if (!tb.InListItemScope(name))
                    {
                        tb.Error(this);
                        return(false);
                    }
                    else
                    {
                        tb.GenerateImpliedEndTags(name);
                        if (!tb.CurrentElement.NodeName.Equals(name))
                        {
                            tb.Error(this);
                        }
                        tb.PopStackToClose(name);
                    }
                }
                else if (StringUtil.In(name, "dd", "dt"))
                {
                    if (!tb.InScope(name))
                    {
                        tb.Error(this);
                        return(false);
                    }
                    else
                    {
                        tb.GenerateImpliedEndTags(name);
                        if (!tb.CurrentElement.NodeName.Equals(name))
                        {
                            tb.Error(this);
                        }
                        tb.PopStackToClose(name);
                    }
                }
                else if (HeadingTags.Contains(name))
                {
                    if (!tb.InScope(HeadingTags))
                    {
                        tb.Error(this);
                        return(false);
                    }
                    else
                    {
                        tb.GenerateImpliedEndTags(name);
                        if (!tb.CurrentElement.NodeName.Equals(name))
                        {
                            tb.Error(this);
                        }
                        tb.PopStackToClose(HeadingTags);
                    }
                }
                else if (name.Equals("sarcasm"))
                {
                    // *sigh*
                    return(AnyOtherEndTag(t, tb));
                }
                else if (StringSet.Create("a b big code em font i nobr s small strike strong tt u").Contains(name))
                {
                    // Adoption Agency Algorithm.
OUTER:
                    for (int i = 0; i < 8; i++)
                    {
                        var formatEl = tb.GetActiveFormattingElement(name);
                        if (formatEl == null)
                        {
                            return(AnyOtherEndTag(t, tb));
                        }

                        else if (!tb.OnStack(formatEl))
                        {
                            tb.Error(this);
                            tb.RemoveFromActiveFormattingElements(formatEl);
                            return(true);
                        }
                        else if (!tb.InScope(formatEl.NodeName))
                        {
                            tb.Error(this);
                            return(false);
                        }
                        else if (tb.CurrentElement != formatEl)
                        {
                            tb.Error(this);
                        }

                        DomContainer furthestBlock                 = null;
                        DomContainer commonAncestor                = null;
                        bool         seenFormattingElement         = false;
                        DescendableLinkedList <DomContainer> stack = tb.Stack;

                        for (int si = 0; si < stack.Count; si++)
                        {
                            DomContainer el = stack.ElementAt(si);
                            if (el == formatEl)
                            {
                                commonAncestor        = stack.ElementAt(si - 1);
                                seenFormattingElement = true;
                            }
                            else if (seenFormattingElement && tb.IsSpecial(el))
                            {
                                furthestBlock = el;
                                break;
                            }
                        }

                        if (furthestBlock == null)
                        {
                            tb.PopStackToClose(formatEl.NodeName);
                            tb.RemoveFromActiveFormattingElements(formatEl);
                            return(true);
                        }

                        // TODO: Let a bookmark note the position of the formatting element in the list of active formatting elements relative to the elements on either side of it in the list.
                        // does that mean: int pos of format el in list?
                        DomContainer node     = furthestBlock;
                        DomContainer lastNode = furthestBlock;

INNER:
                        for (int j = 0; j < 3; j++)
                        {
continueINNER:
                            if (tb.OnStack(node))
                            {
                                node = tb.AboveOnStack(node);
                            }

                            if (!tb.IsInActiveFormattingElements(node))   // note no bookmark check
                            {
                                tb.RemoveFromStack(node);
                                goto continueINNER;
                            }
                            else if (node == formatEl)
                            {
                                goto breakINNER;
                            }

                            HtmlElement replacement = new HtmlElement(node.NodeName);
                            tb.ReplaceActiveFormattingElement(node, replacement);
                            tb.ReplaceOnStack(node, replacement);
                            node = replacement;

                            if (lastNode == furthestBlock)
                            {
                                // TODO: move the aforementioned bookmark to be immediately after the new node in the list of active formatting elements.
                                // not getting how this bookmark both straddles the element above, but is inbetween here...
                            }
                            if (lastNode.Parent != null)
                            {
                                lastNode.Remove();
                            }
                            node.Append(lastNode);

                            lastNode = node;
                        }
breakINNER:

                        if (StringUtil.In(commonAncestor.NodeName, "table", "tbody", "tfoot", "thead", "tr"))
                        {
                            if (lastNode.Parent != null)
                            {
                                lastNode.Remove();
                            }
                            tb.InsertInFosterParent(lastNode);
                        }
                        else
                        {
                            if (lastNode.Parent != null)
                            {
                                lastNode.Remove();
                            }
                            commonAncestor.Append(lastNode);
                        }

                        HtmlElement adopter    = new HtmlElement(name);
                        var         childNodes = furthestBlock.ChildNodes.ToArray();
                        foreach (var childNode in childNodes)
                        {
                            adopter.Append(childNode); // append will reparent. thus the clone to avvoid concurrent mod.
                        }

                        furthestBlock.Append(adopter);
                        tb.RemoveFromActiveFormattingElements(formatEl);
                        // TODO: insert the new element into the list of active formatting elements at the position of the aforementioned bookmark.
                        tb.RemoveFromStack(formatEl);
                        tb.InsertOnStackAfter(furthestBlock, adopter);
                    }
                }
                else if (StringUtil.In(name, "applet", "marquee", "object"))
                {
                    if (!tb.InScope("name"))
                    {
                        if (!tb.InScope(name))
                        {
                            tb.Error(this);
                            return(false);
                        }

                        tb.GenerateImpliedEndTags();
                        if (!tb.CurrentElement.NodeName.Equals(name))
                        {
                            tb.Error(this);
                        }
                        tb.PopStackToClose(name);
                        tb.ClearFormattingElementsToLastMarker();
                    }
                }
                else if (name.Equals("br"))
                {
                    tb.Error(this);
                    tb.Process(new Token.StartTag("br"));
                    return(false);
                }
                else
                {
                    return(AnyOtherEndTag(t, tb));
                }

                return(null);
            }